wimglenn / pytest-structlog

Structured logging assertions
MIT License
54 stars 6 forks source link

Add logger-name assertion #26

Closed petemounce closed 8 months ago

petemounce commented 8 months ago

I have been unable to make this work in a project where I've installed structlog and pytest-structlog.

Instead of getting a pass, I get an error like:

..F                                                                                                                                                                                                                                                                          [100%]
===================================================================================================================================== FAILURES =====================================================================================================================================
___________________________________________________________________________________________________________________________________ test_plugin ____________________________________________________________________________________________________________________________________

my_log = <common.log.Logger object at 0x10df971d0>, log = <pytest_structlog.StructuredLogCapture object at 0x10dfa70d0>

    def test_plugin(my_log, log):
        assert len(log.events) == 0
        logger = my_log.get_logger('unit-test')
        logger.warning('foo')
        assert len(log.events) == 1
        assert [
            {
                'event': 'foo',
                'log_level': 'warning',
                'logger': 'unit-test',
            }
        ]
>       assert log.has('foo', logger='unit-test')
E       AssertionError: assert False
E        +  where False = <bound method StructuredLogCapture.has of <pytest_structlog.StructuredLogCapture object at 0x10dfa70d0>>('foo', logger='unit-test')
E        +    where <bound method StructuredLogCapture.has of <pytest_structlog.StructuredLogCapture object at 0x10dfa70d0>> = <pytest_structlog.StructuredLogCapture object at 0x10dfa70d0>.has

components/common/test/test_log.py:24: AssertionError
----------------------------------------------------------------------------------------------------------------------------- Captured structlog call ------------------------------------------------------------------------------------------------------------------------------
{'event': 'foo', 'level': 'warning'}
============================================================================================================================= short test summary info ==============================================================================================================================
FAILED components/common/test/test_log.py::test_plugin - AssertionError: assert False
 +  where False = <bound method StructuredLogCapture.has of <pytest_structlog.StructuredLogCapture object at 0x10dfa70d0>>('foo', logger='unit-test')
 +    where <bound method StructuredLogCapture.has of <pytest_structlog.StructuredLogCapture object at 0x10dfa70d0>> = <pytest_structlog.StructuredLogCapture object at 0x10dfa70d0>.has
1 failed, 2 passed in 0.40s
wimglenn commented 8 months ago

Related: https://github.com/wimglenn/pytest-structlog/issues/22

Are you reconfiguring structlog for test? Do you have the add_logger_name processor in the chain? Please create a reproducible example.

pytest-structlog will not put the add_logger_name processor by default, if you want it you have to add it explicitly, with something like this:

import pytest
import structlog

logger = structlog.get_logger("the-logger-name")

@pytest.fixture(autouse=True)
def inject_logger_name(log):
    original_processors = structlog.get_config().get("processors", [])
    if structlog.stdlib.add_logger_name not in original_processors:
        processors = [structlog.stdlib.add_logger_name] + original_processors
        log.original_configure(processors=processors)
        yield
        log.original_configure(processors=original_processors)

def test_logger_name(log):
    logger.info("foo", k="bar")
    assert log.has("foo", k="bar", logger="the-logger-name")
petemounce commented 8 months ago

pytest-structlog will not put the add_logger_name processor by default

Ah! I have a singleton-class that initialises structlog. I hadn't appreciated that pytest-structlog is not acting on that same configuration.

My goal is to make some assertions that logging is configured (and remains configured!) the way I expect and want it to be, so for my use-case it's important that the tests run within the context of structlog being configured as I intend. For example, I have a processor to rename some fields to be how GCP Cloud Logging expects, among others.

Now I understand that nuance, I think I can figure out how to get pytest to set up my logging before running my tests with their assertions therein.

wimglenn commented 3 months ago

@petemounce In the recently released pytest-structlog 1.0, you have some new configuration options available in this plugin to help with controlling the logging configuration during test. It allows the user to specify what pre-existing processors they want to keep or evict.

See advanced configuration section in the readme for details.

petemounce commented 3 months ago

Thanks!