feat: add an opt-in OpenTelemetry metrics pipeline - #265
Merged
Merged
Conversation
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #179.
OpenTelemetry defines three signals and this library shipped one. No
MeterProviderwasconstructed anywhere, so the metrics signal was absent, and three integrations that accept a meter
provider were being handed nothing:
opentelemetry-instrumentation-asgi,-fastapi, andfaststream's telemetry middleware, whose protocol at
faststream_bootstrapper.py:40alreadydeclared
meter_providerwhile the call site passedtracer_provideralone. Those integrationsbuilt their duration histograms against the API's no-op provider and the data went nowhere.
Opt-in, through its own field
opentelemetry_metrics_endpointturns the signal on. Set it andbootstrap()builds aMeterProviderwith aPeriodicExportingMetricReaderover the OTLP metric exporter, sharing theresource the tracer provider already gets, and installs it. Leave it unset and no meter provider is
constructed at all.
Its own field rather than riding on
opentelemetry_endpoint, which is the decision #179 calledblocked. Reusing the trace endpoint would start exporting metrics for every existing user on
upgrade, with request metrics then counted twice wherever the Prometheus instrument is also on.
Opt-in matches how this repo has handled new signals twice recently (#241, #243) and keeps the
cheap direction open: opt-in to default-on later is easy, the reverse is breaking.
docs/adr/getsnothing, because nothing here is hard to reverse.
opentelemetry_exporter_protocolandopentelemetry_insecureare shared with traces rather thanduplicated. The export interval stays the SDK's, overridable with
OTEL_METRIC_EXPORT_INTERVAL,following ADR-0008's line that a knob the SDK already reads from the environment does not need a
field.
is_configurednow accepts a metrics-only config, since metrics are the same concern and askingonly for them is asking for the instrument. Teardown shuts the meter provider down through the
existing error collector, and the missing-exporter warning has a metrics twin naming
[otl]or[otl-http].The #227 lesson, carried over
set_meter_provideris set-once exactly likeset_tracer_provider, so this PR would have shippeda second silent orphan: a configured exporter, a live export thread, and nothing feeding it. It
warns the same way, and the conftest fixture from #264 now resets both globals. The meter
provider's pair lives in
opentelemetry.metrics._internal, one module below the public re-export.Two changes beyond the strict ask
opentelemetry_endpointalone would mean a remote insecure metrics endpoint warned aboutnothing, a gap this PR would have introduced. Its wording moves from "sending traces
unencrypted" to "sending telemetry unencrypted", which is now the accurate word. No test
asserted the old text; all three match on
unencrypted.floor_smoke.pysets the metrics endpoint on all four otel targets, so the 25 floors legsexercise
MeterProvider,PeriodicExportingMetricReaderand both OTLP metric exporters at thedeclared floor instead of leaving the new surface untested there. It costs a second exporter
retry loop per leg at shutdown, on top of the one traces already pays.
Tests
Written failing first, red for the right reason each time. On the instrument: the meter provider is
installed and carries the resource, the http protocol picks the http exporter, an unset endpoint
installs nothing, teardown shuts it down, each protocol warns when its exporter package is absent,
a metrics-only config is configured, and the lost-race warning fires with caller attribution. One
binding test per framework pins that the meter provider actually reaches the integration.
Three existing Litestar tests construct
LitestarOpenTelemetryInstrumentationMiddlewaredirectlyand now pass a meter provider. The parameter is required, like
tracer_provider; the class is notexported from
lite_bootstrap/__init__.pyand appears in no docs.Verified
eof-fixer --check,ruff format --check,ruff check --no-fix,ty checkclean.345 passed under
-p no:randomlyand under random order. Coverage 100.00%, gate satisfied.mkdocs build --strictpasses with the new Metrics section indocs/introduction/configuration.md.Floors: ran the
freetarget locally at Python 3.10 against opentelemetry-api/-sdk 1.28.0 andopentelemetry-exporter-otlp-proto-grpc 1.28.0, with the metrics endpoint set:
floor smoke OK: free on 3.10.21.