251 lines
11 KiB
Elixir
251 lines
11 KiB
Elixir
defmodule Bandit.Telemetry do
|
|
@moduledoc """
|
|
The following telemetry spans are emitted by bandit
|
|
|
|
## `[:bandit, :request, *]`
|
|
|
|
Represents Bandit handling a specific client HTTP request
|
|
|
|
This span is started by the following event:
|
|
|
|
* `[:bandit, :request, :start]`
|
|
|
|
Represents the start of the span
|
|
|
|
This event contains the following measurements:
|
|
|
|
* `monotonic_time`: The time of this event, in `:native` units
|
|
|
|
This event contains the following metadata:
|
|
|
|
* `telemetry_span_context`: A unique identifier for this span
|
|
* `connection_telemetry_span_context`: The span context of the Thousand Island `:connection`
|
|
span which contains this request
|
|
* `conn`: The `Plug.Conn` representing this connection. Not present in cases where `error`
|
|
is also set and the nature of error is such that Bandit was unable to successfully build
|
|
the conn
|
|
* `plug`: The Plug which is being used to serve this request. Specified as `{plug_module, plug_opts}`
|
|
|
|
This span is ended by the following event:
|
|
|
|
* `[:bandit, :request, :stop]`
|
|
|
|
Represents the end of the span
|
|
|
|
This event contains the following measurements:
|
|
|
|
* `monotonic_time`: The time of this event, in `:native` units
|
|
* `duration`: The span duration, in `:native` units
|
|
* `req_header_end_time`: The time that header reading completed, in `:native` units
|
|
* `req_body_start_time`: The time that request body reading started, in `:native` units.
|
|
* `req_body_end_time`: The time that request body reading completed, in `:native` units
|
|
* `req_body_bytes`: The length of the request body, in octets
|
|
* `resp_start_time`: The time that the response started, in `:native` units
|
|
* `resp_end_time`: The time that the response completed, in `:native` units
|
|
* `resp_body_bytes`: The length of the response body, in octets. If the response is
|
|
compressed, this is the size of the compressed payload as sent on the wire
|
|
* `resp_uncompressed_body_bytes`: The length of the original, uncompressed body. Only
|
|
included for responses which are compressed
|
|
* `resp_compression_method`: The method of compression, as sent in the `Content-Encoding`
|
|
header of the response. Only included for responses which are compressed
|
|
|
|
This event contains the following metadata:
|
|
|
|
* `telemetry_span_context`: A unique identifier for this span
|
|
* `connection_telemetry_span_context`: The span context of the Thousand Island `:connection`
|
|
span which contains this request
|
|
* `conn`: The `Plug.Conn` representing this connection. Not present in cases where `error`
|
|
is also set and the nature of error is such that Bandit was unable to successfully build
|
|
the conn
|
|
* `plug`: The Plug which is being used to serve this request. Specified as `{plug_module, plug_opts}`
|
|
* `error`: The error that caused the span to end, if it ended in error
|
|
|
|
The following events may be emitted within this span:
|
|
|
|
* `[:bandit, :request, :exception]`
|
|
|
|
The request for this span ended unexpectedly
|
|
|
|
This event contains the following measurements:
|
|
|
|
* `monotonic_time`: The time of this event, in `:native` units
|
|
|
|
This event contains the following metadata:
|
|
|
|
* `telemetry_span_context`: A unique identifier for this span
|
|
* `connection_telemetry_span_context`: The span context of the Thousand Island `:connection`
|
|
span which contains this request
|
|
* `conn`: The `Plug.Conn` representing this connection. Not present in cases where `error`
|
|
is also set and the nature of error is such that Bandit was unable to successfully build
|
|
the conn
|
|
* `plug`: The Plug which is being used to serve this request. Specified as `{plug_module, plug_opts}`
|
|
* `kind`: The kind of unexpected condition, typically `:exit`
|
|
* `exception`: The exception which caused this unexpected termination. May be an exception
|
|
or an arbitrary value when the event was an uncaught throw or an exit
|
|
* `stacktrace`: The stacktrace of the location which caused this unexpected termination
|
|
|
|
## `[:bandit, :websocket, *]`
|
|
|
|
Represents Bandit handling a WebSocket connection
|
|
|
|
This span is started by the following event:
|
|
|
|
* `[:bandit, :websocket, :start]`
|
|
|
|
Represents the start of the span
|
|
|
|
This event contains the following measurements:
|
|
|
|
* `monotonic_time`: The time of this event, in `:native` units
|
|
* `compress`: Details about the compression configuration for this connection
|
|
|
|
This event contains the following metadata:
|
|
|
|
* `telemetry_span_context`: A unique identifier for this span
|
|
* `connection_telemetry_span_context`: The span context of the Thousand Island `:connection`
|
|
span which contains this request
|
|
* `websock`: The WebSock which is being used to serve this request. Specified as `websock_module`
|
|
|
|
This span is ended by the following event:
|
|
|
|
* `[:bandit, :websocket, :stop]`
|
|
|
|
Represents the end of the span
|
|
|
|
This event contains the following measurements:
|
|
|
|
* `monotonic_time`: The time of this event, in `:native` units
|
|
* `duration`: The span duration, in `:native` units
|
|
* `recv_text_frame_count`: The number of text frames received
|
|
* `recv_text_frame_bytes`: The total number of bytes received in the payload of text frames
|
|
* `recv_binary_frame_count`: The number of binary frames received
|
|
* `recv_binary_frame_bytes`: The total number of bytes received in the payload of binary frames
|
|
* `recv_ping_frame_count`: The number of ping frames received
|
|
* `recv_ping_frame_bytes`: The total number of bytes received in the payload of ping frames
|
|
* `recv_pong_frame_count`: The number of pong frames received
|
|
* `recv_pong_frame_bytes`: The total number of bytes received in the payload of pong frames
|
|
* `recv_connection_close_frame_count`: The number of connection close frames received
|
|
* `recv_connection_close_frame_bytes`: The total number of bytes received in the payload of connection close frames
|
|
* `recv_continuation_frame_count`: The number of continuation frames received
|
|
* `recv_continuation_frame_bytes`: The total number of bytes received in the payload of continuation frames
|
|
* `send_text_frame_count`: The number of text frames sent
|
|
* `send_text_frame_bytes`: The total number of bytes sent in the payload of text frames
|
|
* `send_binary_frame_count`: The number of binary frames sent
|
|
* `send_binary_frame_bytes`: The total number of bytes sent in the payload of binary frames
|
|
* `send_ping_frame_count`: The number of ping frames sent
|
|
* `send_ping_frame_bytes`: The total number of bytes sent in the payload of ping frames
|
|
* `send_pong_frame_count`: The number of pong frames sent
|
|
* `send_pong_frame_bytes`: The total number of bytes sent in the payload of pong frames
|
|
* `send_connection_close_frame_count`: The number of connection close frames sent
|
|
* `send_connection_close_frame_bytes`: The total number of bytes sent in the payload of connection close frames
|
|
* `send_continuation_frame_count`: The number of continuation frames sent
|
|
* `send_continuation_frame_bytes`: The total number of bytes sent in the payload of continuation frames
|
|
|
|
This event contains the following metadata:
|
|
|
|
* `telemetry_span_context`: A unique identifier for this span
|
|
* `origin_telemetry_span_context`: The span context of the Bandit `:request` span from which
|
|
this connection originated
|
|
* `connection_telemetry_span_context`: The span context of the Thousand Island `:connection`
|
|
span which contains this request
|
|
* `websock`: The WebSock which is being used to serve this request. Specified as `websock_module`
|
|
* `error`: The error that caused the span to end, if it ended in error
|
|
"""
|
|
|
|
defstruct span_name: nil, telemetry_span_context: nil, start_time: nil, start_metadata: nil
|
|
|
|
@typep span_name :: atom()
|
|
@opaque t :: %__MODULE__{
|
|
span_name: span_name(),
|
|
telemetry_span_context: reference(),
|
|
start_time: integer(),
|
|
start_metadata: :telemetry.event_metadata()
|
|
}
|
|
|
|
@app_name :bandit
|
|
|
|
@doc false
|
|
@spec start_span(span_name(), :telemetry.event_measurements(), :telemetry.event_metadata()) ::
|
|
t()
|
|
def start_span(span_name, measurements \\ %{}, metadata \\ %{}) do
|
|
measurements = Map.put_new_lazy(measurements, :monotonic_time, &monotonic_time/0)
|
|
telemetry_span_context = make_ref()
|
|
metadata = Map.put(metadata, :telemetry_span_context, telemetry_span_context)
|
|
event([span_name, :start], measurements, metadata)
|
|
|
|
%__MODULE__{
|
|
span_name: span_name,
|
|
telemetry_span_context: telemetry_span_context,
|
|
start_time: measurements[:monotonic_time],
|
|
start_metadata: metadata
|
|
}
|
|
end
|
|
|
|
@doc false
|
|
@spec stop_span(t(), :telemetry.event_measurements(), :telemetry.event_metadata()) :: :ok
|
|
def stop_span(span, measurements \\ %{}, metadata \\ %{}) do
|
|
measurements = Map.put_new_lazy(measurements, :monotonic_time, &monotonic_time/0)
|
|
|
|
measurements =
|
|
Map.put(measurements, :duration, measurements[:monotonic_time] - span.start_time)
|
|
|
|
metadata = Map.merge(span.start_metadata, metadata)
|
|
|
|
untimed_span_event(span, :stop, measurements, metadata)
|
|
end
|
|
|
|
@spec span_exception(t(), Exception.kind(), Exception.t() | term(), Exception.stacktrace()) ::
|
|
:ok
|
|
def span_exception(span, kind, reason, stacktrace) do
|
|
# Using :exit for backwards-compatibility with Bandit =< 1.5.7
|
|
kind = if kind == :error, do: :exit, else: kind
|
|
|
|
metadata =
|
|
Map.merge(span.start_metadata, %{
|
|
kind: kind,
|
|
exception: reason,
|
|
stacktrace: stacktrace
|
|
})
|
|
|
|
span_event(span, :exception, %{}, metadata)
|
|
end
|
|
|
|
@doc false
|
|
@spec span_event(t(), span_name(), :telemetry.event_measurements(), :telemetry.event_metadata()) ::
|
|
:ok
|
|
def span_event(span, name, measurements \\ %{}, metadata \\ %{}) do
|
|
measurements = Map.put_new_lazy(measurements, :monotonic_time, &monotonic_time/0)
|
|
untimed_span_event(span, name, measurements, metadata)
|
|
end
|
|
|
|
@doc false
|
|
@spec untimed_span_event(
|
|
t(),
|
|
span_name(),
|
|
:telemetry.event_measurements(),
|
|
:telemetry.event_metadata()
|
|
) :: :ok
|
|
def untimed_span_event(span, name, measurements \\ %{}, metadata \\ %{}) do
|
|
metadata = Map.put(metadata, :telemetry_span_context, span.telemetry_span_context)
|
|
event([span.span_name, name], measurements, metadata)
|
|
end
|
|
|
|
@spec monotonic_time :: integer()
|
|
defdelegate monotonic_time, to: System
|
|
|
|
@spec event(
|
|
:telemetry.event_name(),
|
|
:telemetry.event_measurements(),
|
|
:telemetry.event_metadata()
|
|
) :: :ok
|
|
defp event(suffix, measurements, metadata) do
|
|
:telemetry.execute([@app_name | suffix], measurements, metadata)
|
|
end
|
|
|
|
@doc false
|
|
@spec telemetry_span_context(t()) :: reference()
|
|
def telemetry_span_context(span) do
|
|
span.telemetry_span_context
|
|
end
|
|
end
|