Created
January 23, 2019 08:19
-
-
Save BARJ/c20e4c6c1d7bfcc17ed5a5cd979d4dfd to your computer and use it in GitHub Desktop.
Mixin Context Logger
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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