Skip to content

Default opentelemetry_exclude_spans to ["receive", "send"] and support it on FastMCP - #364

Open
lesnik512 wants to merge 1 commit into
mainfrom
otel-exclude-spans-default
Open

lesnik512 wants to merge 1 commit into
mainfrom
otel-exclude-spans-default

Conversation

@lesnik512

Copy link
Copy Markdown
Member

Closes #309.

On FastAPI, Litestar and FastMCP, opentelemetry_exclude_spans now defaults to ["receive", "send"], so each request records only its server span. Before this change, the OpenTelemetry ASGI middleware also opened one span per receive and per send event. It opened them with start_as_current_span even when the trace was unsampled. FastMcpConfig gains the field, and it is passed to OpenTelemetryMiddleware.

Changes

  • OpenTelemetryAsgiConfig in opentelemetry_instrument.py subclasses OpenTelemetryConfig and declares opentelemetry_exclude_spans once. FastAPIConfig, LitestarConfig and FastMcpConfig inherit it in place of OpenTelemetryConfig, the same way SentryLeanCaptureConfig is shared. Free and FastStream keep OpenTelemetryConfig and get no field. The issue left this mixin optional.
  • FastMcpOpenTelemetryInstrument._instrument_http_app passes exclude_spans. The middleware has accepted it since the 0.49b0 floor (opentelemetry/instrumentation/asgi/__init__.py:551 at contrib tag v0.49b0, which I checked).
  • The "only the FastAPI and Litestar instrumentors take exclude_spans" comment is gone along with the per-config fields.

Tests

Written first. These failed on main:

  • test_fastapi_opentelemetry_exclude_spans_defaults_to_dropping_the_event_spans (the flipped default test)
  • test_litestar_otel_exclude_spans_defaults_to_only_the_server_span: one request now gives exactly one span, of kind SERVER. This covers the issue's "one server span" check.
  • test_fastmcp_otel_exclude_spans_defaults_to_only_the_server_span and test_fastmcp_otel_exclude_spans_emptied_records_the_event_spans, which send a health-check request through http_app().

The existing explicit-value tests on FastAPI and Litestar now set [] and check that the event spans come back.

The full suite passes, 554 tests at 100% coverage. just lint (including ty), just adr-check and just docs-build pass too. I didn't run the floors locally. The only new call is exclude_spans on OpenTelemetryMiddleware, which has been in the floor's signature since 0.49b0, so I left the floors to CI.

Measurement

In-process on an M2 Mac at 100% sampling (CPython 3.14.7, opentelemetry-sdk 1.45.1, instrumentation-asgi 0.66b1, fastapi 0.162.0, litestar 2.25.0, fastmcp 4.1.4). Figures are µs over the bare app:

suite new default (otel) opentelemetry_exclude_spans=[] (otel_all_spans) saved
FastAPI, per request +91.8 +127.8 36.0
Litestar, per request +79.3 +116.1 36.8
FastMCP, per tools/call +175.4 +273.8 98.4

FastMCP's rounds differed by up to 9%, and FastAPI's otel row by 17%. These agree with the issue's Linux numbers: 46 µs on FastAPI, 41 to 53 µs on Litestar and 91 µs for the FastMCP prototype. otel_all_spans is a new scenario in the three suites, with ALL_SPANS in common.py. The existing *_excl scenarios now have the same config as the default, so I left them alone.

Docs

  • configuration.md: the paragraph now covers FastAPI, Litestar and FastMCP and gives the new default, its cost and how to get the spans back.
  • performance.md: the table row is marked as the default since 2.0. The "savings applied for you" paragraph now has six savings, and the unsampled-floor note says the spans are excluded by default.
  • benchmarks/README.md:
    • §4a describes 1.x and 2.0 and carries the rerun table.
    • §6's tuned config drops the setting, and the text below it says this is now the default.
    • §4d, §8b and §8e point out that their OpenTelemetry rows still record the event spans.

Departure from the issue

The issue suggests shipping the field on FastMCP with an empty default in a 1.x minor, which would make this PR only the flip. I did both here because main is on 2.0. If you want the field in a 1.x release too, it would need a separate backport.

Breaking changes

Traces from FastAPI, Litestar and FastMCP services no longer have the per-message receive and send spans. Set opentelemetry_exclude_spans=[] to get them back.

This branch has not been deployed

No deployments
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.

Default opentelemetry_exclude_spans to ["receive", "send"] and support it on FastMCP

1 participant