Skip to content

Commit

Permalink
[PATCH] Fixed logging
Browse files Browse the repository at this point in the history
  • Loading branch information
Diapolo10 committed Oct 23, 2024
1 parent 126b3b4 commit c091e47
Show file tree
Hide file tree
Showing 7 changed files with 236 additions and 179 deletions.
3 changes: 3 additions & 0 deletions .github/workflows/ruff.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@ on:
push:
branches:
- '**'
pull_request:
branches:
- '**'

permissions:
contents: write
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/unit_tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,11 @@ jobs:
matrix:
os: [macos-latest, ubuntu-latest, windows-latest]
python-version: [
'3.8',
'3.9',
'3.10',
'3.11',
# 'pypy-3.10',
'3.12',
'pypy-3.10',
]

exclude:
Expand Down
314 changes: 165 additions & 149 deletions poetry.lock

Large diffs are not rendered by default.

27 changes: 16 additions & 11 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,13 @@ requires = ["poetry-core>=1.2.0", "wheel",]
build-backend = "poetry.core.masonry.api"


[tool.coverage.report]
exclude_lines = [
"pragma: not covered",
"@overload",
]


[tool.coverage.run]
branch = true
relative_files = true
Expand Down Expand Up @@ -39,7 +46,6 @@ classifiers = [
"Development Status :: 3 - Alpha",
"License :: OSI Approved :: MIT License",
"Operating System :: OS Independent",
"Programming Language :: Python :: 3.8",
"Programming Language :: Python :: 3.9",
"Programming Language :: Python :: 3.10",
"Programming Language :: Python :: 3.11",
Expand All @@ -51,31 +57,31 @@ classifiers = [


[tool.poetry.dependencies]
python = "^3.8.1"
python = "^3.9.0"
python-dotenv = "^1.0.1"
tomli = { version = "^2.0.1", python = "<3.11" }


[tool.poetry.group.dev.dependencies]
mypy = "^1.8.0"
mypy = "^1.13.0"


[tool.poetry.group.linters]
optional = true


[tool.poetry.group.linters.dependencies]
ruff = "^0.5.2"
ruff = "^0.7.0"


[tool.poetry.group.tests]
optional = true


[tool.poetry.group.tests.dependencies]
pytest = "^8.0.0"
pytest = "^8.3.2"
pytest-cov = "^5.0.0"
tox = "^4.12.1"
tox = "^4.23.0"
tox-gh-actions = "^3.2.0"


Expand Down Expand Up @@ -127,7 +133,7 @@ lint.select = [
"FBT", # "Boolean trap"
"FIX", # "FIXME"-comments
"FLY", # F-strings
# "FURB", # Refurb
"FURB", # Refurb
"G", # Logging format
"I", # Isort
"ICN", # Import conventions
Expand Down Expand Up @@ -171,10 +177,9 @@ lint.ignore = [
"Q000", # Single quotes found but double quotes preferred
]
line-length = 120
# preview = true
show-fixes = true
src = ["src",]
target-version = "py38"
target-version = "py39"


[tool.ruff.lint.flake8-copyright]
Expand Down Expand Up @@ -211,15 +216,15 @@ ban-relative-imports = "all"
[tool.tox]
legacy_tox_ini = """
[tox]
envlist = py38, py39, py310, py311, pypy3
envlist = py39, py310, py311, py312, pypy3
skip_missing_interpreters = true
[gh-actions]
python =
3.8: py38
3.9: py39
3.10: py310
3.11: py311
3.12: py312
pypy-3.10: pypy3
[testenv]
Expand Down
48 changes: 36 additions & 12 deletions src/project_name/logger.py
Original file line number Diff line number Diff line change
Expand Up @@ -58,11 +58,34 @@ def _generate_next_value_(name: str, start: int, count: int, last_values: list)
taskName = auto()


class ColouredFormatter(logging.Formatter):
"""Coloured log formatter."""

@override
def format(self, record: logging.LogRecord) -> str:
"""Format the log record."""
log_level_colours = {
logging.CRITICAL: '\033[31;1;40m', # Red, bold
logging.ERROR: '\033[31;40m', # Red
logging.WARNING: '\033[33;40m', # Yellow
logging.INFO: '\033[32;40m', # Green
logging.DEBUG: '\033[36;40m', # Cyan
}
reset = '\033[0m'

record.msg = f"{log_level_colours.get(record.levelno, reset)}{record.msg}{reset}"
record.levelname = (
f"{log_level_colours.get(record.levelno, reset)}{record.levelname:^8}{reset}"
)

return super().format(record)


class FormatKeys(TypedDict):
"""Log format keys."""

message: str
timestamp: dt.datetime
message: NotRequired[str]
timestamp: NotRequired[dt.datetime]
level: NotRequired[str]
logger: NotRequired[str]
module: NotRequired[str]
Expand All @@ -82,13 +105,10 @@ class CustomQueueHandler(logging.handlers.QueueHandler):
"""Custom queue handler."""

@override
def __init__(self, *args: Any, **kwargs: dict[str, Any]) -> None:
def __init__(self, *args: Any, **kwargs: Any) -> None:
queue_handler = logging.getHandlerByName("queue_handler")
if queue_handler is None:
super().__init__(*args, **kwargs)
else:
queue_handler.listener.start()
atexit.register(queue_handler.listener.stop)
super().__init__(*args, **kwargs) # type: ignore[arg-type]


class JSONLogFormatter(logging.Formatter):
Expand All @@ -97,7 +117,11 @@ class JSONLogFormatter(logging.Formatter):
@override
def __init__(self, *, fmt_keys: FormatKeys | None = None) -> None:
super().__init__()
self.fmt_keys = fmt_keys if fmt_keys is not None else {}
self.fmt_keys = (
fmt_keys
if fmt_keys is not None
else FormatKeys()
)

@override
def format(self, record: logging.LogRecord) -> str:
Expand All @@ -119,18 +143,18 @@ def _prepare_log_dict(self, record: logging.LogRecord) -> LogDict:
if record.stack_info is not None:
required_fields['stack_info'] = self.formatStack(record.stack_info)

message: LogDict = {
message: LogDict = { # type: ignore[assignment]
key: msg_val
if (msg_val := required_fields.pop(val, None)) is not None
else getattr(record, val)
if (msg_val := required_fields.pop(val, None)) is not None # type: ignore[misc, typeddict-item]
else getattr(record, val) # type: ignore[call-overload]
for key, val in self.fmt_keys.items()
}

message.update(required_fields)

for key, val in record.__dict__.items():
if key not in RecordAttrs:
message[key] = val
message[key] = val # type: ignore[literal-required]

return message

Expand Down
15 changes: 13 additions & 2 deletions src/project_name/logger_config.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
version = 1
disable_existing_loggers = false

[formatters.colour]
"()" = "project_name.logger.ColouredFormatter"
format = "%(asctime)s [%(levelname)s] %(module)s:L%(lineno)04d | %(funcName)s: %(message)s"
datefmt = "%d-%m-%Y %I:%M:%S"

[formatters.simple]
format = "[%(levelname)s|%(module)s|L%(lineno)d] %(asctime)s: %(message)s"
datefmt = "%Y-%m-%dT%H:%M:%S%z"
Expand All @@ -18,6 +23,12 @@ function = "funcName"
line = "lineno"
thread_name = "threadName"

[handlers.stdout]
class = "logging.StreamHandler"
level = "INFO"
formatter = "colour"
stream = "ext://sys.stdout"

[handlers.stderr]
class = "logging.StreamHandler"
level = "WARNING"
Expand All @@ -35,8 +46,9 @@ backupCount = 3
[handlers.queue_handler]
class = "project_name.logger.CustomQueueHandler"
handlers = [
"stderr",
"file_json",
# "stderr",
"stdout",
]
respect_handler_level = true

Expand All @@ -45,4 +57,3 @@ level = "DEBUG"
handlers = [
"queue_handler",
]

4 changes: 1 addition & 3 deletions src/project_name/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,14 @@

import logging

from project_name.logger import ROOT_LOGGER_NAME, setup_logging, CustomQueueHandler
from project_name.logger import ROOT_LOGGER_NAME, setup_logging

logger = logging.getLogger(ROOT_LOGGER_NAME)


def main() -> None:
"""Lorem Ipsum."""
setup_logging()
# logger.addHandler(CustomQueueHandler(level=logging.INFO))
# logging.basicConfig(level=logging.INFO) # noqa: ERA001

logger.debug("debug message", extra={'foo': 'hello'})
logger.info("info message")
Expand Down

0 comments on commit c091e47

Please sign in to comment.