Skip to content

MAUI OTel: force TracerProvider materialization since IHostedService doesn't run #171

@davidortinau

Description

@davidortinau

Summary

MAUI's MauiApp implements IHostApplicationBuilder but does not run IHostedService instances (no IHost.StartAsync loop). OpenTelemetry.Extensions.Hosting registers a TelemetryHostedService whose StartAsync is what materializes the TracerProvider, attaches its ActivityListeners, and begins exporting. On MAUI, that service never runs — so:

  • Logs still work (they hook ILoggerFactory synchronously during AddOpenTelemetry()).
  • Auto-instrumentation (AddHttpClientInstrumentation) does not — no listener → no spans → no traceparent header injection → API sees every request as a root span and correlation joins return zero rows in Application Insights.

Evidence from this session

  • OpenTelemetry.Instrumentation.Http 1.15.0 is present, .AddHttpClientInstrumentation() has been on the TracerProvider since commit 216a2da1 (March 4).
  • Ran a trim-disabled (<MtouchLink>None</MtouchLink>) Release build on DX24; bundle 136 MB / 333 DLLs — trimming disproven.
  • KQL showed 127 mobile traces with empty operation_Id on every entry → no ambient Activity ever existed on the device.
  • Existing OpenTelemetryInitializer : IMauiInitializeService used nullable services.GetService<TracerProvider>() — may have silently returned null.

Workaround shipped

PR #XXX (replace) adds an ApiActivityHandler DelegatingHandler and a dedicated ActivitySource (SentenceStudio.Mobile.HttpClient) explicitly registered with the TracerProvider. It also hardens OpenTelemetryInitializer to use GetRequiredService<TracerProvider>() to force materialization. This makes correlation work today but does not address the root cause.

Root-cause fix (this issue)

Decide between:

  1. Explicitly call TelemetryHostedService.StartAsync from OpenTelemetryInitializer — get every auto-instrumentation listener attached for free, no per-call handler needed.
  2. Build TracerProvider directly via Sdk.CreateTracerProviderBuilder() instead of going through services.AddOpenTelemetry().WithTracing(...), bypassing the hosted-service dependency entirely.
  3. Upstream fix — ask the OpenTelemetry maintainers for a non-IHostedService bootstrap path for IHostApplicationBuilder implementations that don't run hosted services (MAUI, some WPF/WinForms IHost scenarios).

If option 1 or 2 lands, the ApiActivityHandler can stay (it's still a correct Client span for each API call) and the AddHttpClientInstrumentation() spans become additive. No code needs to be reverted.

Acceptance criteria

  • On a clean install of the mobile app, a single API call produces:
    • At least one dependencies row in App Insights from the mobile side.
    • A matching requests row on the server with equal operation_Id to that dependency.
    • Server operation_Id != operation_ParentId (i.e., mobile traceparent actually propagated).
  • Works without the manual ApiActivityHandler being the only source.

Links

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions