lib/opentelemetry_ravix.ex

defmodule OpentelemetryRavix do
  require OpenTelemetry.Tracer

  def setup(store, config \\ []) do
    success_event = [:ravix, store, :requests, :success]
    failure_event = [:ravix, store, :requests, :error]

    :telemetry.attach(
      {__MODULE__, success_event},
      success_event,
      &__MODULE__.handle_success/4,
      config
    )

    :telemetry.attach(
      {__MODULE__, failure_event},
      failure_event,
      &__MODULE__.handle_failure/4,
      config
    )
  end

  @doc false
  def handle_success(
        _event,
        _event_payload,
        event_labels,
        config
      ) do
    {parent_token, span} = build_span(event_labels, config)
    OpenTelemetry.Span.set_status(span, OpenTelemetry.status(:ok))
    OpenTelemetry.Span.end_span(span)

    if parent_token != :undefined do
      OpenTelemetry.Ctx.detach(parent_token)
    end
  end

  @doc false
  def handle_failure(
        _event,
        _event_payload,
        event_labels,
        config
      ) do
    {parent_token, span} = build_span(event_labels, config)
    OpenTelemetry.Span.set_status(span, OpenTelemetry.status(:error))
    OpenTelemetry.Span.end_span(span)

    if parent_token != :undefined do
      OpenTelemetry.Ctx.detach(parent_token)
    end
  end

  defp build_span(
         %{node_url: node_url, database: database},
         config
       ) do
    end_time = :opentelemetry.timestamp()
    span_name = "RavenDB #{database}"

    additional_attributes = Keyword.get(config, :additional_attributes, %{})

    base_attributes = %{
      "db.name": database,
      "db.url": node_url
    }

    attributes =
      base_attributes
      |> Map.merge(additional_attributes)

    parent_context =
      case OpentelemetryProcessPropagator.fetch_ctx(self()) do
        :undefined ->
          OpentelemetryProcessPropagator.fetch_parent_ctx(1, :"$callers")

        ctx ->
          ctx
      end

    parent_token =
      if parent_context != :undefined do
        OpenTelemetry.Ctx.attach(parent_context)
      else
        :undefined
      end

    {parent_token,
     OpenTelemetry.Tracer.start_span(span_name, %{
       start_time: end_time,
       attributes: attributes,
       kind: :client
     })}
  end
end