An executable CMake lab showing how a lossy telemetry projection can erase an OpenTelemetry instrumentation scope, merge incompatible metric identities, and fabricate a latency improvement during a library rollout.
The default scenario is deliberately simple:
- Instrumentation
1.9.0reports a real checkout latency as420 ms. - Instrumentation
2.0.0reports the same latency as0.420 s. - Both versions are present during a 50/50 rolling upgrade.
- The alert threshold is 300 ms.
Native OTLP retains scope version and metric unit, so both streams normalize to 420 ms and the alert fires. A flat exporter that keeps only service and metric name averages the raw numeric tokens as if both were milliseconds:
(5,000 × 420 + 5,000 × 0.420) / 10,000 = 210.21 ms
The dashboard reports a 49.95% improvement that never happened and the alert
stops firing. A last-write-wins backend can report 0.420 ms, a 1000× error.
This is not another service-version or schema-drift lab. The application, resource, and real measurement remain constant. The failure is specifically the removal of metric identity carried by instrumentation Scope and unit.
OpenTelemetry defines an instrumentation scope as the
(name, version, schema_url, attributes) tuple identifying the logical
software unit that emits telemetry.
OTLP metric streams are identified by:
- Resource
- Instrumentation Scope
- Metric name
- Point type and intrinsic properties
- Unit
Flattening OTLP into a format without a native scope is safe only if the identity is bridged into queryable dimensions. This lab preserves:
otel.scope.name
otel.scope.version
metric.unit
otel.scope.schema_url
With those dimensions, telemetry.sh can separate rollout cohorts and normalize their units before aggregation.
Requirements: Node.js 20+ and CMake 3.20+.
npm ci
npm startOpen http://localhost:8080.
Or run the container:
docker compose up --buildcmake \
-DROLLOUT_PERCENT=50 \
-DREAL_LATENCY_MS=420 \
-DTHRESHOLD_MS=300 \
-DSAMPLE_COUNT=10000 \
-P model/simulate.cmakeThe Node adapter invokes that CMake script for every simulation:
npm run simulate
npm run simulate -- --rollout-percent 90 --real-latency-ms 750
npm run telemetryHTTP endpoints expose the same controls:
curl 'http://localhost:8080/api/simulate?rolloutPercent=50'
curl 'http://localhost:8080/api/telemetry?rolloutPercent=50'The OTLP-shaped response contains:
- Two native
ScopeMetricsgroups with the same metric name but distinct scope versions, schema URLs, and units. - Diagnostic metrics comparing observed latency, visible scope versions, and alert state across four projection strategies.
- Correlated logs and traces explaining where interpretation becomes impossible.
Every response includes the exact CMake runtime version, a SHA-256 digest of
model/simulate.cmake, and the model path. The Node server does not duplicate
the simulation arithmetic.
npm run checkTests cover partial, zero, and full rollouts; unit normalization; the false alert result; native OTLP scope identity; runtime proof; and all HTTP endpoints. CI also builds the clean Linux container image.
- OpenTelemetry instrumentation scope
- OpenTelemetry metrics data model
- OpenTelemetry naming and
otel.scope.name - CMake language documentation
MIT