use opentelemetry::trace::TraceContextExt;
use tracing::Span;
use tracing::field::Empty;
use tracing_opentelemetry::OpenTelemetrySpanExt;
use crate::telemetry::metrics;
use crate::usage::UsageRecord;
pub fn trace_id() -> Option<String> {
if !super::is_exporting() {
return None;
}
let context = Span::current().context();
let span_context = context.span().span_context().clone();
span_context
.is_valid()
.then(|| span_context.trace_id().to_string())
}
pub const ATTEMPT_OK: &str = "ok";
pub const ATTEMPT_ERROR: &str = "error";
pub const LEASE_SERVED: &str = "served";
pub const LEASE_RATE_LIMITED: &str = "rate_limited";
pub const LEASE_ERROR: &str = "error";
pub const LEASE_PARKED: &str = "parked";
pub fn upstream_attempt_span(
attempt: u32,
target_provider: &str,
target_model: &str,
credential_source: &'static str,
) -> Span {
tracing::info_span!(
target: "axond.upstream",
"axond.upstream.attempt",
axond.attempt = attempt,
axond.target.provider = target_provider,
axond.target.model = target_model,
axond.credential_source = credential_source,
axond.status = Empty,
axond.latency_ms = Empty,
axond.ttft_ms = Empty,
)
}
pub fn finish_upstream_attempt(
span: &Span,
status: &'static str,
latency_ms: u64,
ttft_ms: Option<u64>,
) {
span.record("axond.status", status);
span.record("axond.latency_ms", latency_ms);
if let Some(ttft_ms) = ttft_ms {
span.record("axond.ttft_ms", ttft_ms);
}
}
pub fn credential_lease_span(
credential_id: &str,
credential_source: &'static str,
index: usize,
) -> Span {
tracing::info_span!(
target: "axond.upstream",
"axond.credential.lease",
axond.credential.id = credential_id,
axond.credential_source = credential_source,
axond.credential.index = index,
axond.status = Empty,
)
}
pub fn finish_credential_lease(span: &Span, status: &'static str) {
span.record("axond.status", status);
}
pub const RELOAD_APPLIED: &str = "applied";
pub const RELOAD_REJECTED: &str = "rejected";
pub fn config_reload_span(trigger: &'static str) -> Span {
tracing::info_span!(
target: "axond.config",
"axond.config.reload",
axond.reload.trigger = trigger,
axond.reload.outcome = Empty,
axond.config.generation = Empty,
)
}
pub fn finish_config_reload(
span: &Span,
trigger: &'static str,
outcome: &'static str,
generation: u64,
) {
span.record("axond.reload.outcome", outcome);
span.record("axond.config.generation", generation);
metrics::record_config_reload(trigger, outcome, generation);
}
pub fn record_request(record: &UsageRecord, ttft_ms: Option<u64>, attempts: u32) {
let span = Span::current();
span.record("axond.request_id", record.request_id.as_str());
span.record("axond.namespace", record.namespace.as_str());
span.record("axond.subject", record.subject.as_str());
span.record("gen_ai.request.model", record.model.as_str());
span.record("axond.target.provider", record.target_provider.as_str());
span.record("axond.target.model", record.target_model.as_str());
span.record("axond.credential_source", record.credential_source);
span.record("axond.status", record.status.as_str());
span.record("axond.retry_count", attempts.saturating_sub(1));
span.record("gen_ai.usage.input_tokens", record.input_tokens);
span.record("gen_ai.usage.cache_read_tokens", record.cache_read_tokens);
span.record("gen_ai.usage.cache_write_tokens", record.cache_write_tokens);
span.record("gen_ai.usage.output_tokens", record.output_tokens);
span.record("axond.cost_microdollars", record.cost_microdollars);
span.record("axond.latency_ms", record.latency_ms);
if let Some(ttft_ms) = ttft_ms {
span.record("axond.ttft_ms", ttft_ms);
}
metrics::record_request(record, ttft_ms);
}
pub fn record_routing(
namespace: &str,
subject: &str,
alias: &str,
target_provider: &str,
target_model: &str,
credential_source: &'static str,
) {
let span = Span::current();
span.record("axond.namespace", namespace);
span.record("axond.subject", subject);
span.record("gen_ai.request.model", alias);
span.record("axond.target.provider", target_provider);
span.record("axond.target.model", target_model);
span.record("axond.credential_source", credential_source);
}
pub fn record_streamed(record: &UsageRecord, ttft_ms: Option<u64>) {
metrics::record_request(record, ttft_ms);
}