async def test_log_message_type_shortcuts(log_level): max_size = 5 factory = LoggerFactory() factory.min_log_level = LogLevel.NONE test_target = InMemoryFlushLogTarget(max_size) factory.add_target(test_target) logger = factory.get_logger(__name__) assert logger is not None for i in range(max_size): if log_level == LogLevel.DEBUG: await logger.debug(f'Message: {i}') if log_level == LogLevel.INFORMATION: await logger.info(f'Message: {i}') if log_level == LogLevel.CRITICAL: await logger.critical(f'Message: {i}') if log_level == LogLevel.ERROR: await logger.error(f'Message: {i}') if log_level == LogLevel.WARNING: await logger.warning(f'Message: {i}') # all records must be present in destinations assert len(test_target.destination) == max_size i = 0 for record in test_target.destination: assert f'Message: {i}' == record.message assert record.level == log_level i += 1
async def test_logger_throws_for_too_high_log_level(): factory = LoggerFactory() factory.min_log_level = LogLevel.NONE test_target = InMemoryFlushLogTarget() factory.add_target(test_target) logger = factory.get_logger(__name__) with raises(ValueError, match='Invalid log level'): await logger.log('Something', level=max(LogLevel) + 1)
async def test_records_support_extra_arguments(): factory = LoggerFactory() test_target = InMemoryTarget() factory.add_target(test_target) logger = factory.get_logger(__name__) assert logger is not None await logger.info('Hello, World', 'One', 'Two', 'Three') record = test_target.records[0] # type: LogRecord assert ('One', 'Two', 'Three') == record.args
async def test_records_support_extra_data(): factory = LoggerFactory() test_target = InMemoryTarget() factory.add_target(test_target) logger = factory.get_logger(__name__) assert logger is not None await logger.info('Hello, World', id=2016, name='Tyberiusz') record = test_target.records[0] # type: LogRecord assert {'id': 2016, 'name': 'Tyberiusz'} == record.data
async def test_records_have_timestamp(): factory = LoggerFactory() test_target = InMemoryTarget() factory.add_target(test_target) logger = factory.get_logger(__name__) assert logger is not None for i in range(10): await logger.info(f'Hello, World {i}') for record in test_target.records: assert record.time
async def test_flush_target_no_fallback_warning_with_graceful_handling(): factory = LoggerFactory() max_size = 2 test_target = FailingFlushLogTargetNoFallback(max_size) factory.add_target(test_target) logger = factory.get_logger(__name__) assert logger is not None for i in range(max_size - 1): await logger.info(f'Message: {i}') with pytest.warns(RuntimeWarning, match='Failed to log records for'): await logger.info(f'Message: {max_size - 1}')
def test_logger_factory_get_targets(): factory = LoggerFactory() test_target = InMemoryTarget() factory.add_target(test_target, minimum_level=LogLevel.CRITICAL) targets = factory.targets assert targets is not None assert targets[LogLevel.DEBUG] == [] assert targets[LogLevel.INFORMATION] == [] assert targets[LogLevel.CRITICAL] == [test_target] second_target = InMemoryTarget() factory.add_target(second_target, minimum_level=LogLevel.INFORMATION) assert targets[LogLevel.INFORMATION] == [second_target] assert targets[LogLevel.CRITICAL] == [test_target]
async def test_logger_factory_flushes_when_disposing_handling_exceptions(): factory = LoggerFactory() target_1 = FailingFlushLogTarget(5) target_2 = InMemoryFlushLogTarget(5) factory.add_target(target_1) factory.add_target(target_2) logger = factory.get_logger('example') for i in range(3): await logger.info(f'Hello, World {i}') assert len(target_2.destination) == 0 await factory.dispose() assert len(target_2.destination) == 3
async def test_flushing_fallback_nested_flushing_target(): factory = LoggerFactory() max_size = 5 test_target = FailingFlushLogTarget( max_size, fallback_target=InMemoryFlushLogTarget(max_size=max_size)) factory.add_target(test_target) logger = factory.get_logger(__name__) assert logger is not None for i in range(max_size - 1): await logger.info(f'Message: {i}') await logger.info(f'Message: {max_size - 1}') assert max_size == len(test_target.fallback.destination) i = 0 for record in test_target.fallback.destination: assert f'Message: {i}' == record.message i += 1
async def test_logger_factory_on_dispose_error_callback(): factory = LoggerFactory() factory.add_target(FailingFlushLogTargetFailFallback(5)) k = 0 def on_error_callback(exc): nonlocal k k = 1 assert isinstance(exc, CrashTest) factory.on_dispose_error = on_error_callback logger = factory.get_logger('example') for i in range(3): await logger.info(f'Hello, World {i}') await factory.dispose() assert k == 1
async def test_flushing_fallback_when_fails(): factory = LoggerFactory() max_size = 2 test_target = FailingFlushLogTarget(max_size) factory.add_target(test_target) logger = factory.get_logger(__name__) assert logger is not None for i in range(max_size - 1): await logger.info(f'Message: {i}') await logger.info(f'Message: {max_size - 1}') # since we forced failure, records should be logged in fallback target assert max_size == len(test_target.fallback.records) i = 0 for record in test_target.fallback.records: assert f'Message: {i}' == record.message i += 1
async def test_logger_exception(): factory = LoggerFactory() test_target = InMemoryTarget() factory.add_target(test_target) logger = factory.get_logger(__name__) try: 1 / 0 except Exception as ex: # passing exception await logger.exception('Oh, no!', ex) assert 'Oh, no!' == test_target.records[0].message try: 1 / 0 except Exception: # without passing exception await logger.exception('Oh, no2!') assert 'Oh, no2!' == test_target.records[1].message
async def test_flushing(max_size): factory = LoggerFactory() test_target = InMemoryFlushLogTarget(max_size) factory.add_target(test_target) logger = factory.get_logger(__name__) assert logger is not None for i in range(max_size - 1): await logger.info(f'Message: {i}') assert 0 == len(test_target.destination) await logger.info(f'Message: {max_size - 1}') # now all records must be present in destinations assert max_size == len(test_target.destination) i = 0 for record in test_target.destination: assert f'Message: {i}' == record.message i += 1
async def test_logger_wrapping_sync_logging_dynamic_target(): name = str(uuid.uuid4()) get_builtin_sync_logger(name) factory = LoggerFactory() factory.add_target(DynamicBuiltInLoggingTarget()) logger = factory.get_logger(name) await logger.info('Lorem ipsum dolor sit amet') try: 1 / 0 except Exception: # passing exception await logger.exception('Oh, no!') with open(name + '.log', mode='rt', encoding='utf8') as file_log: content = file_log.read() assert 'Lorem ipsum dolor sit amet' in content assert 'ZeroDivisionError: division by zero' in content os.remove(name + '.log')
def test_logger_factory_raises_invalid_minimum_level(invalid_value): factory = LoggerFactory() with raises(ValueError, match='Invalid minimum_level'): factory.add_target(InMemoryTarget(), minimum_level=invalid_value)