userver: /data/code/userver/testsuite/pytest_plugins/pytest_userver/plugins/log_capture.py Source File
Loading...
Searching...
No Matches
log_capture.py
1"""
2Capture and work with logs.
3"""
4
5# pylint: disable=redefined-outer-name
6import logging
7
8import pytest
9
10from testsuite import logcapture
11from testsuite.logcapture import __tracebackhide__ # noqa
12
13from ..utils import tskv
14
15USERVER_CONFIG_HOOKS = ['_userver_config_logs_capture']
16DEFAULT_PORT = 2211
17
18logger = logging.getLogger(__name__)
19
20
21def pytest_addoption(parser) -> None:
22 group = parser.getgroup('logs-capture')
23 group.addoption(
24 '--logs-capture-port',
25 type=int,
26 default=0,
27 help='Port to bind logs-capture server to.',
28 )
29 group.addoption(
30 '--logs-capture-host',
31 default='localhost',
32 help='Host to bind logs-capture server to.',
33 )
34
35
36@pytest.fixture(scope='session')
37async def userver_log_capture(pytestconfig, userver_log_level) -> logcapture.CaptureServer:
38 """
39 Session-scoped TCP server that receives service logs in TSKV format.
40
41 The server is started once per testsuite session. Static config is patched
42 so that the service can send logs when log capture is enabled for a test.
43
44 In most tests use
45 @ref pytest_userver.plugins.service_client.service_client "service_client".capture_logs()
46 instead of this fixture directly. See @ref testsuite_logs_capture.
47
48 Example — filter captured logs after a request:
49
50 @snippet samples/testsuite-support/tests/test_logcapture.py select
51
52 Example — subscribe to log events as they arrive:
53
54 @snippet samples/testsuite-support/tests/test_logcapture.py subscribe
55
56 @ingroup userver_testsuite_fixtures
57 """
58 host = pytestconfig.option.logs_capture_host
59 port = pytestconfig.option.logs_capture_port
60 if pytestconfig.option.service_wait or pytestconfig.option.service_disable:
61 port = port or DEFAULT_PORT
62
63 server = logcapture.CaptureServer(
64 log_level=logcapture.LogLevel.from_string(userver_log_level),
65 parse_line=_tskv_parse_line,
66 )
67 async with server.start(host=host, port=port):
68 yield server
69
70
71@pytest.fixture(scope='session')
72def _userver_config_logs_capture(userver_log_capture):
73 socknames = userver_log_capture.getsocknames()
74 assert socknames
75 sockname = socknames[0]
76
77 def patch_config(config: dict, _config_vars: dict) -> None:
78 logging_config = config['components_manager']['components']['logging']
79 default_logger = logging_config['loggers']['default']
80 # Other formats are not yet supported by log-capture.
81 default_logger['format'] = 'tskv'
82 default_logger['testsuite-capture'] = {
83 'host': sockname[0],
84 'port': sockname[1],
85 }
86
87 return patch_config
88
89
90def _tskv_parse_line(rawline: bytes) -> tskv.TskvRow:
91 line = rawline.decode(encoding='utf-8', errors='replace')
92 return tskv.parse_line(line)