Skip to content

feat: add W3C Trace Context propagation middleware for OpenTelemetry - #38

Merged
yordis merged 1 commit into
mainfrom
otel-middleware
Jan 1, 2026
Merged

yordis merged 1 commit into
mainfrom
otel-middleware

Conversation

@yordis

@yordis yordis commented Jan 1, 2026

Copy link
Copy Markdown
Member

No description provided.

@cursor

cursor Bot commented Jan 1, 2026 •

Copy link
Copy Markdown

PR Summary

Introduces OpenTelemetry-based trace context propagation to correlate commands and event handling.

  • New Commanded.Middleware.TraceContextPropagator injects traceparent/tracestate into event metadata when a span is active
  • Comprehensive tests cover presence/absence of active spans, metadata preservation, and child-span behavior
  • Documentation updated in guides/explanations/fork-differences.md with usage and benefits
  • Adds opentelemetry_api as optional dependency; test-only opentelemetry and opentelemetry_exporter; updates dialyzer PLT apps and lockfile

Written by Cursor Bugbot for commit 91c29a8. This will update automatically on new commits. Configure here.

@coderabbitai

coderabbitai Bot commented Jan 1, 2026 •

Copy link
Copy Markdown

Warning

Rate limit exceeded

@yordis has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 6 minutes and 31 seconds before requesting another review.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

📥 Commits

Reviewing files that changed from the base of the PR and between 8240051 and 91c29a8.

⛔ Files ignored due to path filters (1)
  • mix.lock is excluded by !**/*.lock
📒 Files selected for processing (4)
  • guides/explanations/fork-differences.md
  • lib/commanded/middleware/trace_context_propagator.ex
  • mix.exs
  • test/opentelemetry/trace_context_propagator_test.exs

Note

Other AI code review bot(s) detected

CodeRabbit has detected other AI code review bot(s) in this pull request and will avoid duplicating their findings in the review comments. This may lead to a less comprehensive review.

Walkthrough

This PR introduces OpenTelemetry W3C Trace Context propagation to Commanded via a new middleware module. It captures OpenTelemetry span context during command dispatch and injects traceparent/tracestate headers into event metadata for downstream trace correlation. Includes documentation, optional dependencies, and comprehensive tests.

Changes

Cohort / File(s) Summary
Documentation
guides/explanations/fork-differences.md
Added new "W3C Trace Context Propagation Middleware" section documenting the TraceContextPropagator, its usage, benefits (trace correlation, non-invasive metadata), and marking opentelemetry_api as optional.
Core Implementation
lib/commanded/middleware/trace_context_propagator.ex
New middleware module implementing Commanded.Middleware behavior. Conditionally loaded when otel_propagator_text_map is available. Captures OpenTelemetry span context via W3C standard headers (traceparent, tracestate) and injects into pipeline metadata. Includes before_dispatch/1 logic and passthrough after_dispatch/1, after_failure/1.
Configuration
mix.exs
Added opentelemetry_api as optional dependency; added opentelemetry and opentelemetry_exporter as test dependencies; updated dialyzer plt_add_apps to include opentelemetry_api.
Tests
test/opentelemetry/trace_context_propagator_test.exs
Comprehensive test module validating before_dispatch/1 captures traceparent when span is active, handles absence of active spans, preserves existing metadata, and after_dispatch/1 and after_failure/1 return pipeline unchanged.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Poem

🐰 With whiskers twitched and hoppy feet,
I trace the context through the beat,
W3C standards, clean and bright,
Propagating spans in OpenTelemetry light!
No invasive hops, just metadata bliss—
Correlation perfection, what a trace to miss! ✨

Pre-merge checks and finishing touches

❌ Failed checks (1 warning, 1 inconclusive)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 33.33% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
Description check ❓ Inconclusive No pull request description was provided by the author, making it impossible to assess relatedness to the changeset. Add a pull request description explaining the purpose, benefits, and usage of the new W3C Trace Context propagation middleware feature.
✅ Passed checks (1 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately describes the main change: adding a W3C Trace Context propagation middleware for OpenTelemetry, which matches the new middleware module and documentation.

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@yordis
yordis marked this pull request as ready for review January 1, 2026 02:24
@yordis
yordis force-pushed the otel-middleware branch 4 times, most recently from a400ee9 to 8240051 Compare January 1, 2026 04:31

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (1)
test/opentelemetry/trace_context_propagator_test.exs (1)

14-26: Consider case-insensitive hex matching in W3C format validation.

The regex pattern uses [a-f0-9] which only matches lowercase hex digits. The W3C Trace Context specification allows both uppercase and lowercase hex characters in traceparent.

🔎 Proposed fix for case-insensitive matching
-        assert Regex.match?(~r/^00-[a-f0-9]{32}-[a-f0-9]{16}-[a-f0-9]{2}$/, traceparent)
+        assert Regex.match?(~r/^00-[a-fA-F0-9]{32}-[a-fA-F0-9]{16}-[a-fA-F0-9]{2}$/i, traceparent)
📜 Review details

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 852e384 and a400ee9.

⛔ Files ignored due to path filters (1)
  • mix.lock is excluded by !**/*.lock
