예제 #1
0
 def test_formatter_with_tz_info_utc(self):
     """
     Check that, if tz is not None, log messages must have timezone info
     """
     formatter = ExtendedJsonFormatter(tz=timezone.utc)
     result = dict(formatter.formatter_fields_for_record(self.record))
     self.assertEqual(
         result, {
             'logged_at': '2018-06-16T13:16:00+00:00',
             'line_number': 42,
             'function': 'xablaufunc',
             'level': 'WARNING',
             'file_path':
             '/aiologger/tests/formatters/test_json_formatter.py'
         })
예제 #2
0
 def with_default_handlers(  # type: ignore
     cls,
     *,
     name: str = "aiologger-json",
     level: int = LogLevel.NOTSET,
     serializer: Callable[..., str] = json.dumps,
     flatten: bool = False,
     serializer_kwargs: Dict = None,
     extra: Dict = None,
     exclude_fields: Iterable[str] = None,
     loop: Optional[AbstractEventLoop] = None,
     tz: timezone = None,
     formatter: Optional[Formatter] = None,
 ):
     if formatter is None:
         formatter = ExtendedJsonFormatter(
             serializer=serializer, exclude_fields=exclude_fields, tz=tz
         )
     return super(JsonLogger, cls).with_default_handlers(
         name=name,
         level=level,
         loop=loop,
         flatten=flatten,
         serializer_kwargs=serializer_kwargs,
         extra=extra,
         formatter=formatter,
     )
예제 #3
0
    def test_json_properly_serialized_when_bytes_object(self):
        # orjson
        custom_formatter = ExtendedJsonFormatter(serializer=orjson.dumps)
        # Note: json.dumps by default uses this separator (', ', ': ')
        # adding a whitespace whereas with orjson it is not
        # so to have a perfect match is it necessary to specify it
        custom_orjson_serializer_msg = custom_formatter.format(self.record)

        # json
        serialized_result = self.formatter.format(self.record)
        content = json.loads(serialized_result)
        default_json_serializer_msg = self.formatter.serializer(
            content, separators=(",", ":"))

        self.assertEqual(custom_orjson_serializer_msg,
                         default_json_serializer_msg)
예제 #4
0
    def __init__(self,
                 name: str = 'aiologger-json',
                 level: int = logging.DEBUG,
                 serializer: Callable[..., str] = json.dumps,
                 flatten: bool = False,
                 serializer_kwargs: Dict = None,
                 extra: Dict = None,
                 exclude_fields: Iterable[str] = None,
                 loop: AbstractEventLoop = None,
                 tz: timezone = None,
                 formatter: Optional[logging.Formatter] = None,
                 handler_factory: Optional[Callable[
                     [], Awaitable[Iterable[logging.Handler]]]] = None):
        formatter = formatter or ExtendedJsonFormatter(
            serializer=serializer, exclude_fields=exclude_fields, tz=tz)
        super().__init__(name=name,
                         level=level,
                         loop=loop,
                         formatter=formatter,
                         handler_factory=handler_factory)

        self.flatten = flatten

        if serializer_kwargs is None:
            serializer_kwargs = {}
        self.serializer_kwargs = serializer_kwargs

        if extra is None:
            extra = {}
        self.extra = extra
예제 #5
0
 def test_formatter_with_tz_info_other_zone(self):
     """
     Current time is NOT UTC (is -7) and we want logs to be generate in America/Sao_Paulo (-3)
     """
     tz_america = timezone(timedelta(hours=-3))
     formatter = ExtendedJsonFormatter(tz=tz_america)
     result = dict(formatter.formatter_fields_for_record(self.record))
     self.assertEqual(
         result, {
             'logged_at': '2018-06-16T19:20:00-03:00',
             'line_number': 42,
             'function': 'xablaufunc',
             'level': 'WARNING',
             'file_path':
             '/aiologger/tests/formatters/test_json_formatter.py'
         })
예제 #6
0
 def test_formatter_with_tz_info_utc(self):
     """
     Check that, if tz is not None, log messages must have timezone info
     """
     formatter = ExtendedJsonFormatter(tz=timezone.utc)
     result = dict(formatter.formatter_fields_for_record(self.record))
     self.assertEqual(
         result,
         {
             "logged_at": "2018-06-16T13:16:00+00:00",
             "line_number": 42,
             "function": "xablaufunc",
             "level": "WARNING",
             "file_path":
             "/aiologger/tests/formatters/test_json_formatter.py",
         },
     )
예제 #7
0
 def setUp(self):
     self.formatter = ExtendedJsonFormatter()
     self.record = LogRecord(
         level=30,
         name='aiologger',
         pathname="/aiologger/tests/formatters/test_json_formatter.py",
         func='xablaufunc',
         lineno=42,
         msg={
             "dog": "Xablau",
             "action": "bark"
         },
         exc_info=None,
         args=None,
         extra=None,
         flatten=False,
         serializer_kwargs={})
예제 #8
0
 def test_formatter_with_tz_info_america_sao_paulo_from_utc(self):
     """
     Current time is UTC and we want logs to be generated on America/Sao_Paulo (-3)
     """
     tz_america = timezone(timedelta(hours=-3))
     formatter = ExtendedJsonFormatter(tz=tz_america)
     result = dict(formatter.formatter_fields_for_record(self.record))
     self.assertEqual(
         result,
         {
             "logged_at": "2018-06-16T13:20:00-03:00",
             "line_number": 42,
             "function": "xablaufunc",
             "level": "WARNING",
             "file_path":
             "/aiologger/tests/formatters/test_json_formatter.py",
         },
     )
예제 #9
0
 def get_logger(nats_handler, service_type):
     """
     Creates and returns a nats logging handler
     Args:
         nats_handler: a nats_handler object
         service_type: type of service 
     """
     handler = NatsLoggingHandler(nats_handler, service_type)
     formatter = ExtendedJsonFormatter(exclude_fields=["file_path"])
     handler.formatter = formatter
     logger = JsonLogger(name=nats_handler.sender_id)
     logger.add_handler(handler)
     return logger
예제 #10
0
 def test_default_log_fields_can_be_excluded_with_exclude_fields_initialization_argument(
         self):
     formatter = ExtendedJsonFormatter(
         exclude_fields=(LOG_LEVEL_FIELDNAME, ))
     self.assertNotIn(LOG_LEVEL_FIELDNAME, formatter.log_fields)
예제 #11
0
 def test_it_uses_default_log_fields_if_none_are_excluded_on_initialization(
         self):
     formatter = ExtendedJsonFormatter()
     self.assertEqual(ExtendedJsonFormatter.default_fields,
                      formatter.log_fields)
