// Copyright (c) 2026 Yingjie Shang
// agent-telemetry is licensed under Mulan PSL v2.
///| Internal instrument constructors
///|
fn get_gen_ai_operation_duration_histogram(
meter : @metrics.Meter,
) -> @metrics.Histogram[Double] {
meter
.f64_histogram("gen_ai.client.operation.duration")
.with_description("GenAI client operation duration")
.with_unit("s")
.build()
}
///|
fn get_gen_ai_token_usage_histogram(
meter : @metrics.Meter,
) -> @metrics.Histogram[UInt64] {
meter
.u64_histogram("gen_ai.client.token.usage")
.with_description("Number of input and output tokens used")
.with_unit("{token}")
.build()
}
///|
fn get_tool_calls_counter(meter : @metrics.Meter) -> @metrics.Counter[UInt64] {
meter
.u64_counter("agent.tool.calls_total")
.with_description("Total number of tool executions")
.with_unit("1")
.build()
}
///|
fn get_turn_total_counter(meter : @metrics.Meter) -> @metrics.Counter[UInt64] {
meter
.u64_counter("agent.turn.total")
.with_description("Total number of agent turns")
.with_unit("1")
.build()
}
///| Public metric functions
///|
/// Record the duration of one GenAI chat operation in seconds.
pub fn record_llm_latency(
meter : @metrics.Meter,
provider_name : String,
model : String,
seconds~ : Double,
) -> Unit {
get_gen_ai_operation_duration_histogram(meter).record(seconds, attributes=[
@common.KeyValue::new("gen_ai.operation.name", String("chat")),
@common.KeyValue::new("gen_ai.provider.name", String(provider_name)),
@common.KeyValue::new("gen_ai.request.model", String(model)),
])
}
///|
/// Record token usage for one GenAI chat operation.
pub fn record_usage(
meter : @metrics.Meter,
provider_name : String,
model : String,
token_type : String,
value : Int64,
) -> Unit {
let tokens = if value < 0L { 0UL } else { value.reinterpret_as_uint64() }
get_gen_ai_token_usage_histogram(meter).record(tokens, attributes=[
@common.KeyValue::new("gen_ai.operation.name", String("chat")),
@common.KeyValue::new("gen_ai.provider.name", String(provider_name)),
@common.KeyValue::new("gen_ai.request.model", String(model)),
@common.KeyValue::new("gen_ai.token.type", String(token_type)),
])
}
///|
/// Record one tool execution.
pub fn record_tool_call(
meter : @metrics.Meter,
tool_name : String,
success~ : Bool,
) -> Unit {
get_tool_calls_counter(meter).add(1UL, attributes=[
@common.KeyValue::new("gen_ai.tool.name", String(tool_name)),
@common.KeyValue::new("success", String(success.to_string())),
])
}
///|
/// Record one completed agent turn.
pub fn record_turn(
meter : @metrics.Meter,
max_tool_turns_reached~ : Bool,
) -> Unit {
get_turn_total_counter(meter).add(1UL, attributes=[
@common.KeyValue::new(
"max_tool_turns_reached",
String(max_tool_turns_reached.to_string()),
),
])
}
///|
/// Record the duration of one GenAI agent invocation in seconds.
///
/// Metric: `gen_ai.invoke_agent.duration` (Histogram, unit="s")
pub fn record_agent_duration(
meter : @metrics.Meter,
agent_name : String,
/// Duration in seconds.
seconds~ : Double,
) -> Unit {
meter
.f64_histogram("gen_ai.invoke_agent.duration")
.with_description(
"The end-to-end duration of a single in-process agent invocation",
)
.with_unit("s")
.build()
.record(seconds, attributes=[
@common.KeyValue::new("gen_ai.agent.name", String(agent_name)),
])
}
///|
/// Record the duration of one GenAI tool execution in seconds.
///
/// Metric: `gen_ai.execute_tool.duration` (Histogram, unit="s")
pub fn record_tool_duration(
meter : @metrics.Meter,
tool_name : String,
/// Duration in seconds.
seconds~ : Double,
) -> Unit {
meter
.f64_histogram("gen_ai.execute_tool.duration")
.with_description("The duration of a single tool execution")
.with_unit("s")
.build()
.record(seconds, attributes=[
@common.KeyValue::new("gen_ai.tool.name", String(tool_name)),
])
}