Telemetría
ADK-Rust proporciona observabilidad de nivel de producción a través de la crate adk-telemetry, que integra el registro estructurado (structured logging) y el rastreo distribuido (distributed tracing) utilizando el ecosistema tracing y OpenTelemetry.
Resumen
El sistema de telemetría permite:
- Registro Estructurado (
Structured Logging): Registros ricos y consultables con información contextual - Rastreo Distribuido (
Distributed Tracing): Rastrea solicitudes a través de jerarquías de Agent y límites de servicio - Integración con OpenTelemetry: Exporta trazas a backends de observabilidad (Jaeger, Datadog, Honeycomb, etc.)
- Propagación Automática de Contexto: Los ID de Session, usuario e invocación fluyen a través de todas las operaciones
- Spans Preconfigurados: Funciones de ayuda para operaciones comunes de ADK
Inicio Rápido
Registro Básico en Consola
Para desarrollo y despliegues sencillos, inicialice el registro en consola:
use adk_telemetry::init_telemetry;
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
// Initialize telemetry with your service name
init_telemetry("my-agent-service")?;
// Your agent code here
Ok(())
}
Esto configura el registro estructurado (structured logging) a stdout con valores predeterminados sensatos.
Exportación OpenTelemetry
Para despliegues en producción con rastreo distribuido (distributed tracing):
use adk_telemetry::init_with_otlp;
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
// Initialize with OTLP exporter
init_with_otlp("my-agent-service", "http://localhost:4317")?;
// Your agent code here
// Flush traces before exit
adk_telemetry::shutdown_telemetry();
Ok(())
}
Esto exporta trazas y métricas a un punto final del recopilador de OpenTelemetry.
Niveles de Registro
Controle la verbosidad del registro utilizando la variable de entorno RUST_LOG:
| Nivel | Descripción | Caso de Uso |
|---|---|---|
error | Solo errores | Producción (mínimo) |
warn | Advertencias y errores | Producción (predeterminado) |
info | Mensajes informativos | Desarrollo, staging |
debug | Información de depuración detallada | Desarrollo local |
trace | Rastreo muy verboso | Depuración profunda |
Configuración de Niveles de Registro
# Set global log level
export RUST_LOG=info
# Set per-module log levels
export RUST_LOG=adk_agent=debug,adk_model=info
# Combine global and module-specific levels
export RUST_LOG=warn,adk_agent=debug
El sistema de telemetría utiliza el nivel info por defecto si RUST_LOG no está configurado.
Macros de Registro
Utilice las macros estándar de tracing para el registro:
use adk_telemetry::{trace, debug, info, warn, error};
// Informational logging
info!("Agent started successfully");
// Structured logging with fields
info!(
agent.name = "my_agent",
session.id = "sess-123",
"Processing user request"
);
// Debug logging
debug!(user_input = ?input, "Received input");
// Warning and error logging
warn!("Rate limit approaching");
error!(error = ?err, "Failed to call model");
Campos Estructurados
Agregue campos contextuales a los mensajes de registro para una mejor filtrado y análisis:
use adk_telemetry::info;
info!(
agent.name = "customer_support",
user.id = "user-456",
session.id = "sess-789",
invocation.id = "inv-abc",
"Agent execution started"
);
Estos campos se vuelven consultables en su backend de observabilidad.
Instrumentación
Instrumentación Automática
Usa el atributo #[instrument] para crear automáticamente spans para funciones:
use adk_telemetry::{instrument, info};
#[instrument]
async fn process_request(user_id: &str, message: &str) {
info!("Processing request");
// Function logic here
}
// Crea un span llamado "process_request" con user_id y message como campos
Omitir Parámetros Sensibles
Excluye datos sensibles de los rastreos:
use adk_telemetry::instrument;
#[instrument(skip(api_key))]
async fn call_external_api(api_key: &str, query: &str) {
// api_key won't appear in traces
}
Nombres de Span Personalizados
use adk_telemetry::instrument;
#[instrument(name = "external_api_call")]
async fn fetch_data(url: &str) {
// Span will be named "external_api_call" instead of "fetch_data"
}
Spans Preconfigurados
ADK-Telemetry proporciona funciones auxiliares para operaciones comunes:
Span de Ejecución de Agent
use adk_telemetry::agent_run_span;
let span = agent_run_span("my_agent", "inv-123");
let _enter = span.enter();
// Agent execution code here
// Todos los logs dentro de este ámbito heredan el contexto del span
Span de Llamada a Model
use adk_telemetry::model_call_span;
let span = model_call_span("gemini-2.0-flash");
let _enter = span.enter();
// Model API call here
Span de Ejecución de Tool
use adk_telemetry::tool_execute_span;
let span = tool_execute_span("weather_tool");
let _enter = span.enter();
// Tool execution code here
Span de Callback
use adk_telemetry::callback_span;
let span = callback_span("before_model");
let _enter = span.enter();
// Callback logic here
Añadiendo Atributos de Contexto
Añade contexto de usuario y sesión al span actual:
use adk_telemetry::add_context_attributes;
add_context_attributes("user-456", "sess-789");
Creación Manual de Spans
Para instrumentación personalizada, crea spans manualmente:
use adk_telemetry::{info, Span};
let span = tracing::info_span!(
"custom_operation",
operation.type = "data_processing",
operation.id = "op-123"
);
let _enter = span.enter();
info!("Performing custom operation");
// Operation code here
Atributos de Span
Añade atributos dinámicamente:
use adk_telemetry::Span;
let span = Span::current();
span.record("result.count", 42);
span.record("result.status", "success");
Configuración de OpenTelemetry
Punto de Conexión OTLP
El exportador OTLP envía rastreos a un punto de conexión de colector:
use adk_telemetry::init_with_otlp;
// Local Jaeger (puerto OTLP predeterminado)
init_with_otlp("my-service", "http://localhost:4317")?;
// Punto de conexión del proveedor de la nube
init_with_otlp("my-service", "https://otlp.example.com:4317")?;
Ejecutando un Colector Local
Para desarrollo, ejecuta Jaeger con soporte OTLP:
docker run -d --name jaeger \
-p 4317:4317 \
-p 16686:16686 \
jaegertracing/all-in-one:latest
# View traces at http://localhost:16686
Visualización de Rastreo
Una vez configurado, los rastreos aparecen en tu backend de observabilidad mostrando:
- Jerarquía de ejecución de Agent
- Latencias de llamadas a Model
- Tiempos de ejecución de Tool
- Propagación de errores
- Flujo de contexto (ID de usuario, ID de sesión, etc.)
Integración con ADK
Los componentes de ADK-Rust emiten telemetría automáticamente cuando el sistema de telemetría se inicializa:
use adk_rust::prelude::*;
use adk_telemetry::init_telemetry;
use std::sync::Arc;
#[tokio::main]
async fn main() -> std::result::Result<(), Box<dyn std::error::Error>> {
// Initialize telemetry first
init_telemetry("my-agent-app")?;
let api_key = std::env::var("GOOGLE_API_KEY")?;
let model = Arc::new(GeminiModel::new(&api_key, "gemini-2.5-flash")?);
let agent = LlmAgentBuilder::new("support_agent")
.model(model)
.instruction("You are a helpful support agent.")
.build()?;
// Use Launcher for simple execution
Launcher::new(Arc::new(agent)).run().await?;
Ok(())
}
Las operaciones del Agent, model y Tool emitirán automáticamente registros y trazas estructurados.
Telemetría Personalizada en Tools
Añada telemetría a los tools personalizados:
use adk_rust::prelude::*;
use adk_telemetry::{info, instrument, tool_execute_span};
use serde_json::{json, Value};
#[instrument(skip(ctx))]
async fn weather_tool_impl(
ctx: Arc<dyn ToolContext>,
args: Value,
) -> Result<Value> {
let span = tool_execute_span("weather_tool");
let _enter = span.enter();
let location = args["location"].as_str().unwrap_or("unknown");
info!(location = location, "Fetching weather data");
// Tool logic here
let result = json!({
"temperature": 72,
"condition": "sunny"
});
info!(location = location, "Weather data retrieved");
Ok(result)
}
let weather_tool = FunctionTool::new(
"get_weather",
"Get current weather for a location",
json!({
"type": "object",
"properties": {
"location": {"type": "string"}
},
"required": ["location"]
}),
weather_tool_impl,
);
Telemetría Personalizada en Callbacks
Añada observabilidad a los callbacks:
use adk_rust::prelude::*;
use adk_telemetry::{info, callback_span};
use std::sync::Arc;
let agent = LlmAgentBuilder::new("observed_agent")
.model(model)
.before_callback(Box::new(|ctx| {
Box::pin(async move {
let span = callback_span("before_agent");
let _enter = span.enter();
info!(
agent.name = ctx.agent_name(),
user.id = ctx.user_id(),
session.id = ctx.session_id(),
"Agent execution starting"
);
Ok(None)
})
}))
.after_callback(Box::new(|ctx| {
Box::pin(async move {
let span = callback_span("after_agent");
let _enter = span.enter();
info!(
agent.name = ctx.agent_name(),
"Agent execution completed"
);
Ok(None)
})
}))
.build()?;
Consideraciones de Rendimiento
Muestreo
Para sistemas de alto rendimiento, considere el muestreo de trazas:
// Nota: La configuración de muestreo depende de su configuración de OpenTelemetry
// Configure el muestreo en su colector OTLP o backend
Spans Asíncronos
Siempre use #[instrument] en funciones async para asegurar un contexto de span adecuado:
use adk_telemetry::instrument;
// ✅ Correcto - el contexto del span se conserva en los puntos de await
#[instrument]
async fn async_operation() {
tokio::time::sleep(Duration::from_secs(1)).await;
}
// ❌ Incorrecto - el span manual puede perder el contexto
async fn manual_span_operation() {
let span = tracing::info_span!("operation");
let _enter = span.enter();
tokio::time::sleep(Duration::from_secs(1)).await;
// El contexto puede perderse después de await
}
Nivel de Log en Producción
Use el nivel info o warn en producción para reducir la sobrecarga:
export RUST_LOG=warn,my_app=info
Solución de problemas
No Aparecen Registros
- Verifique que la variable de entorno
RUST_LOGesté configurada - Asegúrese de que se llame a
init_telemetry()antes de cualquier registro - Verifique que la telemetría se inicialice solo una vez (internamente usa
Once)
Trazas No Exportadas
- Verifique que el endpoint OTLP sea alcanzable
- Verifique que el collector esté ejecutándose y aceptando conexiones
- Llame a
shutdown_telemetry()antes de la salida de la aplicación para vaciar las trazas pendientes - Verifique si hay problemas de red/firewall
Contexto Faltante en las Trazas
- Use
#[instrument]en funciones async - Asegúrese de que las trazas se inicien con
let _enter = span.enter() - Mantenga el guard
_enterdentro del ámbito durante la duración de la operación
Mejores Prácticas
- Inicializar Temprano: Llame a
init_telemetry()al inicio demain() - Usar Campos Estructurados: Agregue contexto con pares clave-valor, no interpolación de cadenas
- Instrumentar Funciones Async: Siempre use
#[instrument]en funciones async - Vaciar al Salir: Llame a
shutdown_telemetry()antes de la terminación de la aplicación - Niveles de Registro Apropiados: Use
infopara eventos importantes,debugpara detalles - Evitar Datos Sensibles: Omita parámetros sensibles con
#[instrument(skip(...))] - Nomenclatura Consistente: Use nombres de campo consistentes (ej.,
user.id,session.id)
Relacionado
- Callbacks - Agregue telemetría a los callbacks
- Tools - Instrumente herramientas personalizadas
- Deployment - Configuración de telemetría en producción
Anterior: ← Events | Siguiente: Launcher →