OpenTelemetryAPI

The content in this page is organized in the same order as the OpenTelemetry Specification.

Context

All the MUST items in the original specification are implemented.

Context is implemented as a wrapper of NamedTuple, which means it is immutable. Each Task has exactly ONE Context instance, which is injected into the task_local_storage of the current_task by the parent task automatically.

Warning

Type piracy is used to the propagate context between tasks. See more discussions in #32

create_key is used to create a context key. But it is not exported yet because it seems to be only used internally until now.

Base.getindex(::Context, key) is implemented so to get a value in a Context, one can simply call ctx[key] to get the associated value of a key in a ctx.

Setting value of a Context is not directly supported. Given that Context is immutable, updating an immutable object in Julia seems strange. We provide the with_context function to create a new context based on the key-value pairs in the current_context. This syntax is more common than the attach/detach operations in the original specification.

OpenTelemetryAPI.with_contextMethod
with_context(f, [context]; kv...)

Run function f in the context. If extra kv pairs are provided, they will be merged with the context to form a new context. When context is not provided, the current_context will be used.

Propagators

inject_context! and extract_context are provided based on the original specification.

The GLOBAL_PROPAGATOR is set to a CompositePropagator, with multiple dispatch, each inner propagator can be customized to handle different contexts and carriers. Since it's mainly used internally for now, it's not exposed yet.

Trace

The relationship between trace provider, tracer, span context and span is depicted below:

┌────────────────────────────┐
│ AbstractSpan               │
│   ┌──────────────────────┐ │
│   │ Tracer               │ │
│   │   ┌────────────────┐ │ │
│   │   │    Abstract    │ │ │
│   │   │ TracerProvider │ │ │
│   │   └────────────────┘ │ │
│   │  instrumentation     │ │
│   │   ┌────────────────┐ │ │
│   │   │ name           │ │ │
│   │   │ version        │ │ │
│   │   └────────────────┘ │ │
│   └──────────────────────┘ │
└────────────────────────────┘

In OpenTelemetryAPI.jl, only one concrete AbstractTracerProvider (the DummyTracerProvider) is provided. It is set as the default global_tracer_provider. Without SDK installed, the with_span will only create a NonRecordingSpan. This is to make the OpenTelemetryAPI.jl lightweight enough so that instrumentation package users can happily add it as a dependency without losing performance.

OpenTelemetryAPI.TracerType
Tracer(;instrumentation_scope=InstrumentationScope(), provider=global_meter_provider())
OpenTelemetryAPI.attributesMethod
attributes(s::AbstractSpan)

A BoundedAttributes is expected.

Warning

Do not modify the returned attributes directly. Users should always modify attributes through (s::AbstractSpan)[key]=val because it will check the is_recording(s) first.

OpenTelemetryAPI.end_span!Method
end_span!([s=current_span()], [t=UInt(time()*10^9)])

Set the end time of the span and trigger span processors. Note t is the nanoseconds.

OpenTelemetryAPI.resourceMethod
resource(s::AbstractSpan)

Get the associated resource of the span s. Fall back to resource(provider(::AbstractSpan))

OpenTelemetryAPI.span_status!Method
span_status!([current_span()], code::SpanStatusCode, description=nothing)

Update the status of span s by following the original specification. description is only considered when the code is SPAN_STATUS_ERROR. Only valid when the span is not ended yet.

OpenTelemetryAPI.with_spanFunction
with_span(f, name::String, [tracer=Tracer()]; kw...)

Call function f with the current span set a newly created one of name with tracer.

Keyword arguments

  • end_on_exit=true, controls whether to call end_span! after f or not.
  • record_exception=true, controls whether to record the exception.
  • set_status_on_exception=true, decides whether to set status to SPAN_STATUS_ERROR automatically when an exception is caught.
  • The rest keyword arguments are forwarded to create_span.
OpenTelemetryAPI.with_spanMethod
with_span(f, s::AbstractSpan; kw...)

Call function f with the provided span s.

Keyword arguments

  • end_on_exit=true, controls whether to call end_span! after f or not.
  • record_exception=true, controls whether to record the exception.
  • set_status_on_exception=true, decides whether to set status to SPAN_STATUS_ERROR automatically when an exception is caught.

Metric

The relationship between MeterProvider, Meter and different instruments are depicted below:

 ┌─────────────────────────────┐
 │AbstractInstrument           │
 │                             │
 │  name                       │
 │  unit                       │
 │  description                │
 │                             │
 │  meter                      │
 │   ┌───────────────────────┐ │
 │   │Meter                  │ │
 │   │                       │ │
 │   │  provider             │ │
 │   │   ┌────────────────┐  │ │
 │   │   │   Abstract     │  │ │
 │   │   │ MeterProvider  │  │ │
 │   │   └────────────────┘  │ │
 │   │  name                 │ │
 │   │  version              │ │
 │   │  schema_url           │ │
 │   │                       │ │
 │   │  instrumentation      │ │
 │   │   ┌────────────────┐  │ │
 │   │   │ name           │  │ │
 │   │   │ version        │  │ │
 │   │   └────────────────┘  │ │
 │   │  instruments          │ │
 │   │                       │ │
 │   │    * Counter          │ │
 │   │    * Histogram        │ │
 │   │    * UpDownCounter    │ │
 │   │    * ObservableCounter│ │
 │   │    * Observable       │ │
 │   │      UpDownCounter    │ │
 │   └───────────────────────┘ │
 │                             │
 └─────────────────────────────┘
  • An Instrument belongs to a Meter, each Meter may contain many different Instruments. Similarly, a Meter belongs to a MeterProvider and a MeterProvider may contain many different Meters.
OpenTelemetryAPI.MeterType
Meter(name::String;kw...)

Meter is responsible for creating instruments.

Keyword Arguments:

  • provider::P = global_meter_provider()
  • instrumentation_scope = InstrumentationScope()

Instruments

All instruments provided here can be classified into two categories: AbstractSyncInstrument and AbstractAsyncInstrument.

OpenTelemetryAPI.HistogramType
Histogram{T}(name, meter; unit = "", description = "") where {T}

Histogram is an AbstractSyncInstrument which can be used to report arbitrary values that are likely to be statistically meaningful. It is intended for statistics such as histograms, summaries, and percentile.

See more details from the specification

OpenTelemetryAPI.ObservableGaugeType
ObservableGauge{T}(callback, name, meter; unit = "", description = "",) where {T}

ObservableGauge is an AbstractAsyncInstrument which reports non-additive value(s) (e.g. the room temperature - it makes no sense to report the temperature value from multiple rooms and sum them up) when the instrument is being observed.

See also the details from the specification

OpenTelemetryAPI.ObservableUpDownCounterType
ObservableUpDownCounter{T}(callback, name, meter; unit = "", description = "") where {T}

ObservableUpDownCounter is an AbstractAsyncInstrument which reports additive value(s) (e.g. the process heap size - it makes sense to report the heap size from multiple processes and sum them up, so we get the total heap usage) when the instrument is being observed.

See more details from the specification.

Logging

The idea is simple, a OtelLogTransformer is provided to transform each logging message into a LogRecord. To understand how to use it, users should be familiar with how TransformerLogger from LoggingExtras.jl works.

Misc

OpenTelemetryAPI.AbstractAsyncInstrumentType

Async instrument usually has a callback function (which is named Observable in OpenTelemetry) to get its measurement.

Note

If the return of the callback function is not a Measurement, it will be converted into a Measurement with an empty BoundedAttributes implicitly when being uploaded to the associated meter provider.

OpenTelemetryAPI.AbstractMeterProviderType

A meter provider defines how to collect and update Measurements. Each meter provider should have the following interfaces implemented:

  • Base.push!(provider, m::Meter), register a meter.
  • Base.push!(provider, ins::AbstractInstrument), register an instrument.
  • Base.push!(provider, (ins::AbstractInstrument, m::Measurement)), update a measurement.
OpenTelemetryAPI.AbstractTracerProviderType

A tracer provider is a part of an Tracer. For each concrete tracer provider, resource and OpenTelemetryAPI.create_span(name::String, tracer::Tracer{<:YourCustomProvider}) should also be implemented.

OpenTelemetryAPI.BoundedAttributesType
BoundedAttributes(attrs; count_limit=nothing, value_length_limit=nothing)

This provides a wrapper around attributes (typically AbstractDict or NamedTuple) to follow the specification of Attribute.

The following methods from Base are defined on BoundedAttributes which are then forwarded to the inner attrs by default. Feel free to create a PR if you find any method you need is missing:

  • Base.getindex
  • Base.setindex!
  • Base.iterate
  • Base.length
  • Base.haskey
  • Base.push!. Obviously, an error will be thrown when calling on immutable attrss like NamedTuple.
OpenTelemetryAPI.InstrumentationScopeType
InstrumentationScope(;name="OpenTelemetryAPI", version=<default>, schema_url="", attributes=BoundedAttributes())

Usually used in an instrumentation package.

OpenTelemetryAPI.ResourceType
Resource(;attributes=nothing, schema_url="", default_attributes=OTEL_RESOURCE_ATTRIBUTES())

Quoted from the specification:

Resource captures information about the entity for which telemetry is recorded. For example, metrics exposed by a Kubernetes container can be linked to a resource that specifies the cluster, namespace, pod, and container name.

Resource may capture an entire hierarchy of entity identification. It may describe the host in the cloud and specific container or an application running in the process.

OpenTelemetryAPI.SpanContextType
SpanContext(;span_id, trace_id, is_remote, trace_flag=TraceFlag(), trace_state=TraceState())

A SpanContext represents the portion of a Span which must be serialized and propagated along side of a distributed context. SpanContexts are immutable.

The OpenTelemetry SpanContext representation conforms to the W3C TraceContext specification. It contains two identifiers - a TraceId and a SpanId - along with a set of common TraceFlags and system-specific TraceState values.

TraceId A valid trace identifier is a 16-byte array with at least one non-zero byte.

SpanId A valid span identifier is an 8-byte array with at least one non-zero byte.

TraceFlags contain details about the trace. Unlike TraceState values, TraceFlags are present in all traces. The current version of the specification only supports a single flag called sampled.

TraceState carries vendor-specific trace identification data, represented as a list of key-value pairs. TraceState allows multiple tracing systems to participate in the same trace. It is fully described in the W3C Trace Context specification.

OpenTelemetryAPI.SpanStatusType
SpanStatus(code, description=nothing)

Possible codes are:

  • SPAN_STATUS_UNSET
  • SPAN_STATUS_ERROR
  • SPAN_STATUS_OK

description is required when code is SPAN_STATUS_ERROR.

OpenTelemetryAPI.TraceStateType
TraceState(entries::Pair{String,String}...)

TraceState carries vendor-specific trace identification data, represented as a list of key-value pairs. TraceState allows multiple tracing systems to participate in the same trace. It is fully described in the W3C Trace Context specification.

Base.getindexMethod
Base.getindex(s::AbstractSpan, key)

Look up key in the attributes of the span s.

Base.haskeyMethod
Base.haskey(s::AbstractSpan, key)

Check if the span s has the key in its attributes.

Base.push!Method
Base.push!([s::AbstractSpan], event::Event)

Add an Event into the span s.

Base.push!Method
Base.push!([current_span()], link::Link)

Add a Link into the span s.

Base.push!Method
Base.push!(s::AbstractSpan, ex::Exception; is_rethrow_followed = false)

A specialized variant of Event to record exceptions. Usually used in a try... catch...end to capture the backtrace. If the ex is rethrowed in the catch...end, is_rethrow_followed should be set to true.

Base.setindex!Method
(s::AbstractSpan)[key] = val

Set the attributes in span s. Only valid when the span is not ended yet.

OpenTelemetryAPI.OTEL_PROPAGATORSMethod

Propagators to be used as a comma-separated list .

Values MUST be deduplicated in order to register a Propagator only once.

OpenTelemetryAPI.OTEL_SDK_DISABLEDMethod

Disable the SDK for all signals.

Boolean value. If "true", a no-op SDK implementation will be used for all telemetry signals. Any other value or absence of the variable will have no effect and the SDK will remain enabled. This setting has no effect on propagators configured through the OTEL_PROPAGATORS variable.

OpenTelemetryAPI.OTEL_TRACES_SAMPLER_ARGMethod

String value to be used as the sampler argument.

The specified value will only be used if OTELTRACESSAMPLER is set. Each Sampler type defines its own expected input, if any. Invalid or unrecognized input MUST be logged and MUST be otherwise ignored, i.e. the SDK MUST behave as if OTELTRACESSAMPLER_ARG is not set.

OpenTelemetryAPI.extract_contextMethod
extract_context(carrier, [global_propagator], [current_context])

Extracts the value from an incoming request. For example, from the headers of an HTTP request.

OpenTelemetryAPI.inject_context!Method
inject(carrier, [global_propagator], [current_context])

Injects the value into a carrier. For example, into the headers of an HTTP request.