Skip to content

Commit 6c1f645

Browse files
Ensure logging is patched before calling basicConfig (#2905) (#2911)
* Ensure logging is patched before calling basicConfig fixes #1960 To reproduce run `DD_LOGS_INJECTION=true DD_TRACE_DEBUG=true ddtrace-run python -c ''`. The problem happens because we call basicConfig in `ddtrace/tracer.py` and then any logging that occurs during tracer initialization before `sitecustomize.py` will call `patch(logging=True)` * Add release note * remove flaky assertion * update comment Co-authored-by: mergify[bot] <37929162+mergify[bot]@users.noreply.github.com> (cherry picked from commit 38ddd31) Co-authored-by: Brett Langdon <[email protected]>
1 parent ef59bcc commit 6c1f645

File tree

4 files changed

+40
-1
lines changed

4 files changed

+40
-1
lines changed

ddtrace/contrib/logging/patch.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,9 @@ def _get_current_span(tracer=None):
3939
if not tracer:
4040
tracer = ddtrace.tracer
4141

42-
if not tracer.enabled:
42+
# We might be calling this during library initialization, in which case `ddtrace.tracer` might
43+
# be the `tracer` module and not the global tracer instance.
44+
if not getattr(tracer, "enabled", False):
4345
return None
4446

4547
return tracer.current_span()

ddtrace/tracer.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@
4949
from .internal.writer import AgentWriter
5050
from .internal.writer import LogWriter
5151
from .internal.writer import TraceWriter
52+
from .monkey import patch
5253
from .provider import DefaultContextProvider
5354
from .sampler import BasePrioritySampler
5455
from .sampler import BaseSampler
@@ -72,6 +73,8 @@
7273
)
7374
if debug_mode and not hasHandlers(log) and call_basic_config:
7475
if config.logs_injection:
76+
# We need to ensure logging is patched in case the tracer logs during initialization
77+
patch(logging=True)
7578
logging.basicConfig(level=logging.DEBUG, format=DD_LOG_FORMAT)
7679
else:
7780
logging.basicConfig(level=logging.DEBUG)
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
---
2+
fixes:
3+
- |
4+
Fixes exceptions raised when logging during tracer initialization when ``DD_LOGS_INJECTION`` is enabled.

tests/integration/test_integration.py

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -601,3 +601,33 @@ def test_partial_flush_log(run_python_code_in_subprocess):
601601
log.debug.assert_has_calls(calls)
602602
s1.finish()
603603
t.shutdown()
604+
605+
606+
def test_ddtrace_run_startup_logging_injection(ddtrace_run_python_code_in_subprocess):
607+
"""
608+
Regression test for enabling debug logging and logs injection
609+
610+
When both DD_TRACE_DEBUG and DD_LOGS_INJECTION are enabled
611+
any logging during tracer initialization would raise an exception
612+
because `dd.service` was not available in the log record yet.
613+
"""
614+
env = os.environ.copy()
615+
env["DD_TRACE_DEBUG"] = "true"
616+
env["DD_LOGS_INJECTION"] = "true"
617+
618+
# DEV: We don't actually have to execute any code to validate this
619+
out, err, status, pid = ddtrace_run_python_code_in_subprocess("", env=env)
620+
621+
# The program will always exit successfully
622+
# Errors during logging do not crash the app
623+
assert status == 0, (out, err)
624+
625+
# The program does nothing
626+
assert out == b""
627+
628+
# stderr is expected to log something due to debug logging
629+
assert b"[dd.service= dd.env= dd.version= dd.trace_id=0 dd.span_id=0]" in err
630+
631+
# Assert no logging exceptions in stderr
632+
assert b"KeyError: 'dd.service'" not in err
633+
assert b"ValueError: Formatting field not found in record: 'dd.service'" not in err

0 commit comments

Comments
 (0)