📒 Files selected for processing (5)
  • guides/explanations/fork-differences.md
  • lib/commanded/middleware/trace_context_propagator.ex
  • mix.exs
  • test/opentelemetry/trace_context_propagator_test.exs
  • test/support/opentelemetry_case.ex
🚧 Files skipped from review as they are similar to previous changes (2)
  • mix.exs
  • test/support/opentelemetry_case.ex
🧰 Additional context used
🧬 Code graph analysis (1)
test/opentelemetry/trace_context_propagator_test.exs (1)
lib/commanded/middleware/trace_context_propagator.ex (1)
  • before_dispatch (45-55)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Quality Assurance (1.18.x, 27)
🔇 Additional comments (8)
lib/commanded/middleware/trace_context_propagator.ex (4)

1-1: Conditional compilation approach is appropriate for optional dependencies.

The compile-time check ensures the module is only defined when the OpenTelemetry propagator is available. Users who configure this middleware without installing opentelemetry_api will encounter a clear module-not-found error, which is acceptable for explicit opt-in features.


57-60: LGTM!

The helper functions correctly handle the return values from List.keyfind/3, cleanly separating the nil case (key not found) from the tuple case (key found with value).


62-64: LGTM!

The passthrough implementations are appropriate since the middleware only needs to capture trace context during before_dispatch/1. No additional work is required after dispatch or on failure.


45-55: No action needed. The implementation correctly uses the OpenTelemetry API. The inject/1 function with an empty list is the correct API for opentelemetry_api version 1.0.0, and the returned headers use string keys for "traceparent" and "tracestate" as expected. The maybe_assign/3 helper properly handles both nil results (when headers are not found) and {key, value} tuples from List.keyfind/3. Existing tests confirm this works correctly.

test/opentelemetry/trace_context_propagator_test.exs (3)

1-11: LGTM!

The test setup is appropriate. Using async: false is necessary because OpenTelemetry's tracer context is global state that cannot be safely shared across concurrent tests.


28-55: LGTM!

The tests comprehensively cover the middleware behavior:

  • Correctly verifies no traceparent when no active span
  • Validates existing metadata preservation
  • Confirms empty tracestate is not added unnecessarily

58-72: LGTM!

The tests correctly verify that after_dispatch/1 and after_failure/1 return the pipeline unchanged, confirming the passthrough behavior.

guides/explanations/fork-differences.md (1)

150-173: LGTM!

The documentation is comprehensive and well-structured. It clearly explains:

  • What the feature does
  • How to use it (with code example)
  • The benefits for distributed tracing
  • That it's non-invasive and only activates when spans are present

The format is consistent with other feature documentation in this guide.

Comment thread lib/commanded/middleware/trace_context_propagator.ex
Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>
@yordis
yordis merged commit b6c3e0b into main Jan 1, 2026
5 checks passed
@yordis
yordis deleted the otel-middleware branch January 1, 2026 04:52
@sht-bot sht-bot mentioned this pull request Jan 1, 2026
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