import json import logging from unittest import mock import pytest from structlog.testing import capture_logs from smelog.entities import LoggerConfig from smelog.factory import LoggerFactory dummy_exception = ValueError('incorrect name') @pytest.mark.freeze_time('2021-04-26') @pytest.mark.parametrize( 'name, msg_args, msg_kwargs, context_kwargs, expected', [ ( 'empty', (), {}, {}, [{ 'event': 'debug message: %s', 'log_level': 'info' }], ), ( 'interpolation', ('interpolation variable', ), {}, {}, [ { 'positional_args': ('interpolation variable', ), 'event': 'debug message: %s', 'log_level': 'info' } ], ), ( 'extra', ('interpolation variable', ), { 'error': dummy_exception, 'page': 1, 'title': 'GoF', }, {}, [ { 'error': dummy_exception, 'page': 1, 'title': 'GoF', 'positional_args': ('interpolation variable', ), 'event': 'debug message: %s', 'log_level': 'info' } ] ), ( 'context', ('interpolation variable', ), { 'error': dummy_exception, 'page': 1, 'title': 'GoF', }, { 'trace_id': '12345', 'timestamp': 12345, }, [ { 'trace_id': '12345', 'timestamp': 12345, 'error': dummy_exception, 'page': 1, 'title': 'GoF', 'positional_args': ('interpolation variable', ), 'event': 'debug message: %s', 'log_level': 'info' } ], ), ] ) def test_logger_before_processing( name, msg_args, msg_kwargs, context_kwargs, expected, caplog, reset_structlog ): # pylint: disable=unused-argument factory = LoggerFactory( LoggerConfig( name='test_config', version='0.0.1', level=logging.DEBUG, environment='dev', is_local=True, ) ).configure() with capture_logs() as cap_logs: logger = factory.get_logger() logger = logger.bind(**context_kwargs) logger.info('debug message: %s', *msg_args, **msg_kwargs) assert cap_logs == expected @pytest.mark.freeze_time('2021-04-26') @pytest.mark.parametrize( 'level, is_local, msg, expected', [ ( logging.DEBUG, False, 'aaa', [ { "event": "aaa", "logger": "test_config", "level": "debug", 'env': 'dev', 'timestamp': '2021-04-26 00:00:00' }, { "event": "aaa", "logger": "test_config", "level": "info", 'env': 'dev', 'timestamp': '2021-04-26 00:00:00' }, { "event": "aaa", "logger": "test_config", "level": "warning", 'env': 'dev', 'timestamp': '2021-04-26 00:00:00' }, { "event": "aaa", "logger": "test_config", "level": "error", 'env': 'dev', 'timestamp': '2021-04-26 00:00:00' }, { "event": "aaa", "logger": "test_config", "level": "critical", 'env': 'dev', 'timestamp': '2021-04-26 00:00:00' }, ] ), ( logging.DEBUG, False, 'bbbb', [ { "event": "bbbb", "logger": "test_config", "level": "debug", 'env': 'dev', 'timestamp': '2021-04-26 00:00:00' }, { "event": "bbbb", "logger": "test_config", "level": "info", 'env': 'dev', 'timestamp': '2021-04-26 00:00:00' }, { "event": "bbbb", "logger": "test_config", "level": "warning", 'env': 'dev', 'timestamp': '2021-04-26 00:00:00' }, { "event": "bbbb", "logger": "test_config", "level": "error", 'env': 'dev', 'timestamp': '2021-04-26 00:00:00' }, { "event": "bbbb", "logger": "test_config", "level": "critical", 'env': 'dev', 'timestamp': '2021-04-26 00:00:00' }, ] ), ( logging.INFO, False, 'ccc', [ { "event": "ccc", "logger": "test_config", "level": "info", 'env': 'dev', 'timestamp': '2021-04-26 00:00:00' }, { "event": "ccc", "logger": "test_config", "level": "warning", 'env': 'dev', 'timestamp': '2021-04-26 00:00:00' }, { "event": "ccc", "logger": "test_config", "level": "error", 'env': 'dev', 'timestamp': '2021-04-26 00:00:00' }, { "event": "ccc", "logger": "test_config", "level": "critical", 'env': 'dev', 'timestamp': '2021-04-26 00:00:00' }, ] ), ( logging.CRITICAL, False, 'ddd', [ { "event": "ddd", "logger": "test_config", "level": "critical", 'env': 'dev', 'timestamp': '2021-04-26 00:00:00' }, ] ), ] ) def test_raw_messages_filters(level, is_local, msg, expected, reset_structlog): # pylint: disable=unused-argument factory = LoggerFactory( LoggerConfig( name='test_config', version='0.0.1', level=level, environment='dev', is_local=is_local, ) ).configure() logger = factory.get_logger('test_config').new() handler = mock.MagicMock() handler.level = logging.DEBUG handler.handle = mock.Mock() logger.addHandler(handler) try: logger.debug(msg) logger.info(msg) logger.warning(msg) logger.error(msg) logger.critical(msg) result = [json.loads(x[0][0].msg) for x in handler.handle.call_args_list] assert result == expected finally: logger.removeHandler(handler) @pytest.mark.freeze_time('2021-04-26') @pytest.mark.parametrize( 'level, is_local, msg, expected', [ ( logging.INFO, False, 'message', [ '{"event": "message", "logger": "test_config",' ' "level": "info", "env": "dev", "timestamp": "2021-04-26 00:00:00"}', ] ), ( logging.INFO, True, 'message', [ '\x1b[2m2021-04-26 00:00:00\x1b[0m [\x1b[32m\x1b[1minfo \x1b[0m] ' '\x1b[1mmessage \x1b[0m [\x1b[34m\x1b[1mtest_config\x1b[0m] ' '\x1b[36menv\x1b[0m=\x1b[35mdev\x1b[0m' ] ), ] ) def test_raw_messages_renderers(level, is_local, msg, expected, reset_structlog): # pylint: disable=unused-argument logger = LoggerFactory( LoggerConfig( name='test_config', version='0.0.1', level=level, environment='dev', is_local=is_local, ) ).get_logger('test_config') handler = mock.MagicMock() handler.level = logging.DEBUG handler.handle = mock.Mock() logger.addHandler(handler) try: logger.info(msg) result = [x[0][0].msg for x in handler.handle.call_args_list] assert result == expected finally: logger.removeHandler(handler) @pytest.mark.freeze_time('2021-04-26') @pytest.mark.parametrize( 'msg, msg_args, msg_kwargs, context_kwargs, expected', [ ( 'message', (), {}, {}, [ { 'event': 'message', 'logger': 'test_config', 'level': 'debug', 'env': 'dev', 'timestamp': '2021-04-26 00:00:00' } ], ), ( 'message %s', ('hello', ), {}, {}, [ { 'event': 'message hello', 'logger': 'test_config', 'level': 'debug', 'env': 'dev', 'timestamp': '2021-04-26 00:00:00' } ], ), ( 'message', (), { 'hello': 'world' }, {}, [ { 'hello': 'world', 'event': 'message', 'logger': 'test_config', 'level': 'debug', 'env': 'dev', 'timestamp': '2021-04-26 00:00:00' } ], ), ( 'message', (), {}, { 'planet': 'Earth' }, [ { 'planet': 'Earth', 'event': 'message', 'logger': 'test_config', 'level': 'debug', 'env': 'dev', 'timestamp': '2021-04-26 00:00:00', } ], ), ] ) def test_raw_messages_enriched( msg, msg_args, msg_kwargs, context_kwargs, expected, reset_structlog ): # pylint: disable=unused-argument factory = LoggerFactory( LoggerConfig( name='test_config', version='0.0.1', level=logging.DEBUG, environment='dev', is_local=False ) ).configure() logger = factory.get_logger('test_config') handler = mock.MagicMock() handler.level = logging.DEBUG handler.handle = mock.Mock() logger.addHandler(handler) try: logger = logger.bind(**context_kwargs) logger.debug(msg, *msg_args, **msg_kwargs) result = [json.loads(x[0][0].msg) for x in handler.handle.call_args_list] assert result == expected finally: logger.removeHandler(handler)