Skip to content

Commit

Permalink
Avoid basicConfig on import; add setup_fancy_logger for dynamic log l…
Browse files Browse the repository at this point in the history
…evel (#307)
  • Loading branch information
janbjorge committed Feb 5, 2025
1 parent 18e2355 commit e3814cd
Show file tree
Hide file tree
Showing 2 changed files with 91 additions and 8 deletions.
10 changes: 9 additions & 1 deletion pgqueuer/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
from typer import Context
from typing_extensions import AsyncGenerator

from . import db, factories, helpers, listeners, models, qb, queries, supervisor
from . import db, factories, helpers, listeners, logconfig, models, qb, queries, supervisor

try:
from uvloop import run as asyncio_run
Expand Down Expand Up @@ -391,10 +391,18 @@ def run(
"--restart-on-failure",
help="Restart the manager if it fails.",
),
log_level: logconfig.LogLevel | None = typer.Option(
None,
"--log-level",
help="Set pgqueuer log level.",
),
) -> None:
"""
Run the job manager, pulling tasks from the queue and handling them with workers.
"""
if log_level:
logconfig.setup_fancy_logger(log_level)

asyncio_run(
supervisor.runit(
factories.load_factory(factory_fn),
Expand Down
89 changes: 82 additions & 7 deletions pgqueuer/logconfig.py
Original file line number Diff line number Diff line change
@@ -1,17 +1,92 @@
"""
Logging configuration for the pgqueuer application.
This module initializes the logging settings for the application. It sets up a logger
named 'pgqueuer' and configures its log level based on the 'LOGLEVEL' environment variable.
If 'LOGLEVEL' is not set, it defaults to 'INFO'.
"""

from __future__ import annotations

import logging
import os
import logging.config
import sys
from datetime import datetime
from enum import Enum
from typing import Final

logging.basicConfig()

class LogLevel(Enum):
CRITICAL = "CRITICAL"
FATAL = "FATAL"
ERROR = "ERROR"
WARN = "WARN"
WARNING = "WARNING"
INFO = "INFO"
DEBUG = "DEBUG"
NOTSET = "NOTSET"


class ISOFormatter(logging.Formatter):
"""Outputs log timestamps in ISO 8601 format with timezone information."""

def formatTime(self, record: logging.LogRecord, datefmt: str | None = None) -> str:
return datetime.fromtimestamp(record.created).astimezone().isoformat()


class MaxLevelFilter(logging.Filter):
"""Only allows log records up to a specified maximum logging level."""

def __init__(self, max_level: int):
super().__init__()
self.max_level = max_level

def filter(self, record: logging.LogRecord) -> bool:
return record.levelno <= self.max_level


def setup_fancy_logger(level: LogLevel) -> None:
"""
Update the 'pgqueuer' logger's level dynamically.
"""

logging.config.dictConfig(
{
"version": 1,
"disable_existing_loggers": False,
"formatters": {
"default": {
"()": ISOFormatter,
"format": "%(asctime)s [%(name)s] %(levelname)s: %(message)s",
},
},
"filters": {
"max_info": {
"()": MaxLevelFilter,
"max_level": logging.INFO,
},
},
"handlers": {
"stdout": {
"class": "logging.StreamHandler",
"level": "DEBUG",
"formatter": "default",
"stream": sys.stdout,
"filters": ["max_info"],
},
"stderr": {
"class": "logging.StreamHandler",
"level": "WARNING",
"formatter": "default",
"stream": sys.stderr,
},
},
"loggers": {
"pgqueuer": {
"handlers": ["stdout", "stderr"],
"level": level.name,
}
},
}
)


# Create the 'pgqueuer' logger and attach a NullHandler by default.
logger: Final = logging.getLogger("pgqueuer")
logger.setLevel(level=os.environ.get("LOGLEVEL", "INFO").upper())
logger.addHandler(logging.NullHandler())

0 comments on commit e3814cd

Please sign in to comment.