///|
/// OpenTelemetry span kind.
///
/// Use `Server` for inbound request handlers, `Client` for outbound requests,
/// `Producer`/`Consumer` for messaging, and `Internal` for local work.
/// Spec: https://opentelemetry.io/docs/specs/otel/trace/api/#spankind
pub(all) enum SpanKind {
Internal
Client
Server
Producer
Consumer
} derive(Eq, Compare, Hash, ToJson, Debug)
///|
/// Span status code: unset, ok, or error.
/// Spec: https://opentelemetry.io/docs/specs/otel/trace/api/#set-status
pub(all) enum StatusCode {
Unset
Ok
Error
} derive(Eq, Compare, Hash, ToJson, Debug)
///|
/// Span status with a code and optional description.
///
/// Status represents the final outcome of the operation. Recording an exception
/// event does not automatically set status; call `Span::set_status()` when the
/// operation should be marked as an error.
/// Spec: https://opentelemetry.io/docs/specs/otel/trace/api/#set-status
pub struct Status {
code : StatusCode
description : String?
} derive(Eq, ToJson, Debug)
///|
/// Event attached to a span builder.
///
/// Events represent timestamped facts that happened during a span, such as a
/// retry, cache miss, or exception. Use attributes for event-specific detail.
/// Spec: https://opentelemetry.io/docs/specs/otel/trace/api/#add-events
pub struct Event {
name : String
timestamp_unix_nano : Int64
attributes : Array[@common.KeyValue]
dropped_attributes_count : Int
} derive(Eq, ToJson, Debug)
///|
/// Link attached to a span builder.
///
/// Links connect this span to another span context without making that span the
/// parent. They are useful for queues, batch jobs, and fan-in/fan-out workflows.
/// Spec: https://opentelemetry.io/docs/specs/otel/trace/api/#link
pub struct Link {
span_context : @common.SpanContext
attributes : Array[@common.KeyValue]
dropped_attributes_count : Int
} derive(Eq, ToJson, Debug)
///|
/// Immutable span-construction descriptor used by `Tracer::build*()`.
///
/// Use a builder when a span needs non-default kind, explicit start time,
/// initial attributes, events, or links. For simple spans, `Tracer::start()` is
/// shorter.
/// Spec: https://opentelemetry.io/docs/specs/otel/trace/api/#span-creation
pub struct SpanBuilder {
span_kind : SpanKind?
name : String
start_time_unix_nano : Int64?
attributes : Array[@common.KeyValue]
events : Array[Event]
links : Array[Link]
} derive(Eq, ToJson, Debug)
///|
/// Public span handle.
///
/// A span represents one in-flight operation. When created from a no-op tracer,
/// the span still propagates a valid parent context but does not record data.
/// End spans once the represented operation is complete.
/// Spec: https://opentelemetry.io/docs/specs/otel/trace/api/#span
pub struct Span {
span_context_fn : () -> @common.SpanContext
context_fn : () -> @context.Context
is_recording_fn : () -> Bool
has_ended_fn : () -> Bool
add_event_fn : (StringView, Int64, ArrayView[@common.KeyValue]) -> Unit
set_attribute_fn : (@common.KeyValue) -> Unit
set_status_fn : (Status) -> Unit
update_name_fn : (StringView) -> Unit
add_link_fn : (@common.SpanContext, ArrayView[@common.KeyValue]) -> Unit
end_fn : async (Int64) -> Unit
}
///|
/// Public tracer handle.
///
/// A tracer creates spans for one instrumentation scope. Tracers are cheap
/// handles; libraries normally keep or reacquire one by instrumentation name.
/// Spec: https://opentelemetry.io/docs/specs/otel/trace/api/#tracer
pub struct Tracer {
build_with_context_fn : (SpanBuilder, @context.Context) -> Span
}
///|
/// Public tracer provider.
///
/// The default provider is no-op. Applications install SDK-backed providers
/// through the SDK facade while library code depends only on this API type.
/// Spec: https://opentelemetry.io/docs/specs/otel/trace/api/#tracerprovider
pub struct TracerProvider {
tracer_with_scope_fn : (@common.InstrumentationScope) -> Tracer
}
///|
/// Creates a span status.
/// Spec: https://opentelemetry.io/docs/specs/otel/trace/api/#set-status
pub fn Status::new(code : StatusCode, description? : String? = None) -> Status {
{ code, description }
}
///|
/// Returns the default unset status.
/// Spec: https://opentelemetry.io/docs/specs/otel/trace/api/#set-status
pub fn Status::unset() -> Status {
Status::new(Unset)
}
///|
/// Returns an ok status.
/// Spec: https://opentelemetry.io/docs/specs/otel/trace/api/#set-status
pub fn Status::ok() -> Status {
Status::new(Ok)
}
///|
/// Returns an error status with an optional description.
/// Spec: https://opentelemetry.io/docs/specs/otel/trace/api/#set-status
pub fn Status::error(description? : String? = None) -> Status {
Status::new(Error, description~)
}
///|
pub impl Default for Status with fn default() -> Status {
Status::unset()
}
///|
/// Creates one span event.
///
/// The timestamp defaults to the current Unix time in nanoseconds. Events added
/// to a no-op span are ignored.
/// Spec: https://opentelemetry.io/docs/specs/otel/trace/api/#add-events
pub fn Event::new(
name : StringView,
timestamp_unix_nano? : Int64 = @utils.now_unix_nano(),
attributes? : ArrayView[@common.KeyValue] = [],
dropped_attributes_count? : Int = 0,
) -> Event {
{
name: name.to_owned(),
timestamp_unix_nano,
attributes: attributes.to_owned(),
dropped_attributes_count,
}
}
///|
/// Creates one span link.
///
/// Invalid linked span contexts are ignored later when the span is built. Links
/// do not affect parent/child relationships.
/// Spec: https://opentelemetry.io/docs/specs/otel/trace/api/#link
pub fn Link::new(
span_context : @common.SpanContext,
attributes? : ArrayView[@common.KeyValue] = [],
dropped_attributes_count? : Int = 0,
) -> Link {
{ span_context, attributes: attributes.to_owned(), dropped_attributes_count }
}
///|
/// Starts building a span with the given operation name.
///
/// Names should be low-cardinality and describe the operation shape, such as
/// `http.request`, `db.query`, or `queue.publish`, not a user-specific value.
/// Spec: https://opentelemetry.io/docs/specs/otel/trace/api/#span-creation
pub fn SpanBuilder::from_name(name : StringView) -> SpanBuilder {
{
span_kind: None,
name: name.to_owned(),
start_time_unix_nano: None,
attributes: [],
events: [],
links: [],
}
}
///|
/// Returns a copy of the builder with the given span kind.
/// Spec: https://opentelemetry.io/docs/specs/otel/trace/api/#span-creation
pub fn SpanBuilder::with_kind(
self : SpanBuilder,
span_kind : SpanKind,
) -> SpanBuilder {
{ ..self, span_kind: Some(span_kind) }
}
///|
/// Returns a copy of the builder with an explicit start timestamp.
/// Spec: https://opentelemetry.io/docs/specs/otel/trace/api/#span-creation
pub fn SpanBuilder::with_start_time(
self : SpanBuilder,
start_time_unix_nano : Int64,
) -> SpanBuilder {
{ ..self, start_time_unix_nano: Some(start_time_unix_nano) }
}
///|
/// Returns a copy of the builder with the given attribute list.
///
/// This replaces previously stored builder attributes.
/// Spec: https://opentelemetry.io/docs/specs/otel/trace/api/#span-creation
pub fn SpanBuilder::with_attributes(
self : SpanBuilder,
attributes : ArrayView[@common.KeyValue],
) -> SpanBuilder {
{ ..self, attributes: attributes.to_owned() }
}
///|
/// Returns a copy of the builder with the given event list.
///
/// This replaces previously stored builder events.
/// Spec: https://opentelemetry.io/docs/specs/otel/trace/api/#span-creation
pub fn SpanBuilder::with_events(
self : SpanBuilder,
events : ArrayView[Event],
) -> SpanBuilder {
{ ..self, events: events.to_owned() }
}
///|
/// Returns a copy of the builder with the given link list.
///
/// This replaces previously stored builder links.
/// Spec: https://opentelemetry.io/docs/specs/otel/trace/api/#specifying-links
pub fn SpanBuilder::with_links(
self : SpanBuilder,
links : ArrayView[Link],
) -> SpanBuilder {
{ ..self, links: links.to_owned() }
}
///|
fn propagated_context(
parent_context : @context.Context,
span_context : @common.SpanContext,
) -> @context.Context {
parent_context.with_span_context(span_context)
}
///|
fn build_noop_span(
builder : SpanBuilder,
parent_context : @context.Context,
) -> Span {
ignore(builder)
let propagated_span_context = match parent_context.span_context() {
Some(span_context) if span_context.is_valid() => span_context
_ => @common.SpanContext::empty()
}
let ended = Ref(false)
let context = propagated_context(parent_context, propagated_span_context)
Span::from_functions(
() => propagated_span_context,
() => context,
() => false,
() => ended.val,
(_, _, _) => (),
_ => (),
_ => (),
_ => (),
(_, _) => (),
_ => ended.val = true,
)
}
///|
/// Builds a span handle from callbacks.
///
/// SDK implementations use this to erase their concrete span type into the
/// public API without making the API package depend on the SDK.
/// Spec: https://opentelemetry.io/docs/specs/otel/trace/api/#span
pub fn Span::from_functions(
span_context_fn : () -> @common.SpanContext,
context_fn : () -> @context.Context,
is_recording_fn : () -> Bool,
has_ended_fn : () -> Bool,
add_event_fn : (StringView, Int64, ArrayView[@common.KeyValue]) -> Unit,
set_attribute_fn : (@common.KeyValue) -> Unit,
set_status_fn : (Status) -> Unit,
update_name_fn : (StringView) -> Unit,
add_link_fn : (@common.SpanContext, ArrayView[@common.KeyValue]) -> Unit,
end_fn : async (Int64) -> Unit,
) -> Span {
{
span_context_fn,
context_fn,
is_recording_fn,
has_ended_fn,
add_event_fn,
set_attribute_fn,
set_status_fn,
update_name_fn,
add_link_fn,
end_fn,
}
}
///|
/// Builds a tracer from a span-building callback.
/// Spec: https://opentelemetry.io/docs/specs/otel/trace/api/#tracer
pub fn Tracer::from_functions(
build_with_context_fn : (SpanBuilder, @context.Context) -> Span,
) -> Tracer {
{ build_with_context_fn, }
}
///|
/// Builds a tracer provider from a scope-to-tracer callback.
/// Spec: https://opentelemetry.io/docs/specs/otel/trace/api/#tracerprovider
pub fn TracerProvider::from_functions(
tracer_with_scope_fn : (@common.InstrumentationScope) -> Tracer,
) -> TracerProvider {
{ tracer_with_scope_fn, }
}
///|
/// Returns a no-op tracer provider.
///
/// Tracers from this provider create non-recording spans. Valid parent context
/// is still propagated so downstream services can continue an existing trace.
/// Spec: https://opentelemetry.io/docs/specs/otel/trace/api/#behavior-of-the-api-in-the-absence-of-an-installed-sdk
pub fn TracerProvider::noop() -> TracerProvider {
TracerProvider::from_functions(_ => {
Tracer::from_functions((builder, parent_context) => {
build_noop_span(builder, parent_context)
})
})
}
///|
/// Returns a tracer for one instrumentation name.
///
/// If the provider is no-op, the returned tracer creates non-recording spans.
/// Spec: https://opentelemetry.io/docs/specs/otel/trace/api/#get-a-tracer
pub fn TracerProvider::tracer(
self : TracerProvider,
name : StringView,
) -> Tracer {
self.tracer_with_scope(@common.InstrumentationScope::builder(name).build())
}
///|
/// Returns a tracer for a fully constructed instrumentation scope.
/// Spec: https://opentelemetry.io/docs/specs/otel/trace/api/#get-a-tracer
pub fn TracerProvider::tracer_with_scope(
self : TracerProvider,
scope : @common.InstrumentationScope,
) -> Tracer {
(self.tracer_with_scope_fn)(scope)
}
///|
/// Starts a root span with the given name.
///
/// Use `start_with_context()` when handling an inbound request with an extracted
/// parent context.
/// Spec: https://opentelemetry.io/docs/specs/otel/trace/api/#span-creation
pub fn Tracer::start(self : Tracer, name : StringView) -> Span {
self.start_with_context(name, Default::default())
}
///|
/// Starts a span with an explicit parent context.
///
/// This is the usual entry point after extracting inbound propagation headers or
/// when passing a parent context through asynchronous work.
/// Spec: https://opentelemetry.io/docs/specs/otel/trace/api/#span-creation
pub fn Tracer::start_with_context(
self : Tracer,
name : StringView,
parent_context : @context.Context,
) -> Span {
self.build_with_context(SpanBuilder::from_name(name), parent_context)
}
///|
/// Returns a fresh span builder for `name`.
///
/// The returned builder is independent of the tracer until passed to
/// `build()` or `build_with_context()`.
/// Spec: https://opentelemetry.io/docs/specs/otel/trace/api/#span-creation
pub fn Tracer::span_builder(self : Tracer, name : StringView) -> SpanBuilder {
ignore(self)
SpanBuilder::from_name(name)
}
///|
/// Builds a span from a builder with an empty parent context.
/// Spec: https://opentelemetry.io/docs/specs/otel/trace/api/#span-creation
pub fn Tracer::build(self : Tracer, builder : SpanBuilder) -> Span {
self.build_with_context(builder, Default::default())
}
///|
/// Builds a span from a builder and parent context.
///
/// No-op tracers still return a span handle whose context propagates the parent
/// span context.
/// Spec: https://opentelemetry.io/docs/specs/otel/trace/api/#span-creation
pub fn Tracer::build_with_context(
self : Tracer,
builder : SpanBuilder,
parent_context : @context.Context,
) -> Span {
(self.build_with_context_fn)(builder, parent_context)
}
///|
/// Runs `f` inside a root span and returns its result.
///
/// The span is ended after `f` returns successfully. If `f` can fail, record
/// error status or events before returning from the callback.
/// Spec: https://opentelemetry.io/docs/specs/otel/trace/api/#span-creation
pub async fn[T] Tracer::in_span(
self : Tracer,
name : StringView,
f : async (@context.Context) -> T,
) -> T {
self.in_span_with_context(name, Default::default(), f)
}
///|
/// Runs `f` inside a span with an explicit parent context.
///
/// The span is ended after `f` returns successfully.
/// Spec: https://opentelemetry.io/docs/specs/otel/trace/api/#span-creation
pub async fn[T] Tracer::in_span_with_context(
self : Tracer,
name : StringView,
parent_context : @context.Context,
f : async (@context.Context) -> T,
) -> T {
self.in_span_with_builder(SpanBuilder::from_name(name), parent_context, f)
}
///|
/// Runs `f` inside a span built from `builder`.
///
/// The returned child context carries the new span context. The span is ended
/// after `f` returns successfully.
/// Spec: https://opentelemetry.io/docs/specs/otel/trace/api/#span-creation
pub async fn[T] Tracer::in_span_with_builder(
self : Tracer,
builder : SpanBuilder,
parent_context : @context.Context,
f : async (@context.Context) -> T,
) -> T {
let span = self.build_with_context(builder, parent_context)
let context = span.context()
let result = f(context)
span.end()
result
}
///|
/// Returns the span context that should be propagated downstream.
///
/// For no-op spans this may be the valid incoming parent context rather than a
/// newly recorded span context.
/// Spec: https://opentelemetry.io/docs/specs/otel/trace/api/#get-context
pub fn Span::span_context(self : Span) -> @common.SpanContext {
(self.span_context_fn)()
}
///|
/// Returns the context that carries this span as the active span.
/// Spec: https://opentelemetry.io/docs/specs/otel/trace/api/#get-context
pub fn Span::context(self : Span) -> @context.Context {
(self.context_fn)()
}
///|
/// Returns whether the span is currently recording telemetry.
///
/// No-op spans and sampled-out SDK spans report `false`. Use this to avoid
/// constructing expensive attributes or events.
/// Spec: https://opentelemetry.io/docs/specs/otel/trace/api/#isrecording
pub fn Span::is_recording(self : Span) -> Bool {
(self.is_recording_fn)()
}
///|
/// Returns whether the span has already ended.
/// Spec: https://opentelemetry.io/docs/specs/otel/trace/api/#end
pub fn Span::has_ended(self : Span) -> Bool {
(self.has_ended_fn)()
}
///|
/// Adds one event with the current timestamp.
/// Spec: https://opentelemetry.io/docs/specs/otel/trace/api/#add-events
pub fn Span::add_event(
self : Span,
name : StringView,
attributes? : ArrayView[@common.KeyValue] = [],
) -> Unit {
self.add_event_with_timestamp(name, @utils.now_unix_nano(), attributes~)
}
///|
/// Adds one event with an explicit timestamp.
/// Spec: https://opentelemetry.io/docs/specs/otel/trace/api/#add-events
pub fn Span::add_event_with_timestamp(
self : Span,
name : StringView,
timestamp_unix_nano : Int64,
attributes? : ArrayView[@common.KeyValue] = [],
) -> Unit {
(self.add_event_fn)(name, timestamp_unix_nano, attributes)
}
///|
/// Records an `"exception"` event carrying `exception.message`.
///
/// This helper does not set the span status automatically. Call
/// `set_status(Status::error(...))` if the operation should be marked failed.
/// Spec: https://opentelemetry.io/docs/specs/otel/trace/api/#record-exception
pub fn Span::record_error(self : Span, message : StringView) -> Unit {
self.add_event("exception", attributes=[
@common.KeyValue::new("exception.message", String(message.to_owned())),
])
}
///|
/// Sets or replaces one span attribute.
/// Spec: https://opentelemetry.io/docs/specs/otel/trace/api/#set-attributes
pub fn Span::set_attribute(self : Span, attribute : @common.KeyValue) -> Unit {
(self.set_attribute_fn)(attribute)
}
///|
/// Sets or replaces multiple span attributes.
/// Spec: https://opentelemetry.io/docs/specs/otel/trace/api/#set-attributes
pub fn Span::set_attributes(
self : Span,
attributes : ArrayView[@common.KeyValue],
) -> Unit {
for attribute in attributes {
self.set_attribute(attribute)
}
}
///|
/// Sets the span status.
/// Spec: https://opentelemetry.io/docs/specs/otel/trace/api/#set-status
pub fn Span::set_status(self : Span, status : Status) -> Unit {
(self.set_status_fn)(status)
}
///|
/// Replaces the span name.
/// Spec: https://opentelemetry.io/docs/specs/otel/trace/api/#updatename
pub fn Span::update_name(self : Span, new_name : StringView) -> Unit {
(self.update_name_fn)(new_name)
}
///|
/// Adds one link to another span context.
/// Spec: https://opentelemetry.io/docs/specs/otel/trace/api/#add-link
pub fn Span::add_link(
self : Span,
span_context : @common.SpanContext,
attributes? : ArrayView[@common.KeyValue] = [],
) -> Unit {
(self.add_link_fn)(span_context, attributes)
}
///|
/// Ends the span with the current timestamp.
///
/// Ending an SDK span may notify processors and exporters. Ending a no-op span
/// only updates local state.
/// Spec: https://opentelemetry.io/docs/specs/otel/trace/api/#end
pub async fn Span::end(self : Span) -> Unit {
self.end_with_timestamp(@utils.now_unix_nano())
}
///|
/// Ends the span with an explicit timestamp.
///
/// Ending a no-op span only flips its local ended flag.
/// Spec: https://opentelemetry.io/docs/specs/otel/trace/api/#end
pub async fn Span::end_with_timestamp(
self : Span,
timestamp_unix_nano : Int64,
) -> Unit {
(self.end_fn)(timestamp_unix_nano)
}