Skip to content

Commit 002453c

Browse files
authored
chore(logging): make log injection config a boolean (#14032)
## Summary This PR simplifies the internal configuration handling for log injection in ddtrace-py. Currently, DD_LOGS_INJECTION=true and DD_LOGS_INJECTION=structured are treated as distinct states, but in practice, log injection is only supported for structured loggers, not for unstructured logging like print() or loguru without a formatter. With this change: - Both true and structured will be mapped to the boolean True. - false will be mapped to False. This logic only affects internal private configuration and does not alter public interfaces or behavior. ## Compatibility This is fully backwards compatible. The environment variable values structured, true, and false remain supported and retain their expected effects. ## Checklist - [x] PR author has checked that all the criteria below are met - The PR description includes an overview of the change - The PR description articulates the motivation for the change - The change includes tests OR the PR description describes a testing strategy - The PR description notes risks associated with the change, if any - Newly-added code is easy to change - The change follows the [library release note guidelines](https://ddtrace.readthedocs.io/en/stable/releasenotes.html) - The change includes or references documentation updates if necessary - Backport labels are set (if [applicable](https://ddtrace.readthedocs.io/en/latest/contributing.html#backporting)) ## Reviewer Checklist - [ ] Reviewer has checked that all the criteria below are met - Title is accurate - All changes are related to the pull request's stated goal - Avoids breaking [API](https://ddtrace.readthedocs.io/en/stable/versioning.html#interfaces) changes - Testing strategy adequately addresses listed risks - Newly-added code is easy to change - Release note makes sense to a user of the library - If necessary, author has acknowledged and discussed the performance implications of this PR as reported in the benchmarks PR comment - Backport labels are set in a manner that is consistent with the [release branch maintenance policy](https://ddtrace.readthedocs.io/en/latest/contributing.html#backporting)
1 parent 0fa8949 commit 002453c

File tree

18 files changed

+49
-54
lines changed

18 files changed

+49
-54
lines changed

.github/workflows/system-tests.yml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ jobs:
4242
persist-credentials: false
4343
repository: 'DataDog/system-tests'
4444
# Automatically managed, use scripts/update-system-tests-version to update
45-
ref: '13b08f0faf7673656bd68dad5c142ad04eddee69'
45+
ref: 'e79a35571dedbe2e9bc5f4731a3cf172f589b032'
4646

4747
- name: Checkout dd-trace-py
4848
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
@@ -96,7 +96,7 @@ jobs:
9696
persist-credentials: false
9797
repository: 'DataDog/system-tests'
9898
# Automatically managed, use scripts/update-system-tests-version to update
99-
ref: '13b08f0faf7673656bd68dad5c142ad04eddee69'
99+
ref: 'e79a35571dedbe2e9bc5f4731a3cf172f589b032'
100100

101101
- name: Build runner
102102
uses: ./.github/actions/install_runner
@@ -277,7 +277,7 @@ jobs:
277277
persist-credentials: false
278278
repository: 'DataDog/system-tests'
279279
# Automatically managed, use scripts/update-system-tests-version to update
280-
ref: '13b08f0faf7673656bd68dad5c142ad04eddee69'
280+
ref: 'e79a35571dedbe2e9bc5f4731a3cf172f589b032'
281281
- name: Checkout dd-trace-py
282282
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
283283
with:

ddtrace/_logger.py

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ class LogInjectionState(object):
2020
# Log injection is enabled, but not yet configured
2121
ENABLED = "true"
2222
# Log injection is enabled and configured for structured logging
23+
# This value is deprecated, but kept for backwards compatibility
2324
STRUCTURED = "structured"
2425

2526

@@ -108,17 +109,15 @@ def set_log_formatting():
108109
handler.setFormatter(logging.Formatter(DD_LOG_FORMAT))
109110

110111

111-
def get_log_injection_state(raw_config: Optional[str]) -> str:
112+
def get_log_injection_state(raw_config: Optional[str]) -> bool:
112113
"""Returns the current log injection state."""
113114
if raw_config:
114115
normalized = raw_config.lower().strip()
115-
if normalized == LogInjectionState.STRUCTURED:
116-
return LogInjectionState.STRUCTURED
117-
elif normalized in ("true", "1"):
118-
return LogInjectionState.ENABLED
116+
if normalized == LogInjectionState.STRUCTURED or normalized in ("true", "1"):
117+
return True
119118
elif normalized not in ("false", "0"):
120119
logging.warning(
121120
"Invalid log injection state '%s'. Expected 'true', 'false', or 'structured'. Defaulting to 'false'.",
122121
normalized,
123122
)
124-
return LogInjectionState.DISABLED
123+
return False

ddtrace/_trace/product.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -215,7 +215,7 @@ def apm_tracing_rc(lib_config, dd_config):
215215
new_rc_configs["_trace_sampling_rules"] = trace_sampling_rules
216216

217217
if "log_injection_enabled" in lib_config:
218-
new_rc_configs["_logs_injection"] = str(lib_config["log_injection_enabled"]).lower()
218+
new_rc_configs["_logs_injection"] = lib_config["log_injection_enabled"]
219219

220220
if "tracing_tags" in lib_config:
221221
tags = lib_config["tracing_tags"]

ddtrace/contrib/internal/logbook/patch.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@
55

66
import ddtrace
77
from ddtrace import config
8-
from ddtrace._logger import LogInjectionState
98
from ddtrace.contrib.internal.trace_utils import unwrap as _u
109
from ddtrace.internal.utils import get_argument_value
1110

@@ -27,7 +26,7 @@ def _supported_versions() -> Dict[str, str]:
2726

2827
def _w_process_record(func, instance, args, kwargs):
2928
# patch logger to include datadog info before logging
30-
if config._logs_injection != LogInjectionState.DISABLED:
29+
if config._logs_injection:
3130
record = get_argument_value(args, kwargs, 0, "record")
3231
record.extra.update(ddtrace.tracer.get_log_correlation_context())
3332
return func(*args, **kwargs)

ddtrace/contrib/internal/logging/patch.py

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@
55

66
import ddtrace
77
from ddtrace import config
8-
from ddtrace._logger import LogInjectionState
98
from ddtrace._logger import set_log_formatting
109
from ddtrace.contrib.internal.trace_utils import unwrap as _u
1110
from ddtrace.internal.constants import LOG_ATTR_ENV
@@ -54,15 +53,13 @@ def __init__(self, trace_id: int, span_id: int, service: str, version: str, env:
5453
def _w_makeRecord(func, instance, args, kwargs):
5554
# Get the LogRecord instance for this log
5655
record = func(*args, **kwargs)
57-
if config._logs_injection == LogInjectionState.DISABLED:
58-
# log injection is opt-in for non-structured logging
59-
return record
60-
record.__dict__.update(ddtrace.tracer.get_log_correlation_context())
56+
if config._logs_injection:
57+
record.__dict__.update(ddtrace.tracer.get_log_correlation_context())
6158
return record
6259

6360

6461
def _w_StrFormatStyle_format(func, instance, args, kwargs):
65-
if config._logs_injection != LogInjectionState.ENABLED:
62+
if not config._logs_injection:
6663
return func(*args, **kwargs)
6764
# The format string "dd.service={dd.service}" expects
6865
# the record to have a "dd" property which is an object that
@@ -103,7 +100,7 @@ def patch():
103100
_w(logging.Logger, "makeRecord", _w_makeRecord)
104101
_w(logging.StrFormatStyle, "_format", _w_StrFormatStyle_format)
105102

106-
if config._logs_injection == LogInjectionState.ENABLED:
103+
if config._logs_injection:
107104
# Only set the formatter is DD_LOGS_INJECTION is set to True. We do not want to modify
108105
# unstructured logs if a user has not enabled logs injection.
109106
# Also, the Datadog log format must be set after the logging module has been patched,

ddtrace/contrib/internal/loguru/patch.py

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@
55

66
import ddtrace
77
from ddtrace import config
8-
from ddtrace._logger import LogInjectionState
98
from ddtrace.contrib.internal.trace_utils import unwrap as _u
109

1110

@@ -25,12 +24,11 @@ def _supported_versions() -> Dict[str, str]:
2524

2625

2726
def _tracer_injection(event_dict):
28-
if config._logs_injection == LogInjectionState.DISABLED:
27+
if not config._logs_injection:
2928
# log injection is opt-out for structured logging
3029
return event_dict
3130
event_dd_attributes = ddtrace.tracer.get_log_correlation_context()
3231
event_dict.update(event_dd_attributes)
33-
3432
return event_dd_attributes
3533

3634

ddtrace/contrib/internal/structlog/patch.py

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44

55
import ddtrace
66
from ddtrace import config
7-
from ddtrace._logger import LogInjectionState
87
from ddtrace.contrib.internal.trace_utils import unwrap as _u
98
from ddtrace.contrib.internal.trace_utils import wrap as _w
109
from ddtrace.internal.utils import get_argument_value
@@ -27,9 +26,8 @@ def _supported_versions() -> Dict[str, str]:
2726

2827

2928
def _tracer_injection(_, __, event_dict):
30-
if config._logs_injection == LogInjectionState.DISABLED:
31-
return event_dict
32-
event_dict.update(ddtrace.tracer.get_log_correlation_context())
29+
if config._logs_injection:
30+
event_dict.update(ddtrace.tracer.get_log_correlation_context())
3331
return event_dict
3432

3533

ddtrace/settings/_config.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@
1717
from ddtrace.internal.telemetry import validate_otel_envs
1818
from ddtrace.internal.utils.cache import cachedmethod
1919

20-
from .._logger import LogInjectionState
2120
from .._logger import get_log_injection_state
2221
from ..internal import gitmetadata
2322
from ..internal.constants import _PROPAGATION_BEHAVIOR_DEFAULT
@@ -378,7 +377,7 @@ def _default_config() -> Dict[str, _ConfigItem]:
378377
modifier=str,
379378
),
380379
"_logs_injection": _ConfigItem(
381-
default=LogInjectionState.STRUCTURED,
380+
default=True,
382381
envs=["DD_LOGS_INJECTION"],
383382
modifier=get_log_injection_state,
384383
),

tests/commands/test_runner.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -330,7 +330,7 @@ def test_info_no_configs():
330330
b"Application Security enabled: False",
331331
b"Remote Configuration enabled: False",
332332
b"Debug logging: False",
333-
b"Log injection enabled: structured",
333+
b"Log injection enabled: True",
334334
b"Health metrics enabled: False",
335335
b"Partial flushing enabled: True",
336336
b"Partial flush minimum number of spans: 300",
@@ -386,7 +386,7 @@ def test_info_w_configs():
386386
b"Remote Configuration enabled: True",
387387
b"IAST enabled (experimental)",
388388
b"Debug logging: True",
389-
b"Log injection enabled: true",
389+
b"Log injection enabled: True",
390390
b"Health metrics enabled: False",
391391
b"Partial flushing enabled: True",
392392
b"Partial flush minimum number of spans: 1000",

tests/contrib/logging/test_logging.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -303,7 +303,7 @@ def test_log_strformat_style_format(self):
303303
assert getattr(record, LOG_ATTR_SPAN_ID) == str(span.span_id)
304304

305305

306-
@pytest.mark.parametrize("dd_logs_enabled", ["true", "false", "structured"])
306+
@pytest.mark.parametrize("dd_logs_enabled", ["true", "structured"])
307307
def test_manual_log_formatter_injection(dd_logs_enabled: str, run_python_code_in_subprocess):
308308
code = """
309309
import ddtrace.auto
@@ -321,7 +321,7 @@ def test_manual_log_formatter_injection(dd_logs_enabled: str, run_python_code_in
321321
"""
322322

323323
env = os.environ.copy()
324-
env["DD_LOGS_ENABLED"] = dd_logs_enabled
324+
env["DD_LOGS_INJECTION"] = dd_logs_enabled
325325
stdout, stderr, status, _ = run_python_code_in_subprocess(code, env=env)
326326
assert status == 0, stderr
327327

0 commit comments

Comments
 (0)