Coverage for /usr/local/lib/python3.10/site-packages/opal_common-0.0.0-py3.10.egg/opal_common/logger.py: 89%
31 statements
« prev ^ index » next coverage.py v7.15.2, created at 2026-10-10 11:54 +0000
« prev ^ index » next coverage.py v7.15.2, created at 2026-10-10 11:54 +0000
1import logging
2import sys
4from loguru import logger
5from opal_common.config import opal_common_config
6from opal_common.http_utils import redact_url_in_text
7from opal_common.logging_utils.filter import ModuleFilter
8from opal_common.logging_utils.formatter import Formatter
9from opal_common.logging_utils.intercept import InterceptHandler
10from opal_common.logging_utils.scrubbing import CredentialScrubbingStream
11from opal_common.logging_utils.thirdparty import hijack_uvicorn_logs
12from opal_common.monitoring.apm import fix_ddtrace_logging
15def _scrub_record_message(record):
16 """loguru patcher: scrub embedded URL credentials from every record's
17 message before it reaches any sink.
19 Runs once per record (order-independent across sinks), so it also protects
20 the optional rotating file sink, which is path-based and cannot be
21 stream-wrapped. The stream sink is *additionally* wrapped with
22 ``CredentialScrubbingStream`` to scrub rendered exception tracebacks, which
23 this message-only pass does not touch.
24 """
25 message = record.get("message")
26 if message: 26 ↛ exitline 26 didn't return from function '_scrub_record_message' because the condition on line 26 was always true
27 record["message"] = redact_url_in_text(message)
30def configure_logs():
31 """Takeover process logs and create a logger with Loguru according to the
32 configuration."""
33 fix_ddtrace_logging()
35 intercept_handler = InterceptHandler()
36 formatter = Formatter(opal_common_config.LOG_FORMAT)
37 filter = ModuleFilter(
38 include_list=opal_common_config.LOG_MODULE_INCLUDE_LIST,
39 exclude_list=opal_common_config.LOG_MODULE_EXCLUDE_LIST,
40 )
41 logging.basicConfig(handlers=[intercept_handler], level=0, force=True)
43 if opal_common_config.LOG_PATCH_UVICORN_LOGS: 43 ↛ 47line 43 didn't jump to line 47 because the condition on line 43 was always true
44 # Monkey patch UVICORN to use our logger
45 hijack_uvicorn_logs(intercept_handler)
46 # Clean slate
47 logger.remove()
48 # Scrub credentialed URLs from every record's message, for all sinks.
49 logger.configure(patcher=_scrub_record_message)
50 # Logger configuration
51 pipe = sys.stderr if opal_common_config.LOG_PIPE_TO_STDERR else sys.stdout
52 # Wrap the stream so embedded URL credentials are scrubbed from the final
53 # formatted record - including third-party exception tracebacks (e.g. aiohttp
54 # rendering ``https://user:pw@host?token=...``) that the model-layer
55 # redaction cannot reach. Message-level scrubbing for all sinks (incl. the
56 # rotating file sink, which cannot be wrapped) is handled by the patcher above.
57 logger.add(
58 CredentialScrubbingStream(pipe),
59 filter=filter.filter,
60 format=formatter.format,
61 level=opal_common_config.LOG_LEVEL,
62 backtrace=opal_common_config.LOG_TRACEBACK,
63 diagnose=opal_common_config.LOG_DIAGNOSE,
64 colorize=opal_common_config.LOG_COLORIZE,
65 serialize=opal_common_config.LOG_SERIALIZE,
66 )
67 # log to a file
68 if opal_common_config.LOG_TO_FILE: 68 ↛ 69line 68 didn't jump to line 69 because the condition on line 68 was never true
69 logger.add(
70 opal_common_config.LOG_FILE_PATH,
71 compression=opal_common_config.LOG_FILE_COMPRESSION,
72 retention=opal_common_config.LOG_FILE_RETENTION,
73 rotation=opal_common_config.LOG_FILE_ROTATION,
74 serialize=opal_common_config.LOG_FILE_SERIALIZE,
75 level=opal_common_config.LOG_FILE_LEVEL,
76 )
79def get_logger(name=""):
80 """Backward compatibility to old get_logger."""
81 return logger