Why Gemfury? Push, build, and install  RubyGems npm packages Python packages Maven artifacts PHP packages Go Modules Debian packages RPM packages NuGet packages

Repository URL to install this package:

Details    
Size: Mime:
import logging
from itertools import chain
from pathlib import Path
from typing import Dict, Iterable, Iterator, Tuple

from pythonjsonlogger.jsonlogger import RESERVED_ATTRS, JsonFormatter

ELASTIC_APM_FILTERS = (
    "elasticapm_labels",
    "elasticapm_service_name",
    "elasticapm_span_id",
    "elasticapm_trace_id",
    "elasticapm_transaction_id",
    "elasticapm_event_dataset",
)

DEFAULT_LOGGING_FORMAT = "asctime=%(asctime)s levelname=%(levelname)s name=%(name)s pathname=%(pathname)s lineno=%(lineno)d message=%(message)s"
DEFAULT_JSON_LOGGING_FORMAT = "%(asctime)s %(levelname)s %(name)s %(pathname)s %(lineno)d %(message)s"

HOME_PATH = str(Path.home())


def parse_loggers(loggers: Iterable[str]) -> Iterator[Tuple[str, str]]:
    for logger in loggers:
        log_parts = logger.split("=")
        if len(log_parts) == 1:
            yield log_parts[0], "INFO"
        elif len(log_parts) == 2:
            yield log_parts[0], log_parts[1]


class CustomFormatter(logging.Formatter):
    def __init__(self, *args, **kwargs):
        self.reserved = kwargs.pop("reserved_attrs", RESERVED_ATTRS)
        super().__init__(*args, **kwargs)

    def get_extra(self, record: logging.LogRecord) -> Iterator[str]:
        for key, value in record.__dict__.items():
            if key not in self.reserved and not (hasattr(key, "startswith") and key.startswith("_")):
                yield f"{key}={value!r}"

    def format(self, record: logging.LogRecord) -> str:
        base = super().format(record)
        return ", ".join(chain([base], self.get_extra(record)))


def get_logging_formatter(
    loggers: Iterable[str],
    log_stream_handler=None,
    extra_config: Iterable[any] = [],
) -> Dict:
    logging_config = {
        "version": 1,
        "disable_existing_loggers": False,
        "formatters": {
            "default": {
                "()": CustomFormatter,
                "reserved_attrs": RESERVED_ATTRS + ELASTIC_APM_FILTERS,
                "format": DEFAULT_LOGGING_FORMAT,
            },
            "json": {
                "()": JsonFormatter,
                "reserved_attrs": RESERVED_ATTRS + ELASTIC_APM_FILTERS,
                "format": DEFAULT_JSON_LOGGING_FORMAT,
            },
        },
        "handlers": {
            "default": {
                "class": "logging.StreamHandler",
                "formatter": log_stream_handler or "default",
            },
            "log_file": {
                "class": "logging.handlers.RotatingFileHandler",
                "filename": f"{HOME_PATH}/logs/output_drf.log",
                "maxBytes": 1024 * 1024 * 15,  # 15MB
                "backupCount": 10,
                "formatter": log_stream_handler or "default",
            },
        },
        "root": {
            "handlers": ["default", "log_file"],
        },
        "loggers": {name: {"level": level} for name, level in parse_loggers(loggers)},
    }

    for configurer in extra_config:
        configurer.configure(logging_config)

    return logging_config