feat(api): export metrics over OTLP beside traces#227
Merged
Conversation
added 2 commits
July 25, 2026 20:14
- WithMetrics on the existing OTLP gate: ASP.NET Core request metrics (http.server.request.duration, Kestrel), .NET runtime (GC/threads/ exceptions), Npgsql and EF Core meters. Endpoint unset = no exporter, unchanged behavior. - OtlpOptions.ResolveMetricsEndpoint: /v1/metrics appended for http/protobuf via the same UriBuilder path as traces (shared ResolveSignalEndpoint). - Fake collector captures per-signal paths — traces and metrics arrive as separate POSTs in nondeterministic order; listener faults still surface. - Boot line now states both signal endpoints; .env.example documents the meter set and that request-duration histograms include health probes (metrics side has no per-request filter; aggregated + low-cardinality). 5 new tests; suite 732 green, integration run twice.
Review: codex + pi + 2 Claude agents. Accepted:
- Cross-signal endpoint foot-gun (agent, Important): a signal-suffixed
Otlp:Endpoint ('.../v1/traces') would send metrics to /v1/traces/v1/metrics
— silent 404 at the collector. http/protobuf endpoints must now be the BASE
url; any known signal suffix fails at boot with the pointed fix. This
supersedes #226's append-once tolerance (with two signals on one endpoint a
suffixed URL can never be right).
- Smoke-test depth (codex): driver is now a login POST (real DB round-trip so
Npgsql/EF instruments record) and the payload must carry one representative
instrument per required source — http.server.request.duration,
dotnet.gc.collections, db.client.operation.duration,
microsoft.entityframeworkcore. Names taken from a real export dump.
- DRY (pi + cavecrew, converging): one ConfigureResource on the OTel builder,
one exporter recipe closure, cached otlpMetricsEndpoint, uniform guards.
- Docs truth (agent): AddAspNetCoreInstrumentation subscribes ALL built-in
ASP.NET Core meters (rate limiting, auth/Identity, memory pool included —
this app uses the lot); .env.example and the code comment now say so, plus
a note on temporality/interval env overrides for delta-preferring vendors.
Rejected: swapping OpenTelemetry.Instrumentation.Runtime for a bare
AddMeter("System.Runtime") — the package IS the framework facility and
keeps TFM differences its problem.
Resolution facts reworked to assert both signals per endpoint (symmetric
coverage); suite 734 green, integration run twice.
Owner
Author
Review round (repo policy: codex + 2 Claude agents + pi)Accepted → fixed in 3ab4a56:
Rejected: swapping Reviewer verification highlights (agent 1 checked shipped assemblies, not docs): Npgsql 10.0.3 meter name Suite after fixes: 734 green, integration run twice, build clean. |
This was referenced Jul 26, 2026
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 #215. Builds on #226 (merged): same
Otlp:Endpointgate, same eager validation, same fake-collector test rig.What
.WithMetrics()beside the existing tracing: ASP.NET Core request metrics (http.server.request.duration, Kestrel), .NET runtime (GC, thread pool, exceptions),NpgsqlandMicrosoft.EntityFrameworkCoremeters. New package:OpenTelemetry.Instrumentation.Runtime; lock files synced.OtlpOptions.ResolveMetricsEndpoint—/v1/metricsappended for http/protobuf through the same UriBuilder path as traces (sharedResolveSignalEndpoint; query strings survive, no double-append).deploy/.env.exampledocuments the meter set (issue AC) and notes that request-duration histograms include health probes — the metrics side has no per-request filter; aggregated and low-cardinality, unlike the per-probe spans feat(api): activate the telemetry pipeline — OTLP export, request logs, TraceId correlation #226 filters out.Decision recorded in #215: OTLP push, no Prometheus scrape endpoint (single container behind Cloudflare — a scrape port would need its own auth story).
Tests
5 new: 4 endpoint-resolution facts (append-once, vendor base path, grpc untouched) + a metrics export smoke test (flush forced by host disposal, payload must carry the
Cluckwork.Apiservice name). Traces smoke test re-verified through the collector rewrite.Suite: 732 green, integration run twice, build clean (warnings-as-errors).