예제 #12
0
class ExtendedJsonFormatterTests(unittest.TestCase):
    def setUp(self):
        self.formatter = ExtendedJsonFormatter()
        self.record = ExtendedLogRecord(
            level=30,
            name="aiologger",
            pathname="/aiologger/tests/formatters/test_json_formatter.py",
            func="xablaufunc",
            lineno=42,
            msg={
                "dog": "Xablau",
                "action": "bark"
            },
            exc_info=None,
            args=None,
            extra=None,
            flatten=False,
            serializer_kwargs={},
        )

    def test_it_uses_default_log_fields_if_none_are_excluded_on_initialization(
            self):
        formatter = ExtendedJsonFormatter()
        self.assertEqual(ExtendedJsonFormatter.default_fields,
                         formatter.log_fields)

    def test_default_log_fields_can_be_excluded_with_exclude_fields_initialization_argument(
            self):
        formatter = ExtendedJsonFormatter(
            exclude_fields=(LOG_LEVEL_FIELDNAME, ))
        self.assertNotIn(LOG_LEVEL_FIELDNAME, formatter.log_fields)

    def test_formatter_fields_for_record_with_default_fields(self):
        result = dict(self.formatter.formatter_fields_for_record(self.record))
        self.assertEqual(
            result,
            {
                "logged_at": ANY,
                "line_number": 42,
                "function": "xablaufunc",
                "level": "WARNING",
                "file_path":
                "/aiologger/tests/formatters/test_json_formatter.py",
            },
        )

    @freeze_time("2018-06-16T10:16:00-03:00")
    def test_formatter_with_tz_info_utc(self):
        """
        Check that, if tz is not None, log messages must have timezone info
        """
        formatter = ExtendedJsonFormatter(tz=timezone.utc)
        result = dict(formatter.formatter_fields_for_record(self.record))
        self.assertEqual(
            result,
            {
                "logged_at": "2018-06-16T13:16:00+00:00",
                "line_number": 42,
                "function": "xablaufunc",
                "level": "WARNING",
                "file_path":
                "/aiologger/tests/formatters/test_json_formatter.py",
            },
        )

    @freeze_time("2018-06-16T16:20:00+00:00")
    def test_formatter_with_tz_info_america_sao_paulo_from_utc(self):
        """
        Current time is UTC and we want logs to be generated on America/Sao_Paulo (-3)
        """
        tz_america = timezone(timedelta(hours=-3))
        formatter = ExtendedJsonFormatter(tz=tz_america)
        result = dict(formatter.formatter_fields_for_record(self.record))
        self.assertEqual(
            result,
            {
                "logged_at": "2018-06-16T13:20:00-03:00",
                "line_number": 42,
                "function": "xablaufunc",
                "level": "WARNING",
                "file_path":
                "/aiologger/tests/formatters/test_json_formatter.py",
            },
        )

    @freeze_time("2018-06-16T15:20:00-07:00")
    def test_formatter_with_tz_info_other_zone(self):
        """
        Current time is NOT UTC (is -7) and we want logs to be generate in America/Sao_Paulo (-3)
        """
        tz_america = timezone(timedelta(hours=-3))
        formatter = ExtendedJsonFormatter(tz=tz_america)
        result = dict(formatter.formatter_fields_for_record(self.record))
        self.assertEqual(
            result,
            {
                "logged_at": "2018-06-16T19:20:00-03:00",
                "line_number": 42,
                "function": "xablaufunc",
                "level": "WARNING",
                "file_path":
                "/aiologger/tests/formatters/test_json_formatter.py",
            },
        )

    def test_formatter_fields_for_record_with_excluded_fields(self):
        log_fields = {LOG_LEVEL_FIELDNAME, LINE_NUMBER_FIELDNAME}

        with patch.object(self.formatter, "log_fields", log_fields):
            result = dict(
                self.formatter.formatter_fields_for_record(self.record))
            self.assertEqual(result, {"line_number": 42, "level": "WARNING"})

    def test_default_format(self):
        serialized_result = self.formatter.format(self.record)
        content = json.loads(serialized_result)
        self.assertEqual(
            content,
            {
                "logged_at": ANY,
                "line_number": 42,
                "function": "xablaufunc",
                "level": "WARNING",
                "file_path":
                "/aiologger/tests/formatters/test_json_formatter.py",
                "msg": {
                    "dog": "Xablau",
                    "action": "bark"
                },
            },
        )

    def test_flatten_record_attr_adds_msg_to_root(self):
        self.record.flatten = True
        serialized_result = self.formatter.format(self.record)

        content = json.loads(serialized_result)
        self.assertEqual(
            content,
            {
                "logged_at": ANY,
                "line_number": 42,
                "function": "xablaufunc",
                "level": "WARNING",
                "file_path":
                "/aiologger/tests/formatters/test_json_formatter.py",
                "dog": "Xablau",
                "action": "bark",
            },
        )

    def test_flatten_record_attr_does_nothing_if_msg_isnt_a_dict_instance(
            self):
        self.record.flatten = True
        self.record.msg = "Xablau, the dog"
        serialized_result = self.formatter.format(self.record)

        content = json.loads(serialized_result)
        self.assertEqual(
            content,
            {
                "logged_at": ANY,
                "line_number": 42,
                "function": "xablaufunc",
                "level": "WARNING",
                "file_path":
                "/aiologger/tests/formatters/test_json_formatter.py",
                "msg": "Xablau, the dog",
            },
        )

    def test_serialized_kwargs_record_attr_is_passed_to_instance_serialized_function(
            self):
        self.record.serializer_kwargs = {"indent": 2, "sort_keys": True}
        expected_msg = {
            "logged_at": ANY,
            "line_number": 42,
            "function": "xablaufunc",
            "level": "WARNING",
            "file_path": "/aiologger/tests/formatters/test_json_formatter.py",
            "msg": {
                "dog": "Xablau",
                "action": "bark"
            },
        }

        with patch.object(self.formatter, "serializer") as serializer:
            self.formatter.format(self.record)
            serializer.assert_called_once_with(
                expected_msg,
                indent=2,
                sort_keys=True,
                default=self.formatter._default_handler,
            )

    def test_extra_record_attr_adds_content_to_root_of_msg(self):
        self.record.extra = {"female_dog": "Xena"}
        serialized_result = self.formatter.format(self.record)

        content = json.loads(serialized_result)
        self.assertEqual(
            content,
            {
                "logged_at": ANY,
                "line_number": 42,
                "function": "xablaufunc",
                "level": "WARNING",
                "file_path":
                "/aiologger/tests/formatters/test_json_formatter.py",
                "msg": {
                    "dog": "Xablau",
                    "action": "bark"
                },
                "female_dog": "Xena",
            },
        )