Current section

Files

Jump to
sentry lib sentry opentelemetry span_record.ex
Raw

lib/sentry/opentelemetry/span_record.ex

if Sentry.OpenTelemetry.VersionChecker.tracing_compatible?() do
defmodule Sentry.OpenTelemetry.SpanRecord do
@moduledoc false
@type t :: %__MODULE__{}
require Record
require OpenTelemetry
@fields Record.extract(:span, from_lib: "opentelemetry/include/otel_span.hrl")
Record.defrecordp(:span, @fields)
defstruct @fields ++ [:origin]
def new(span() = otel_span) do
otel_attrs = span(otel_span)
{:attributes, _, _, _, attributes} = otel_attrs[:attributes]
origin =
case otel_attrs[:instrumentation_scope] do
{:instrumentation_scope, origin, _version, _} ->
origin
_ ->
:undefined
end
attrs =
otel_attrs
|> Keyword.delete(:attributes)
|> Keyword.merge(
trace_id: cast_trace_id(otel_attrs[:trace_id]),
span_id: cast_span_id(otel_attrs[:span_id]),
parent_span_id: cast_span_id(otel_attrs[:parent_span_id]),
origin: origin,
start_time: cast_timestamp(otel_attrs[:start_time]),
end_time: cast_timestamp(otel_attrs[:end_time]),
attributes: normalize_attributes(attributes)
)
|> Map.new()
struct(__MODULE__, attrs)
end
defp normalize_attributes(attributes) do
Enum.map(attributes, fn {key, value} ->
{to_string(key), value}
end)
|> Map.new()
end
defp cast_span_id(nil), do: nil
defp cast_span_id(:undefined), do: nil
defp cast_span_id(span_id), do: bytes_to_hex(span_id, 16)
defp cast_trace_id(trace_id), do: bytes_to_hex(trace_id, 32)
defp cast_timestamp(:undefined), do: nil
defp cast_timestamp(nil), do: nil
defp cast_timestamp(timestamp) do
nano_timestamp = OpenTelemetry.timestamp_to_nano(timestamp)
{:ok, datetime} = DateTime.from_unix(div(nano_timestamp, 1_000_000), :millisecond)
DateTime.to_iso8601(datetime)
end
defp bytes_to_hex(bytes, length) do
case(:otel_utils.format_binary_string("~#{length}.16.0b", [bytes])) do
{:ok, result} -> result
{:error, _} -> raise "Failed to convert bytes to hex: #{inspect(bytes)}"
end
end
end
end