defmodule Mixpanel.Telemetry do
@moduledoc """
The following telemetry spans are emitted by mixpanel_api_ex:
## `[:mixpanel_api_ex, :client, *]`
Represents a Mixpanel API client is ready
This span is started by the following event:
* `[:mixpanel_api_ex, :client, :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:
* `name`: The name of the client
* `base_url`: The URL which a client instance uses to communicate with
the Mixpanel API
* `http_adapter`: The HTTP adapter which a client instance uses to send
actual requests to the backend
This span is ended by the following event:
* `[:mixpanel_api_ex, :client, :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
This event contains the following metadata:
* `name`: The name of the client
* `base_url`: The URL which a client instance uses to communicate with
the Mixpanel API
* `http_adapter`: The HTTP adapter which a client instance uses to send
actual requests to the backend
The following events may be emitted within this span:
* `[:mixpanel_api_ex, :client, :send]`
Represents a request sent to the Mixpanel API
This event contains the following measurements:
* `event`: The name of the event that was sent
* `payload_size`: The size (in bytes) of the payload has been sent
This event contains the following metadata:
* `telemetry_span_context`: A unique identifier for this span
* `name`: The name of the client
* `[:mixpanel_api_ex, :client, :send_error]`
An error occurred while sending a request to the Mixpanel API
This event contains the following measurements:
* `event`: The name of the event that was attempted to send
* `error`: A description of the error
* `payload_size`: The size (in bytes) of the payload that were attempted to send
This event contains the following metadata:
* `telemetry_span_context`: A unique identifier for this span
* `name`: The name of the client
"""
@enforce_keys [:span_name, :telemetry_span_context, :start_time, :start_metadata]
defstruct @enforce_keys
@type t :: %__MODULE__{
span_name: span_name,
telemetry_span_context: reference,
start_time: integer,
start_metadata: metadata
}
@type span_name :: :client
@type metadata :: :telemetry.event_metadata()
@typedoc false
@type measurements :: :telemetry.event_measurements()
@typedoc false
@type event_name :: :ready | :send_error
@typedoc false
@type untimed_event_name :: :stop | :send
@app_name :mixpanel_api_ex
@doc false
@spec start_span(span_name, measurements, metadata) :: t
def start_span(span_name, measurements, metadata) do
measurements = Map.put_new_lazy(measurements, :monotonic_time, &System.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, measurements, metadata) :: :ok
def stop_span(span, measurements \\ %{}, metadata \\ %{}) do
measurements = Map.put_new_lazy(measurements, :monotonic_time, &System.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
@doc false
@spec span_event(t, event_name, measurements, metadata) :: :ok
def span_event(span, name, measurements \\ %{}, metadata \\ %{}) do
measurements = Map.put_new_lazy(measurements, :monotonic_time, &System.monotonic_time/0)
untimed_span_event(span, name, measurements, metadata)
end
@doc false
@spec untimed_span_event(t, event_name | untimed_event_name, measurements, 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
defp event(suffix, measurements, metadata) do
:telemetry.execute([@app_name | suffix], measurements, metadata)
end
end