Packages

Zero-config APM SDK for Elixir — Phoenix, Plug, Ecto. Add the dep and set METRIXWIRE_KEY; every request/query/HTTP call is traced automatically.

Current section

Files

Jump to
metrixwire lib metrixwire span.ex
Raw

lib/metrixwire/span.ex

defmodule MetrixWire.Span do
@moduledoc """
A single unit of work within a trace (`db_query` | `http_call` | `custom`).
Users never build these — instrumentation creates them. Serialized to the exact
ingest wire shape.
"""
defstruct type: "custom",
description: "",
started_at: nil,
duration_ms: 0,
source_location: nil,
meta: nil
@type t :: %__MODULE__{}
@doc """
Build a span. `type` is "db_query" | "http_call" | "custom". `started_at` is an
ISO8601 string. `meta` is an optional map (e.g. `%{"rowCount" => n}`).
"""
def new(type, description, started_at, duration_ms, opts \\ []) do
%__MODULE__{
type: type,
description: to_string(description),
started_at: started_at,
duration_ms: max(round_num(duration_ms), 0),
source_location: Keyword.get(opts, :source_location),
meta: normalize_meta(Keyword.get(opts, :meta))
}
end
@doc "Serialize to the ingest wire shape (string keys, camelCase)."
def to_map(%__MODULE__{} = span) do
base = %{
"type" => span.type,
"description" => span.description,
"startedAt" => span.started_at,
"durationMs" => span.duration_ms
}
base
|> maybe_put("sourceLocation", span.source_location)
|> maybe_put("meta", span.meta)
end
defp normalize_meta(meta) when is_map(meta) and map_size(meta) > 0, do: meta
defp normalize_meta(_), do: nil
defp maybe_put(map, _key, nil), do: map
defp maybe_put(map, key, value), do: Map.put(map, key, value)
defp round_num(v) when is_integer(v), do: v
defp round_num(v) when is_float(v), do: round(v)
defp round_num(_), do: 0
end