Current section

Files

Jump to
snakebridge lib snakebridge telemetry runtime_forwarder.ex
Raw

lib/snakebridge/telemetry/runtime_forwarder.ex

defmodule SnakeBridge.Telemetry.RuntimeForwarder do
@moduledoc """
Enriches Snakepit runtime telemetry with SnakeBridge context.
This module listens to Snakepit's call events and re-emits them under
the `:snakebridge` namespace with additional context like the SnakeBridge
version and library information.
## Events
Original Snakepit events:
- `[:snakepit, :python, :call, :start]`
- `[:snakepit, :python, :call, :stop]`
- `[:snakepit, :python, :call, :exception]`
Are forwarded as:
- `[:snakebridge, :runtime, :call, :start]`
- `[:snakebridge, :runtime, :call, :stop]`
- `[:snakebridge, :runtime, :call, :exception]`
With added metadata:
- `snakebridge_library` - The library name from the original event
- `snakebridge_version` - The current SnakeBridge version
## Usage
# In your application startup
SnakeBridge.Telemetry.RuntimeForwarder.attach()
"""
@handler_id "snakebridge-runtime-enricher"
@events [
[:snakepit, :python, :call, :start],
[:snakepit, :python, :call, :stop],
[:snakepit, :python, :call, :exception]
]
@doc """
Attaches the runtime forwarder to Snakepit events.
Returns `:ok` on success or `{:error, :already_exists}` if already attached.
"""
@spec attach() :: :ok | {:error, :already_exists}
def attach do
:telemetry.attach_many(
@handler_id,
@events,
&__MODULE__.handle_event/4,
%{}
)
end
@doc """
Detaches the runtime forwarder.
"""
@spec detach() :: :ok | {:error, :not_found}
def detach do
:telemetry.detach(@handler_id)
end
@doc false
def handle_event([:snakepit, :python, :call, :start], measurements, metadata, _config) do
enriched = enrich_metadata(metadata)
:telemetry.execute(
[:snakebridge, :runtime, :call, :start],
measurements,
enriched
)
end
def handle_event([:snakepit, :python, :call, :stop], measurements, metadata, _config) do
enriched = enrich_metadata(metadata)
:telemetry.execute(
[:snakebridge, :runtime, :call, :stop],
measurements,
enriched
)
end
def handle_event([:snakepit, :python, :call, :exception], measurements, metadata, _config) do
enriched = enrich_metadata(metadata)
:telemetry.execute(
[:snakebridge, :runtime, :call, :exception],
measurements,
enriched
)
end
defp enrich_metadata(metadata) do
library =
Map.get(metadata, :library) || Map.get(metadata, :snakebridge_library) ||
Map.get(metadata, :python_module)
function = Map.get(metadata, :function) || Map.get(metadata, :name)
call_type = Map.get(metadata, :call_type) || Map.get(metadata, :type)
metadata
|> Map.put(:library, library || "unknown")
|> Map.put(:function, function || "unknown")
|> Map.put(:call_type, call_type || "unknown")
|> Map.put(:snakebridge_library, library || "unknown")
|> Map.put(:snakebridge_version, version())
end
defp version do
Application.spec(:snakebridge, :vsn) |> to_string()
end
end