From a98b7bf0fa69c40e623ee6daa7e3dde006253b95 Mon Sep 17 00:00:00 2001 From: Suren Khorenyan Date: Thu, 5 Aug 2021 16:46:35 +0300 Subject: [PATCH] Allow to pass custom loads and dumps to JsonFormatter --- jsonformatter/jsonformatter.py | 32 ++++++++++++++++++-- test/test.py | 55 ++++++++++++++++++++++++++++++++++ test/test_windows.py | 55 ++++++++++++++++++++++++++++++++++ 3 files changed, 139 insertions(+), 3 deletions(-) diff --git a/jsonformatter/jsonformatter.py b/jsonformatter/jsonformatter.py index 4ee9038..a47c0b9 100644 --- a/jsonformatter/jsonformatter.py +++ b/jsonformatter/jsonformatter.py @@ -162,7 +162,7 @@ class JsonFormatter(logging.Formatter): def parseFmt(self, fmt): if isinstance(fmt, str): - return json.loads(fmt, object_pairs_hook=dictionary) + return self.loads(fmt, object_pairs_hook=dictionary) elif isinstance(fmt, dictionary): return fmt elif isinstance(fmt, dict): @@ -216,7 +216,28 @@ def wrapper(*args, **kwargs): else: return - def __init__(self, fmt=BASIC_FORMAT, datefmt=None, style='%', record_custom_attrs=None, mix_extra=False, mix_extra_position='tail', skipkeys=False, ensure_ascii=True, check_circular=True, allow_nan=True, cls=None, indent=None, separators=None, encoding='utf-8', default=None, sort_keys=False, **kw): + def __init__( + self, + fmt=BASIC_FORMAT, + datefmt=None, + style='%', + record_custom_attrs=None, + mix_extra=False, + mix_extra_position='tail', + skipkeys=False, + ensure_ascii=True, + check_circular=True, + allow_nan=True, + cls=None, + indent=None, + separators=None, + encoding='utf-8', + default=None, + sort_keys=False, + dumps=json.dumps, + loads=json.loads, + **kw, + ): """ If ``style`` not in ``['%', '{', '$']``, a ``ValueError`` will be raised. @@ -269,6 +290,9 @@ def __init__(self, fmt=BASIC_FORMAT, datefmt=None, style='%', record_custom_attr If *sort_keys* is true (default: ``False``), then the output of dictionaries will be sorted by key. + ``dumps`` custom function to use instead of json.dumps + ``loads`` custom function to use instead of json.loads + To use a custom ``JSONEncoder`` subclass (e.g. one that overrides the ``.default()`` method to serialize additional types), specify it with the ``cls`` kwarg; otherwise ``JSONEncoder`` is used. @@ -290,6 +314,8 @@ def __init__(self, fmt=BASIC_FORMAT, datefmt=None, style='%', record_custom_attr self, fmt='', datefmt=datefmt, style=style) # compatible python2 end + self.dumps = dumps + self.loads = loads self.json_fmt = self.parseFmt(fmt) self.record_custom_attrs = record_custom_attrs self._style = _STYLES[style](self.json_fmt) @@ -424,7 +450,7 @@ def _set_fmt_to_result(): record.__extra = extra # store __extra end - return json.dumps( + return self.dumps( result, skipkeys=self.skipkeys, ensure_ascii=self.ensure_ascii, diff --git a/test/test.py b/test/test.py index 2587b93..69b06cf 100644 --- a/test/test.py +++ b/test/test.py @@ -9,6 +9,7 @@ Description: jsonformatter.py """ import datetime +import json import logging import os import random @@ -486,6 +487,60 @@ def test_basic_config_format(self): ) logging.info('basic config format') + def test_custom_json_lib_dict_config(self): + def my_dumps(*args, **kwargs): + return json.dumps(*args, **kwargs) + + def my_loads(*args, **kwargs): + return json.loads(*args, **kwargs) + + log_format = """{ + "levelname": "levelname", + "name": "name", + "log": "message" + }""" + log_level = "DEBUG" + + formatters = { + "default": { + "()": "jsonformatter.JsonFormatter", + "fmt": log_format, + "indent": None, + "ensure_ascii": False, + "dumps": my_dumps, + "loads": my_loads, + }, + } + + handlers = { + "default": { + "level": log_level, + "class": "logging.StreamHandler", + "stream": "ext://sys.stdout", + "formatter": "default", + } + + } + loggers = { + "": { + "handlers": ["default"], + "level": log_level, + "propagate": False, + }, + } + + config = { + "version": 1, + "disable_existing_loggers": False, + "formatters": formatters, + "handlers": handlers, + "loggers": loggers, + } + + logging.config.dictConfig(config) + logger = logging.getLogger("test-logger") + logger.debug("check if works (it does)") + def tearDown(self): root = logging.getLogger() # remove handlers diff --git a/test/test_windows.py b/test/test_windows.py index 179515d..c525c21 100644 --- a/test/test_windows.py +++ b/test/test_windows.py @@ -9,6 +9,7 @@ Description: jsonformatter.py """ import datetime +import json import logging import os import random @@ -497,6 +498,60 @@ def test_basic_config_format(self): ) logging.info('basic config format') + def test_custom_json_lib_dict_config(self): + def my_dumps(*args, **kwargs): + return json.dumps(*args, **kwargs) + + def my_loads(*args, **kwargs): + return json.loads(*args, **kwargs) + + log_format = """{ + "levelname": "levelname", + "name": "name", + "log": "message" + }""" + log_level = "DEBUG" + + formatters = { + "default": { + "()": "jsonformatter.JsonFormatter", + "fmt": log_format, + "indent": None, + "ensure_ascii": False, + "dumps": my_dumps, + "loads": my_loads, + }, + } + + handlers = { + "default": { + "level": log_level, + "class": "logging.StreamHandler", + "stream": "ext://sys.stdout", + "formatter": "default", + } + + } + loggers = { + "": { + "handlers": ["default"], + "level": log_level, + "propagate": False, + }, + } + + config = { + "version": 1, + "disable_existing_loggers": False, + "formatters": formatters, + "handlers": handlers, + "loggers": loggers, + } + + logging.config.dictConfig(config) + logger = logging.getLogger("test-logger") + logger.debug("check if works (it does)") + def tearDown(self): root = logging.getLogger() # remove handlers