Trace
This file tracks compliance for the OpenTelemetry trace specification in this repository.
Scope
- This repository implements the SDK. The Trace API types live in the external
otel4s-core-*modules. - Trace API-specific specs (e.g.
trace/api.md,trace/exceptions.md) are tracked as external dependencies here.
Module mapping
- SDK core: trace
- SDK exporters: trace
- Context propagation: propagation
- Contrib (non-core): xray, xray-propagator
trace/sdk.md checklist
| Area | Requirement | Status | Evidence | Notes |
|---|---|---|---|---|
| TracerProvider | Builder supports id generator, resource, span limits, sampler, propagators, processors | Compliant | SdkTracerProvider.scala | |
| TracerProvider | Default config (random ids, default resource, default span limits, parent-based always-on sampler) | Compliant | SdkTracerProvider.scala | |
| TracerProvider | Shutdown + ForceFlush on provider (invoke processors) | Partial | TracerProviderAutoConfigure.scala, BatchSpanProcessor.scala | Processor lifecycles are Resource-managed; no explicit shutdown/forceFlush API on provider |
| Span limits | Span limits type + builder with defaults | Compliant | SpanLimits.scala, SpanLimits.scala, SpanLimits.scala | Span limits type and builder defaults are implemented with spec-aligned default values. |
| Span limits | Env/config auto-config for span limits | Compliant | SpanLimitsAutoConfigure.scala, AttributeLimitsConfigurer.scala, SpanLimitsAutoConfigureSuite.scala | Span-specific attribute limits are supported and override global OTEL_ATTRIBUTE_*; global limits are used as fallback when span-specific values are not set. |
| Span limits | Logging when limits drop data | Not Implemented | LimitedData.scala | No once-per-span log when attributes/events/links are dropped |
| Id generator | Default random ids | Compliant | SdkTracerProvider.scala, IdGenerator.scala | Default builder wires IdGenerator.random; random generator produces non-zero span/trace IDs and marks generated root contexts as random-trace-id. |
| Id generator | Custom IdGenerator support | Compliant | SdkTracerProvider.scala | |
| Id generator | IdGenerator randomness extension controls random flag | Compliant | IdGenerator.scala, SdkSpanBuilder.scala, AwsXRayIdGenerator.scala | Root span contexts set the random-trace-id flag based on IdGenerator.generatesRandomTraceId; child spans preserve the parent random bit. |
| Sampling | Sampler interface + parent-based + trace-id-ratio | Partial | Sampler.scala, ParentBasedSampler.scala, TraceIdRatioBasedSampler.scala | No ProbabilitySampler, AlwaysRecord, CompositeSampler; no warnings when TraceIdRatioBased used as child sampler |
| Span processor | SpanProcessor interface with onStart/onEnd + forceFlush | Compliant | SpanProcessor.scala | |
| Span processor | OnEnding hook | Partial | SpanProcessor.scala | onEnd exists with SpanData snapshot; no distinct pre-end OnEnding hook |
| Span processor | Shutdown support | Partial | BatchSpanProcessor.scala, BatchSpanProcessor.scala | Batch processor finalization invokes serialized forceFlush; the processor API has no explicit shutdown operation. |
| Span processor | Simple + Batch processors | Compliant | SimpleSpanProcessor.scala, BatchSpanProcessor.scala, BatchSpanProcessor.scala, BatchSpanProcessorSuite.scala | Both required processors export ended spans; tests cover prompt full and consecutive batches plus serialization when forceFlush overlaps a worker export. |
| Span exporter | SpanExporter interface + no-op + composite | Partial | SpanExporter.scala, SpanExporter.scala, SpanExporter.scala | Interface/noop/composite are implemented; flush serves force-flush semantics, but explicit shutdown is not part of the exporter interface. |
| Span exporter | Shutdown + ForceFlush methods | Partial | SpanExporter.scala, SpanExporter.scala, OtlpSpanExporterAutoConfigure.scala | ForceFlush semantics are represented by flush; lifecycle is Resource-managed in concrete exporters, but explicit shutdown is missing from the interface. |
| Span exporter | Stdout exporter | Partial | ConsoleSpanExporter.scala | Doc comment does not note format is unspecified |
| Span lifecycle | Span creation/ending via SdkSpanBuilder + SdkSpanBackend | Partial | SdkSpanBuilder.scala, SdkSpanBackend.scala | SpanId generated before ShouldSample (spec order is ShouldSample then SpanId) |
trace/tracestate-handling.md checklist
| Area | Requirement | Status | Evidence | Notes |
|---|---|---|---|---|
| TraceState propagation | W3C TraceContext encode/decode | Partial | W3CTraceContextPropagator.scala, W3CTraceContextPropagator.scala | No OpenTelemetry ot entry handling or validation (key uniqueness/length) |
| TraceState propagation | OpenTelemetry ot sub-key handling (th/rv) |
Not Implemented | W3CTraceContextPropagator.scala, W3CTraceContextPropagator.scala | No utilities to set/merge ot entry |
trace/tracestate-probability-sampling.md checklist
| Area | Requirement | Status | Evidence | Notes |
|---|---|---|---|---|
| Consistent probability sampling | TraceState update hooks in sampling results | Partial | SamplingResult.scala, SamplingResult.scala | Updater exists but no ProbabilitySampler, CompositeSampler or rv/th handling |
trace/sdk_exporters
| Area | Requirement | Status | Evidence | Notes |
|---|---|---|---|---|
| SDK Exporter | stdout.md | Partial | ConsoleSpanExporter.scala | |
| SDK Exporter | zipkin.md | Not Applicable |
trace/api.md checklist (external: otel4s-core)
| Area | Requirement | Status | Evidence | Notes |
|---|---|---|---|---|
| TracerProvider | Global default TracerProvider access | Not Implemented | TracerProvider.scala | No global/default provider API found |
| TracerProvider | Get a Tracer accepts name + version + schema_url + attributes | Partial | TracerProvider.scala, TracerBuilder.scala | Attributes parameter not supported |
| TracerProvider | Invalid name handling (empty string -> fallback + log) | Not Implemented | TracerProvider.scala | No validation/logging for empty name |
| Tracer | Enabled API | Compliant | SdkTracer.scala, SdkTracerProvider.scala | Exposes meta on tracer; SDK wires InstrumentMeta.enabled so enablement is available via metadata (meta.isEnabled). |
| SpanContext | TraceId/SpanId hex + binary access | Compliant | SpanContext.scala | traceId/spanId (bytes) and traceIdHex/spanIdHex |
| SpanContext | TraceFlags sampled + random flag exposure | Partial | TraceFlags.scala | Only sampled flag is currently exposed in the released core API. |
| TraceState | get/add/update/delete with validation + error handling | Partial | TraceState.scala | Invalid inputs are ignored (no error signaling) |
| Span | IsRecording API | Not Implemented | Span.scala | No isRecording/IsRecording method |
| Span | Creation only via Tracer; parent must be Context only | Partial | SpanBuilder.scala | Allows explicit parent SpanContext |
| Span | Wrap SpanContext into non-recording Span | Not Implemented | Span.scala | No public API to wrap SpanContext |
| Span | Set attributes / add event / add link / set status / update name / end / record exception | Compliant | Span.scala, SpanMacro.scala | Matches required operations (except IsRecording) |
| Concurrency | TracerProvider/Tracer/Span methods safe to call concurrently | Compliant | SdkTracerProvider.scala, SdkTracer.scala, SdkSpanBackend.scala, SpanStorage.scala | Implemented with Cats Effect concurrency primitives (Ref/MapRef) and immutable shared state. |
| No-SDK behavior | No-op API preserves parent SpanContext for propagation | Not Implemented | Tracer.scala, Span.scala | No public API to wrap SpanContext; Tracer.noop always uses SpanContext.invalid |
trace/api.md context interaction checklist (external: otel4s-core)
| Area | Requirement | Status | Evidence | Notes |
|---|---|---|---|---|
| Context interaction | Extract Span from Context | Partial | TraceScope.scala | TraceScope exposes current SpanContext only; no public API to extract Span |
| Context interaction | Combine Span with Context to create new Context | Partial | TraceScope.scala | childScope/withContext are internal; no explicit API to attach Span to Context |
| Implicit context | Get current span from implicit context | Partial | Tracer.scala | currentSpanContext and currentSpanOrNoop exist, but not a direct Context extraction API |
| Implicit context | Set current span into implicit context | Partial | Tracer.scala | childScope/rootScope/noopScope operate on SpanContext; no public Context-combine API |
| Context API | Generic Context storage only (no trace-specific helpers) | Not Implemented | Context.scala, Contextual.scala | No helpers to extract/attach Span or SpanContext outside trace module |
trace/exceptions.md checklist
| Area | Requirement | Status | Evidence | Notes |
|---|---|---|---|---|
| Exception event | Event name is exception |
Compliant | EventData.scala | ExceptionEventName = "exception" |
| Exception attrs | exception.type, exception.message, exception.stacktrace |
Compliant | EventData.scala, EventData.scala | Exception event population sets type and conditionally sets message and stacktrace when present. |
| RecordException API | Optional extra attributes override defaults | Compliant | EventData.scala | attributes.prependAll(exceptionAttributes) keeps user attrs last |
| Unhandled exception guidance | Record exception + set status Error on unhandled | Partial | SpanFinalizer.scala | reportAbnormal records exception + sets Error; API does not enforce “only if unhandled” |
Cross-cutting specs
- Attribute requirements are tracked in attributes.md.
- Context propagation requirements are tracked in context-propagation.md.
- Instrumentation scope requirements are tracked in instrumentation-scope.md.
- Resource requirements are tracked in resource.md.
- SDK environment-variable requirements are tracked in configuration.md.