Skip to content

Inject active span trace_id into log records#65

Merged
prim-8 merged 2 commits into
mainfrom
feature/log-trace-id
May 5, 2026
Merged

Inject active span trace_id into log records#65
prim-8 merged 2 commits into
mainfrom
feature/log-trace-id

Conversation

@prim-8
Copy link
Copy Markdown
Contributor

@prim-8 prim-8 commented May 5, 2026

Summary

  • Adds a logging.Filter that pulls the active span's trace_id (from either ddtrace or OTel, whichever provider is active) and stamps it on every LogRecord.
  • Updates the format string to surface it as trace_id=<32-hex>.
  • Defaults to empty when no tracing is active or no span is current, so the format never KeyErrors.

This enables logs-to-traces correlation in Grafana Explore (and any other UI that runs a regex over the line) for milter log lines — previously the click-through never matched.

Test plan

  • Standalone smoke test: filter populates trace_id=<32-hex> inside an active OTel span, clears it outside, no KeyError on weird messages, no KeyError when no provider is active.
  • Build the milter image and run a fake mail through it, verify trace_id= field in stdout.
  • After merge + bump in the consumer repo, verify Grafana Explore's logs→traces derived-field click-through resolves to a real Tempo trace.

Adds a logging.Filter that pulls the active span's trace_id (from
either ddtrace or OTel, whichever provider is active) and stamps it
on every LogRecord. Updates the format string to surface it as
trace_id=<32-hex>. Defaults to empty when no tracing is active or no
span is current, so the format never KeyErrors.

Enables Grafana Explore's logs-to-traces derived-field click-through
for milter log lines.
@greptile-apps
Copy link
Copy Markdown
Contributor

greptile-apps Bot commented May 5, 2026

Greptile Summary

Adds a _TraceIdFilter that injects the active span's trace_id into every LogRecord and updates the log format string to surface it, enabling logs-to-traces correlation in Grafana Explore.

  • _TraceIdFilter.filter() always sets record.trace_id = \"\" first, so the %(trace_id)s format token never raises KeyError when no span is active or no tracing provider is configured.
  • The filter is attached at the handler level (rather than the logger level) so it fires for records from third-party libraries as well as application loggers.
  • Imports of ddtrace/opentelemetry are deferred inside the filter method; Python's import cache makes repeated calls cheap.

Confidence Score: 5/5

Safe to merge — the change is additive and isolated to log formatting; the filter always sets a default so the format string is safe even with no active tracing provider.

The logic is straightforward: the filter guards every exit path with a default empty string, the handler-level attachment means all loggers are covered, and Python's module cache keeps the per-record import lookups cheap. Both the ddtrace and OTel branches are handled correctly, including the 0-valued INVALID_TRACE_ID case.

No files require special attention.

Important Files Changed

Filename Overview
milter/primitivemail_milter.py Adds _TraceIdFilter logging.Filter that injects the active span's trace_id into every log record for both ddtrace and OTel providers; updates the log format string and attaches the filter to all configured handlers.

Reviews (2): Last reviewed commit: "Drop dead-code None guard on get_current..." | Re-trigger Greptile

Comment thread milter/primitivemail_milter.py Outdated
OTel's get_current_span() always returns a Span (a live span or the
INVALID_SPAN sentinel), never None. The trace_id == 0 check already
handles the no-active-span case — the if-span-else-None guard above
it was unreachable and misleading.

Per Greptile P2 nit on #65.
@prim-8 prim-8 merged commit 90c01be into main May 5, 2026
8 checks passed
@prim-8 prim-8 deleted the feature/log-trace-id branch May 5, 2026 23:49
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant