Current section
Files
Jump to
Current section
Files
lib/opentelemetry_telemetry.ex
defmodule OpentelemetryTelemetry do
@moduledoc """
`OpentelemetryTelemetry` provides conveniences for leveraging `telemetry`
events for `OpenTelemetry` bridge libraries.
## OpenTelemetry Contexts
`opentelemetry` does not automatically set current span context when ending
another span. Since `telemetry` events are executed in separate handlers with
no shared context, correlating individual events requires a mechanism to do so.
The provided `store_ctx/3`, `store_current_ctx/2`, and `pop_ctx/2` functions
give bridge library authors a mechanism for getting around this challenge.
### Example Telemetry Event Handlers
```
def handle_event(_event,
%{system_time: start_time},
metadata,
%{type: :start, tracer_id: tracer_id, span_name: name}) do
tracer = :opentelemetry.get_tracer(tracer_id)
OpentelemetryTelemetry.store_current_ctx(tracer_id, metadata)
start_opts = %{start_time: start_time}
ctx = :otel_tracer.start_span(tracer, name, start_opts)
:otel_tracer.set_current_span(ctx)
ok
end
def handle_event(_event,
%{duration: duration},
metadata,
%{type: :stop, tracer_id: tracer_id}) do
:otel_tracer.set_attribute(:duration, duration)
:otel_tracer.end_span()
ctx = OpentelemetryTelemetry.pop_ctx(tracer_id, metadata)
:otel_tracer.set_current_span(ctx)
:ok
end
def handle_event(_event,
%{duration: duration},
%{kind: kind, reason: reason, stacktrace: stacktrace} = metadata,
%{type: :exception, tracer_id: tracer_id}) do
status = :opentelemetry.status(:error, to_string(reason, :utf8))
:otel_span.record_exception(:otel_tracer.current_span_ctx(), kind, reason, stacktrace, [{:duration, duration}])
:otel_tracer.set_status(status)
:otel_tracer.end_span()
ctx = OpentelemetryTelemetry.pop_ctx(tracer_id, metadata)
:otel_tracer.set_current_span(ctx)
:ok
end
def handle_event(_event, _measurements, _metadata, _config), do: :ok
```
### Limitations
Span contexts are currently stored in the process dictionary, so spans can only
be correlated within a single process at this time. This covers the primary use
case where library authors have implemented `telemetry:with_span` or the pattern
established in said function. Non-library authors should use opentelemetry directly
wherever possible.
If the `event_metadata` includes a `telemetry_span_context` (introduced in telemetry
`v0.4.3`), contexts are correlated by the `telemetry_span_context` id to guarantee
the correct otel span context. Span events in earlier versions of `telemetry` are stored
in a stack by `tracer_id` to lessen the likelihood of inadvertently closing the wrong
span.
"""
@doc """
Stores the passed `t:OpenTelemetry.span_ctx/0` for a given `tracer_id`.
"""
defdelegate store_ctx(span_ctx, tracer_id, event_metadata), to: :otel_telemetry
@doc """
Convenience function `store_context/3` to use the current span context.
"""
defdelegate store_current_ctx(tracer_id, event_metadata), to: :otel_telemetry
@doc """
Pops and returns a `t:OpenTelemetry.span_ctx/0` for a given `tracer_id`
from the span context store.
"""
defdelegate pop_ctx(tracer_id, event_metadata), to: :otel_telemetry
@doc false
defdelegate trace_application(app), to: :otel_telemetry
@doc false
defdelegate trace_application(app, opts), to: :otel_telemetry
end