ANW-42 Telemetry: take export config from OTEL_ environment variables only

Delete the uptrace DSN parser and the {endpoint}/v1/* concatenation that
produced the dead export, and build the OTLP exporters with no endpoint,
headers, or protocol so the SDK reads OTEL_EXPORTER_OTLP_* itself.

The SDK concatenates as naively as we did: measured against a local sink,
a ?query base sends POST /?query/v1/metrics and a #fragment base sends
POST /. So one check stays -- a query or fragment on
OTEL_EXPORTER_OTLP_ENDPOINT fails at startup. Per-signal variables are
used verbatim and need none.

A protocol variable is the second startup check. The exporter picks its
transport at build time and this binary ships OTLP/HTTP alone, so
OTEL_EXPORTER_OTLP_PROTOCOL=grpc kept exporting over HTTP with nothing in
the log -- the same silence this change removes.

service.name stays a default rather than policy: an attribute set on the
resource builder wins over the SDK detectors that read OTEL_SERVICE_NAME
and OTEL_RESOURCE_ATTRIBUTES, so anwesen supplies its own only for keys
the environment leaves alone.

Telemetry-off is our own check on the endpoint variables: with none set
the exporter would still build and aim at the SDK default localhost:4318.

--uptrace-dsn, --otlp-endpoint, and --otlp-header stay parsed but hidden,
so a deployment upgrading with them set fails naming the OTEL_
replacement instead of going quiet.

Assumed hidden clap stubs are the right migration shape; clap rejecting
the flags as unknown would say nothing about the replacement. Flag if a
plain unknown-argument error is wanted instead.

Assumed rejecting http/json alongside grpc is right: neither has a
transport in this build. Flag if a build with both features is wanted
instead.
This commit is contained in:
Andreas Brenner 2026-07-26 23:44:51 +03:00
parent 8894ea0c7b
commit dc113b8249
5 changed files with 563 additions and 227 deletions

View file

@ -819,18 +819,23 @@ mod tests {
}
/// With telemetry installed, a normal request is answered byte-for-byte
/// as without it. The exporter points at an unreachable local port, so
/// export fails instantly in the background and never touches the
/// response path.
/// as without it. The test process sets no `OTEL_EXPORTER_OTLP_*`
/// variables, so the exporter aims at the SDK default and fails in the
/// background without ever touching the response path.
#[tokio::test]
async fn telemetry_layer_does_not_alter_responses() {
use crate::telemetry::{self, RawTelemetryArgs, TelemetryConfig};
use crate::telemetry::{self, OtelEnv, RawTelemetryArgs, TelemetryConfig};
let cfg = TelemetryConfig::resolve(RawTelemetryArgs {
otlp_endpoint: Some("http://127.0.0.1:9".into()),
slow_request_ms: 500,
..Default::default()
})
let cfg = TelemetryConfig::resolve(
&RawTelemetryArgs {
slow_request_ms: 500,
..Default::default()
},
OtelEnv {
endpoint: Some("http://127.0.0.1:9".into()),
..OtelEnv::default()
},
)
.unwrap()
.expect("telemetry on");
let tel = Arc::new(telemetry::init(cfg).expect("telemetry init"));