Skip to content

fix(mobile): explicitly inject traceparent for mobile↔API correlation#173

Merged
davidortinau merged 1 commit into
mainfrom
squad/mobile-traceparent-inject
Apr 22, 2026
Merged

fix(mobile): explicitly inject traceparent for mobile↔API correlation#173
davidortinau merged 1 commit into
mainfrom
squad/mobile-traceparent-inject

Conversation

@davidortinau

Copy link
Copy Markdown
Owner

Summary

Explicitly inject W3C traceparent into outbound HttpClient requests from mobile so the API can correlate its spans against ours.

Why

PR #172 added ApiActivityHandler which creates an Activity per request (so App Insights dependencies now carry operation_Id). But the correlation join still returned zero rows:

requests
| where cloud_RoleName endswith "SentenceStudio.Api"
| join kind=inner (dependencies | where cloud_RoleName == "SentenceStudio.Mobile") on operation_Id

Evidence after #172:

  • Q1 (mobile deps with operation_Id): 44 rows
  • Q2 (correlation join): 0 rows

Diagnosis: HttpClient's built-in DiagnosticsHandler only injects traceparent automatically when an ActivityListener is attached to "System.Net.Http". On MAUI that listener never attaches because OpenTelemetry's TelemetryHostedService — which materializes the TracerProvider and its listeners — depends on IHostedService, and MauiApp doesn't run hosted services. Tracked in #171.

What changed

In ApiActivityHandler.SendAsync, after the activity null-check and tag-setting, call DistributedContextPropagator.Current.Inject(...) on the request headers. Guarded by !request.Headers.Contains("traceparent") so deliberate upstream callers and resilience retries don't produce duplicate headers.

Why this is the right scope

Verification

  1. Build Mac Catalyst Debug + Release ✅ (compile clean; pre-existing universal-bundle plist merge issue is unrelated).
  2. Publish to DX24 via iOS Release.
  3. Re-run Q2 correlation join ~2 min after generating traffic. Expected: > 0 rows.

Refs: #165 #166 #172 #171

…tion

PR #172 got mobile HttpClient dependency spans emitting with operation_Id,
but the correlation join against API requests still returned zero rows:
the API saw every incoming request without a traceparent header and started
a fresh operation_Id.

Root cause: HttpClient's built-in DiagnosticsHandler only injects traceparent
automatically when an OTel-style ActivityListener is attached to
"System.Net.Http". On MAUI the listener never attaches because OpenTelemetry's
TelemetryHostedService — which wires listeners to the TracerProvider — relies
on IHostedService, and MauiApp doesn't run hosted services (issue #171).

Fix: have ApiActivityHandler explicitly call
DistributedContextPropagator.Current.Inject(...) on the outbound request
headers after starting its Activity. Guards against double-injection if a
caller or a resilience retry already set traceparent.

This is the user-space workaround to #171. Framework fix is still desirable
but now lower priority.

Verification plan: re-run the App Insights correlation join; expect
requests | join dependencies on operation_Id to return > 0 rows for the
mobile role name.

Refs: #165 #166 #172 #171
@davidortinau davidortinau merged commit 48c3fd9 into main Apr 22, 2026
2 of 6 checks passed
@davidortinau davidortinau deleted the squad/mobile-traceparent-inject branch April 22, 2026 15:28
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