defmodule Avalanche.Telemetry do
@moduledoc """
Telemetry integration.
Unless specified, all time's are in `:native` units.
Avalanche executes the following events:
### Query Start
`[:avalanche, :query, :start]` - Executed at the start of each query sent to Snowflake.
#### Measurements
* `:system_time` - The time the query started
#### Metadata:
* `:query` - The query sent to the database as a string
* `:params` - The query parameters
### Query Stop
`[:avalanche, :query, :stop]` - Executed at the end of each query sent to Snowflake.
#### Measurements
* `:duration` - The time spent executing the query
#### Metadata:
* `:query` - The query sent to the database as a string
* `:params` - The query parameters
* `:result` - The query result (selected, updated)
* `:num_rows` - The number of rows effected by the query
* `:error` - Present if any error occurred while processing the query. (optional)
### Query Exception
`[:avalanche, :query, :exception]` - Executed if executing a query throws an exception.
#### Measurements
* `:duration` - The time spent executing the query
#### Metadata
* `:kind` - The type of exception.
* `:error` - Error description or error data.
* `:stacktrace` - The stacktrace
"""
@spec start(atom(), map(), map()) :: map()
@doc "Emits a `start` telemetry event"
def start(event, meta, extra_measurements \\ %{}) do
start_time = System.monotonic_time()
telemetry_output =
telemetry_dispatch_impl().execute(
[:avalanche, event, :start],
Map.merge(extra_measurements, %{system_time: System.system_time()}),
meta
)
%{start_time: start_time, telemetry_output: telemetry_output}
end
@spec stop(atom(), number(), map(), map()) :: map()
@doc "Emits a stop event"
def stop(event, start_time, meta \\ %{}, extra_measurements \\ %{}) do
end_time = System.monotonic_time()
measurements = Map.merge(extra_measurements, %{duration: end_time - start_time})
telemetry_output =
telemetry_dispatch_impl().execute(
[:avalanche, event, :stop],
measurements,
meta
)
%{end_time: end_time, telemetry_output: telemetry_output}
end
@spec event(atom(), number() | map(), map()) :: map()
@doc "Used for reporting generic events"
def event(event, measurements, meta) do
telemetry_output = telemetry_dispatch_impl().execute([:avalanche, event], measurements, meta)
%{telemetry_output: telemetry_output}
end
@spec exception(atom(), number(), any(), any(), any(), map(), map()) :: map()
@doc false
def exception(
event,
start_time,
kind,
reason,
stack,
meta,
extra_measurements \\ %{}
) do
end_time = System.monotonic_time()
measurements = Map.merge(extra_measurements, %{duration: end_time - start_time})
meta =
meta
|> Map.put(:kind, kind)
|> Map.put(:error, reason)
|> Map.put(:stacktrace, stack)
telemetry_output = telemetry_dispatch_impl().execute([:avalanche, event, :exception], measurements, meta)
%{telemetry_output: telemetry_output}
end
defp telemetry_dispatch_impl do
Application.get_env(:avalanche, :telemetry_dispatch_impl, Avalanche.Telemetry.TelemetryDispatchImpl)
end
end