Skip to content

Instantly share code, notes, and snippets.

@BARJ
Created January 23, 2019 08:19
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save BARJ/c20e4c6c1d7bfcc17ed5a5cd979d4dfd to your computer and use it in GitHub Desktop.
Save BARJ/c20e4c6c1d7bfcc17ed5a5cd979d4dfd to your computer and use it in GitHub Desktop.
Mixin Context Logger
import logging
import os
import uuid
from logging.handlers import TimedRotatingFileHandler
from typing import Dict, List
from pythonjsonlogger import jsonlogger
# root logger
log = logging.getLogger()
log.setLevel(logging.INFO)
file = os.path.join("log", "db_service.json.log")
json_file_handler = TimedRotatingFileHandler(file, backupCount=3, when="MIDNIGHT")
formatter = jsonlogger.JsonFormatter(
"(levelname) (asctime) (name) (message) (filename) (lineno)"
)
json_file_handler.setFormatter(formatter)
log.addHandler(json_file_handler)
class LogMixin:
device_id: str
context_id: str
__annotations__: Dict[str, type]
@property
def log(self) -> "LogMixin.Logger":
return self
def set_context_attribute(self, key: str, _type: type) -> None:
LogMixin.__annotations__[key] = _type
def _get_context_attributes(self) -> List[str]:
return [attr for attr in LogMixin.__annotations__ if not attr.startswith("_")]
@property
def root_logger(self) -> logging.Logger:
"""
Override this property to change log handler
The try-except excplictelty shows that log can be undefined
"""
try:
return log
except NameError as error:
raise NameError(error)
def _log(
self, level, msg, args, exc_info=None, extra=None, stack_info=False
) -> None:
if not self.root_logger.isEnabledFor(level):
return
extra = extra if extra is not None else {}
for attr in [attr for attr in self._get_context_attributes()]:
if hasattr(self, attr):
extra[attr] = getattr(self, attr)
log._log(level, msg, args, exc_info, extra, stack_info)
def debug(self, msg, *args, **kwargs) -> None:
self._log(logging.DEBUG, msg, args, **kwargs)
def info(self, msg, *args, **kwargs) -> None:
self._log(logging.INFO, msg, args, **kwargs)
def warning(self, msg, *args, **kwargs) -> None:
self._log(logging.WARNING, msg, args, **kwargs)
def error(self, msg, *args, **kwargs) -> None:
self._log(logging.ERROR, msg, args, **kwargs)
def exception(self, msg, *args, exc_info=True, **kwargs):
self.error(msg, *args, exc_info=exc_info, **kwargs)
def critical(self, msg, *args, **kwargs) -> None:
self._log(logging.CRITICAL, msg, args, **kwargs)
class TestLogMixin(LogMixin):
def __init__(self, device_id):
self.device_id = device_id
self.context_id = str(uuid.uuid4())[0:4]
self.name = "John Doe"
# add random_id to context logger
self.random_id = str(uuid.uuid4())[0:4]
self.set_context_attribute("random_id", str)
def say_hello(self):
self.log.info(
"Hello World", extra={"appliance_state_id": str(uuid.uuid4())[0:4]}
)
TestLogMixin(device_id="foo").say_hello()
"""
OUTPUT:
> 2019-01-23 15:04:04,807", "name": "root", "message": "Hello World", "filename": "log_mixin.py", "lineno": 70, "appliance_state_id": "77bf", "device_id": "foo", "context_id": "0c07", "random_id": "a030"}
Note that filename and lineno are not accurate anymore.
"""
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment