AshBaml.Telemetry (ash_baml v0.2.0)
View SourceTelemetry integration for AshBaml.
Provides observability into BAML function calls through Elixir's
:telemetry ecosystem. Integrates with baml_elixir's collector
API to track token usage, performance, and execution details.
Events
This module emits three telemetry events per BAML function call:
[:ash_baml, :call, :start]- Before function execution[:ash_baml, :call, :stop]- After successful execution[:ash_baml, :call, :exception]- On error
Event names can be customized via the prefix DSL option.
Measurements
:start event
%{
system_time: System.system_time(),
monotonic_time: System.monotonic_time()
}:stop event
%{
duration: native_time, # Time elapsed
input_tokens: 150, # From collector
output_tokens: 75, # From collector
total_tokens: 225, # Sum of input + output
monotonic_time: System.monotonic_time()
}:exception event
%{
duration: native_time,
monotonic_time: System.monotonic_time()
}Metadata
All events include standard metadata:
%{
resource: MyApp.Assistant,
action: :chat,
function_name: "ChatAgent",
collector_name: "MyApp.Assistant-ChatAgent-12345"
}The :stop event additionally includes observability metadata:
%{
model_name: "gpt-4",
provider: "openai",
client_name: "GPT4Client",
num_attempts: 1,
request_id: "req_abc123",
raw_response: "The capital of France is Paris.",
tags: %{"environment" => "production"},
log_type: "call",
http_request: %{
url: "https://api.openai.com/v1/chat/completions",
method: "POST",
headers: %{"content-type" => "application/json"},
body: "{...}"
},
http_response: %{
status_code: 200,
headers: %{"content-type" => "application/json"},
body: "{...}"
}
}Additional metadata can be configured via the DSL.
Privacy
By default, only safe, aggregate data is included:
- Token counts
- Timing information
- Resource/action/function names
Sensitive data (prompts, responses, arguments) is NEVER included without explicit configuration.
Performance
When telemetry is disabled (default), this module has near-zero overhead through early return checks. When enabled, overhead is minimal (~10µs per call for collector creation and usage reading).
Example
:telemetry.attach(
"log-token-usage",
[:ash_baml, :call, :stop],
fn _event, measurements, metadata, _config ->
Logger.info("BAML call completed",
function: metadata.function_name,
tokens: measurements.total_tokens,
duration_ms: System.convert_time_unit(
measurements.duration,
:native,
:millisecond
)
)
end,
nil
)
Summary
Functions
Wraps a BAML function call with telemetry.
Functions
Wraps a BAML function call with telemetry.
Emits :start, :stop, and :exception events with measurements
and metadata. Creates a BamlElixir.Collector to track token usage
and execution details.
Arguments
input- The Ash action input containing resource, action, and argumentsfunction_name- The BAML function name (atom)config- Telemetry configuration (from DSL)func- Function to wrap (receives collector options)
Returns
Returns a tuple {result, collector} where result is {:ok, term()} or
{:error, term()} from the function call, and collector is the
BamlElixir.Collector reference used for the call.
Examples
{result, collector} = AshBaml.Telemetry.with_telemetry(
input,
:ChatAgent,
config,
fn collector_opts ->
ClientModule.ChatAgent.call(args, collector_opts)
end
)