SpanRecord

@Serializable
data class SpanRecord(val traceId: ByteString, val spanId: ByteString, val parentSpanId: ByteString?, val name: String, val kind: SpanKind, val startEpochNanos: Long, val endEpochNanos: Long, val attributes: Map<String, String> = emptyMap(), val status: SpanStatus = SpanStatus.Unset, val causalStamp: CausalStamp? = null)

A completed span record, shaped to round-trip through OTLP.

This is kuilt's KMP-native representation of an OpenTelemetry span. It is intentionally minimal: the fields map 1-to-1 to OTLP's Span proto message so a WarpOtlpBridge can serialize them directly with no further transformation.

traceId and spanId carry raw bytes matching the OTLP protobuf wire format:

  • traceId — 16 bytes (128-bit), matches OTLP proto3 bytes trace_id.

  • spanId — 8 bytes (64-bit), matches OTLP proto3 bytes span_id.

  • parentSpanId — 8 bytes for child spans; null for root spans.

ByteString is used rather than ByteArray because the ORSet inside WarpSpanExporter keys by element equality — ByteString provides content-based equals/hashCode, so re-exporting the same span is always a no-op set union.

SpanRecord is the element type stored in the ORSet inside WarpSpanExporter: keyed by spanId, so re-exporting the same span is a no-op (set union is idempotent).

Honest limits

  • Clock skew. startEpochNanos and endEpochNanos are the producer's local clock. Long-offline devices may produce timestamps far in the past. A hybrid logical clock (HLC) offset could be estimated on reconnect, but is not yet implemented — this is filed as a follow-up.

  • Late traces. Spans that straddle an offline and an online producer only assemble into a complete trace when the offline half syncs. OTLP collectors accept late spans within an assembly window (typically 10 min–1 hr); spans that miss the window are indexed as orphaned roots.

Constructors

Link copied to clipboard
constructor(traceId: ByteString, spanId: ByteString, parentSpanId: ByteString?, name: String, kind: SpanKind, startEpochNanos: Long, endEpochNanos: Long, attributes: Map<String, String> = emptyMap(), status: SpanStatus = SpanStatus.Unset, causalStamp: CausalStamp? = null)

Properties

Link copied to clipboard

Key/value string attributes.

Link copied to clipboard

Optional happens-before position for causal-link inference.

Link copied to clipboard

Epoch-nanosecond end timestamp from the producer's local clock.

Link copied to clipboard

Span kind: SERVER, CLIENT, PRODUCER, CONSUMER, INTERNAL.

Link copied to clipboard

Human-readable operation name.

Link copied to clipboard
@Serializable(with = ByteStringSerializer::class)
val parentSpanId: ByteString?

Parent span id (8 bytes), or null for root spans.

Link copied to clipboard
@Serializable(with = ByteStringSerializer::class)
val spanId: ByteString

64-bit span id as raw bytes (8 bytes). Matches OTLP proto3 bytes span_id.

Link copied to clipboard

Epoch-nanosecond start timestamp from the producer's local clock.

Link copied to clipboard

Span status.

Link copied to clipboard
@Serializable(with = ByteStringSerializer::class)
val traceId: ByteString

128-bit trace id as raw bytes (16 bytes). Matches OTLP proto3 bytes trace_id.