Skip to content

Commit

Permalink
Added support for older python versions (#2)
Browse files Browse the repository at this point in the history
  • Loading branch information
danyi1212 authored Mar 17, 2024
1 parent 7364a53 commit e7c640e
Show file tree
Hide file tree
Showing 28 changed files with 183 additions and 106 deletions.
16 changes: 8 additions & 8 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,13 @@ jobs:
strategy:
fail-fast: false
matrix:
python-version: [ "3.12" ]
ujson-version: ["5.9"]
orjson-version: ["3.9"]
fastapi-version: ["0.110"]
flask-version: ["3.0"]
django-version: ["5.0"]
celery-version: ["5.3"]
python-version: [ "3.9", "3.10", "3.11", "3.12" ]
ujson-version: ["latest"]
orjson-version: ["latest"]
fastapi-version: ["latest"]
flask-version: ["latest"]
django-version: ["4.2"]
celery-version: ["latest"]

steps:
- uses: actions/checkout@v4
Expand Down Expand Up @@ -60,7 +60,7 @@ jobs:
run: poetry install --no-interaction --no-root

- name: Install optional dependencies
run: poetry add "ujson~=${{ matrix.ujson-version }}" "orjson~=${{ matrix.orjson-version }}" "fastapi~=${{ matrix.fastapi-version }}" "flask~=${{ matrix.flask-version }}" "django~=${{ matrix.django-version }}" "celery~=${{ matrix.celery-version }}" --no-interaction
run: poetry add ujson@${{ matrix.ujson-version }} orjson@${{ matrix.orjson-version }} fastapi@${{ matrix.fastapi-version }} flask@${{ matrix.flask-version }} django@${{ matrix.django-version }} celery@${{ matrix.celery-version }} --no-interaction

- name: Install library
run: poetry install --no-interaction
Expand Down
6 changes: 3 additions & 3 deletions dans_log_formatter/contrib/celery/provider.py
Original file line number Diff line number Diff line change
@@ -1,17 +1,17 @@
from logging import LogRecord
from typing import Any
from typing import Any, Optional

from celery import current_task

from providers.abstract import AbstractProvider
from dans_log_formatter.providers.abstract import AbstractProvider


class CeleryTaskProvider(AbstractProvider):
def __init__(self, *, include_args: bool = False):
super().__init__()
self.include_args = include_args

def get_attributes(self, record: LogRecord) -> None | dict[str, Any]: # noqa ARG002
def get_attributes(self, record: LogRecord) -> Optional[dict[str, Any]]: # noqa ARG002
if current_task is None:
return None

Expand Down
2 changes: 1 addition & 1 deletion dans_log_formatter/contrib/django/middleware.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
from asgiref.sync import iscoroutinefunction, markcoroutinefunction
from django.http import HttpRequest

from contrib.django.provider import django_request_context
from dans_log_formatter.contrib.django.provider import django_request_context


class LogContextMiddleware:
Expand Down
8 changes: 4 additions & 4 deletions dans_log_formatter/contrib/django/provider.py
Original file line number Diff line number Diff line change
@@ -1,20 +1,20 @@
from contextvars import ContextVar
from logging import LogRecord
from typing import Any
from typing import Any, Optional

from django.http import HttpRequest
from django.urls import resolve, Resolver404

from providers.abstract_context import AbstractContextProvider
from dans_log_formatter.providers.abstract_context import AbstractContextProvider

django_request_context: ContextVar[HttpRequest | None] = ContextVar("django_log_context", default=None)
django_request_context: ContextVar[Optional[HttpRequest]] = ContextVar("django_log_context", default=None)


class DjangoRequestProvider(AbstractContextProvider):
def __init__(self):
super().__init__(django_request_context)

def get_context_attributes(self, record: LogRecord, request: HttpRequest) -> None | dict[str, Any]: # noqa ARG002
def get_context_attributes(self, record: LogRecord, request: HttpRequest) -> Optional[dict[str, Any]]: # noqa ARG002
result = {
"resource": self.get_resource(request),
"http.url": request.build_absolute_uri(),
Expand Down
2 changes: 1 addition & 1 deletion dans_log_formatter/contrib/fastapi/middleware.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
from starlette.requests import Request
from starlette.responses import Response

from contrib.fastapi.provider import fastapi_request_context
from dans_log_formatter.contrib.fastapi.provider import fastapi_request_context


class LogContextMiddleware(BaseHTTPMiddleware):
Expand Down
5 changes: 3 additions & 2 deletions dans_log_formatter/contrib/fastapi/provider.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
from contextvars import ContextVar
from logging import LogRecord
from typing import Optional

from fastapi.routing import APIRoute
from starlette.requests import Request

from providers.abstract_context import AbstractContextProvider
from dans_log_formatter.providers.abstract_context import AbstractContextProvider

fastapi_request_context: ContextVar[Request | None] = ContextVar("fastapi_log_context", default=None)
fastapi_request_context: ContextVar[Optional[Request]] = ContextVar("fastapi_log_context", default=None)


class FastAPIRequestProvider(AbstractContextProvider):
Expand Down
6 changes: 3 additions & 3 deletions dans_log_formatter/contrib/flask/provider.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
from logging import LogRecord
from typing import Any
from typing import Any, Optional

from flask import has_request_context, request

from providers.abstract import AbstractProvider
from dans_log_formatter.providers.abstract import AbstractProvider


class FlaskRequestProvider(AbstractProvider):
def get_attributes(self, record: LogRecord) -> None | dict[str, Any]: # noqa ARG002
def get_attributes(self, record: LogRecord) -> Optional[dict[str, Any]]: # noqa ARG002
if not has_request_context():
return None

Expand Down
2 changes: 1 addition & 1 deletion dans_log_formatter/contrib/orjson.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

import orjson

from formatter import JsonLogFormatter
from dans_log_formatter.formatter import JsonLogFormatter


class OrJsonLogFormatter(JsonLogFormatter):
Expand Down
2 changes: 1 addition & 1 deletion dans_log_formatter/contrib/ujson.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

import ujson

from formatter import JsonLogFormatter
from dans_log_formatter.formatter import JsonLogFormatter


class UJsonLogFormatter(JsonLogFormatter):
Expand Down
27 changes: 13 additions & 14 deletions dans_log_formatter/formatter.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import json
import sys
from logging import Formatter, LogRecord
from typing import Literal, Mapping, Any
from typing import Literal, Optional

from dans_log_formatter.providers.abstract import AbstractProvider
from formatter_error import FormatterError
from dans_log_formatter.formatter_error import FormatterError

DEFAULT_MESSAGE_SIZE_LIMIT = 64 * 1024
DEFAULT_STACK_SIZE_LIMIT = 128 * 1024
Expand All @@ -14,17 +14,16 @@
class TextLogFormatter(Formatter):
def __init__(
self,
fmt: str | None = None,
datefmt: str | None = None,
fmt: Optional[str] = None,
datefmt: Optional[str] = None,
style: Literal["%", "{", "$"] = "%",
validate: bool = True, # noqa FBT001, FBT002
providers: list[AbstractProvider] | None = None,
providers: Optional[list[AbstractProvider]] = None,
*,
defaults: Mapping[str, Any] | None = None,
message_size_limit: int | None = DEFAULT_MESSAGE_SIZE_LIMIT,
stack_size_limit: int | None = DEFAULT_STACK_SIZE_LIMIT,
message_size_limit: Optional[int] = DEFAULT_MESSAGE_SIZE_LIMIT,
stack_size_limit: Optional[int] = DEFAULT_STACK_SIZE_LIMIT,
):
super().__init__(fmt, datefmt, style, validate, defaults=defaults)
super().__init__(fmt, datefmt, style, validate) # "defaults" argument is added in Python 3.10
self.providers = providers or []
self.message_size_limit = message_size_limit
self.stack_size_limit = stack_size_limit
Expand Down Expand Up @@ -88,7 +87,7 @@ def format_stack_info(self, record: LogRecord) -> str:
stack = self.formatStack(record.stack_info)
return self.truncate_string(stack, self.stack_size_limit, "stack_info")

def truncate_string(self, value: str, limit: int | None, attribute_name: str) -> str:
def truncate_string(self, value: str, limit: Optional[int], attribute_name: str) -> str:
length = len(value)
if limit is not None and length > limit:
self.record_error(f"Attribute '{attribute_name}' value is too long: {length:,} (limit: {limit:,})")
Expand All @@ -102,7 +101,7 @@ def format_location(self, record: LogRecord):
def format_file(self, record: LogRecord):
return record.pathname

def get_provider_attributes(self, index: int, provider: AbstractProvider, record: LogRecord) -> dict | None:
def get_provider_attributes(self, index: int, provider: AbstractProvider, record: LogRecord) -> Optional[dict]:
try:
provider_data = provider.get_attributes(record)
except Exception as e: # noqa BLE001
Expand Down Expand Up @@ -135,10 +134,10 @@ def _get_formatter_errors(self) -> str:
class JsonLogFormatter(TextLogFormatter):
def __init__(
self,
providers: list[AbstractProvider] | None = None,
providers: Optional[list[AbstractProvider]] = None,
*,
message_size_limit: int | None = DEFAULT_MESSAGE_SIZE_LIMIT,
stack_size_limit: int | None = DEFAULT_STACK_SIZE_LIMIT,
message_size_limit: Optional[int] = DEFAULT_MESSAGE_SIZE_LIMIT,
stack_size_limit: Optional[int] = DEFAULT_STACK_SIZE_LIMIT,
):
super().__init__(providers=providers, message_size_limit=message_size_limit, stack_size_limit=stack_size_limit)

Expand Down
4 changes: 2 additions & 2 deletions dans_log_formatter/formatter_error.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
from types import TracebackType
from typing import NamedTuple, Type
from typing import NamedTuple, Type, Union

ExecInfo = tuple[Type[BaseException], BaseException, TracebackType]


class FormatterError(NamedTuple):
message: str
exc_info: ExecInfo | tuple[None, None, None] = (None, None, None)
exc_info: Union[ExecInfo, tuple[None, None, None]] = (None, None, None)
6 changes: 3 additions & 3 deletions dans_log_formatter/providers/abstract.py
Original file line number Diff line number Diff line change
@@ -1,17 +1,17 @@
import sys
from abc import ABC, abstractmethod
from logging import LogRecord
from typing import Any
from typing import Any, Optional

from formatter_error import FormatterError
from dans_log_formatter.formatter_error import FormatterError


class AbstractProvider(ABC):
def __init__(self):
self._formatter_errors: list[FormatterError] = []

@abstractmethod
def get_attributes(self, record: LogRecord) -> None | dict[str, Any]:
def get_attributes(self, record: LogRecord) -> Optional[dict[str, Any]]:
raise NotImplementedError()

def record_error(self, message: str) -> None:
Expand Down
6 changes: 3 additions & 3 deletions dans_log_formatter/providers/abstract_context.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
from abc import abstractmethod, ABC
from contextvars import ContextVar
from logging import LogRecord
from typing import Any
from typing import Any, Optional

from dans_log_formatter.providers.abstract import AbstractProvider

Expand All @@ -11,13 +11,13 @@ def __init__(self, context: ContextVar):
super().__init__()
self.context = context

def get_attributes(self, record: LogRecord) -> None | dict[str, Any]:
def get_attributes(self, record: LogRecord) -> Optional[dict[str, Any]]:
value = self.context.get()
if value is None:
return None

return self.get_context_attributes(record, value)

@abstractmethod
def get_context_attributes(self, record: LogRecord, context_value) -> None | dict[str, Any]:
def get_context_attributes(self, record: LogRecord, context_value) -> Optional[dict[str, Any]]:
raise NotImplementedError()
6 changes: 3 additions & 3 deletions dans_log_formatter/providers/context.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
from contextlib import contextmanager
from contextvars import ContextVar
from logging import LogRecord
from typing import Any
from typing import Any, Optional

from providers.abstract_context import AbstractContextProvider
from dans_log_formatter.providers.abstract_context import AbstractContextProvider

_context: ContextVar[dict[str, Any] | None] = ContextVar("custom_log_context", default=None)
_context: ContextVar[Optional[dict[str, Any]]] = ContextVar("custom_log_context", default=None)


class ContextProvider(AbstractContextProvider):
Expand Down
6 changes: 3 additions & 3 deletions dans_log_formatter/providers/extra.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
from logging import LogRecord
from typing import Any, ClassVar
from typing import Any, ClassVar, Optional

from providers.abstract import AbstractProvider
from dans_log_formatter.providers.abstract import AbstractProvider


class ExtraProvider(AbstractProvider):
Expand Down Expand Up @@ -45,6 +45,6 @@ def extract_extra(self, record: LogRecord) -> dict:
if attr_name not in self.builtin_attrs
}

def get_attributes(self, record: LogRecord) -> None | dict[str, Any]:
def get_attributes(self, record: LogRecord) -> Optional[dict[str, Any]]:
extra = self.extract_extra(record)
return extra if extra else None
6 changes: 3 additions & 3 deletions dans_log_formatter/providers/runtime.py
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
from logging import LogRecord
from typing import Any
from typing import Any, Optional

from providers.abstract import AbstractProvider
from dans_log_formatter.providers.abstract import AbstractProvider


class RuntimeProvider(AbstractProvider):
"""
Add runtime information about thread, process and asyncio task to the log record.
"""

def get_attributes(self, record: LogRecord) -> None | dict[str, Any]:
def get_attributes(self, record: LogRecord) -> Optional[dict[str, Any]]:
result = {}
if record.process is not None:
result["process"] = f"{record.processName} ({record.process})"
Expand Down
Loading

0 comments on commit e7c640e

Please sign in to comment.