opentelemetry-erlang-contrib/instrumentation/opentelemetry_finch/lib/opentelemetry_finch.ex

85 lines
2.1 KiB
Elixir
Raw Normal View History

defmodule OpentelemetryFinch do
@moduledoc """
OpentelemetryFinch uses [telemetry](https://hexdocs.pm/telemetry/) handlers to
create `OpenTelemetry` spans.
## Usage
In your application start:
def start(_type, _args) do
OpentelemetryFinch.setup()
# ...
end
"""
2022-12-15 11:36:52 +00:00
alias OpenTelemetry.SemanticConventions.Trace
require Trace
require OpenTelemetry.Tracer
@typedoc "Setup options"
@type opts :: []
@doc """
Initializes and configures the telemetry handlers.
"""
@spec setup(opts()) :: :ok
def setup(_opts \\ []) do
:telemetry.attach(
{__MODULE__, :request_stop},
[:finch, :request, :stop],
&__MODULE__.handle_request_stop/4,
%{}
)
end
@doc false
def handle_request_stop(_event, measurements, meta, _config) do
duration = measurements.duration
end_time = :opentelemetry.timestamp()
start_time = end_time - duration
status =
case meta.result do
{:ok, response} -> response.status
_ -> 0
end
url = build_url(meta.request.scheme, meta.request.host, meta.request.port, meta.request.path)
attributes = %{
2022-12-15 11:36:52 +00:00
Trace.http_url() => url,
Trace.http_scheme() => meta.request.scheme,
Trace.net_peer_name() => meta.request.host,
Trace.net_peer_port() => meta.request.port,
Trace.http_target() => meta.request.path,
Trace.http_method() => meta.request.method,
Trace.http_status_code() => status
}
s =
OpenTelemetry.Tracer.start_span("HTTP #{meta.request.method}", %{
start_time: start_time,
attributes: attributes,
kind: :client
})
if meta.result |> elem(0) == :error do
OpenTelemetry.Span.set_status(
s,
OpenTelemetry.status(:error, format_error(meta.result |> elem(1)))
)
end
OpenTelemetry.Span.end_span(s)
end
defp build_url(scheme, host, port, path), do: "#{scheme}://#{host}:#{port}#{path}"
defp format_error(%{__exception__: true} = exception), do: Exception.message(exception)
defp format_error(reason), do: inspect(reason)
end