Télémétrie
ADK-Rust fournit une observabilité de qualité production via le crate adk-telemetry, qui intÚgre la journalisation structurée et le traçage distribué en utilisant l'écosystÚme tracing et OpenTelemetry.
Aperçu
Le systÚme de télémétrie permet :
- Journalisation Structurée : Des journaux riches et interrogeables avec des informations contextuelles
- Traçage DistribuĂ© : Suivre les requĂȘtes Ă travers les hiĂ©rarchies d'agents et les limites de service
- Intégration OpenTelemetry : Exporter les traces vers des backends d'observabilité (Jaeger, Datadog, Honeycomb, etc.)
- Propagation Automatique du Contexte : Les ID de session, d'utilisateur et d'invocation circulent à travers toutes les opérations
- Spans Préconfigurés : Fonctions d'aide pour les opérations ADK courantes
Démarrage Rapide
Journalisation Console Basique
Pour le développement et les déploiements simples, initialisez la journalisation console :
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(())
}
Ceci configure la journalisation structurée vers stdout avec des valeurs par défaut raisonnables.
Exportation OpenTelemetry
Pour les déploiements de production avec traçage distribué :
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(())
}
Ceci exporte les traces et les métriques vers un point de terminaison de collecteur OpenTelemetry.
Couche Composable (Avancé)
Si vous avez déjà un abonné tracing configuré, utilisez build_otlp_layer pour obtenir une couche composable au lieu d'initialiser un abonné global :
use adk_telemetry::build_otlp_layer;
use tracing_subscriber::{layer::SubscriberExt, util::SubscriberInitExt};
let otlp_layer = build_otlp_layer("my-agent", "http://localhost:4317")?;
tracing_subscriber::registry()
.with(otlp_layer)
.with(tracing_subscriber::fmt::layer())
.init();
Niveaux de Journalisation
ContrÎlez la verbosité de la journalisation en utilisant la variable d'environnement RUST_LOG :
| Niveau | Description | Cas d'Utilisation |
|---|---|---|
error | Seulement les erreurs | Production (minimale) |
warn | Avertissements et erreurs | Production (par défaut) |
info | Messages d'information | Développement, staging |
debug | Informations de débogage détaillées | Développement local |
trace | Traçage trÚs verbeux | Débogage approfondi |
Définition des Niveaux de Log
# 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
Le systÚme de télémétrie utilise par défaut le niveau info si RUST_LOG n'est pas défini.
Macros de Log
Utilisez les macros standards tracing pour le logging :
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");
Champs Structurés
Ajoutez des champs contextuels aux messages de log pour un meilleur filtrage et une meilleure analyse :
use adk_telemetry::info;
info!(
agent.name = "customer_support",
user.id = "user-456",
session.id = "sess-789",
invocation.id = "inv-abc",
"Agent execution started"
);
Ces champs deviennent interrogeables dans votre backend d'observabilité.
Instrumentation
Instrumentation Automatique
Utilisez l'attribut #[instrument] pour créer automatiquement des spans pour les fonctions :
use adk_telemetry::{instrument, info};
#[instrument]
async fn process_request(user_id: &str, message: &str) {
info!("Processing request");
// Function logic here
}
// Creates a span named "process_request" with user_id and message as fields
Ignorer les ParamĂštres Sensibles
Excluez les données sensibles des traces :
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
}
Noms de Span Personnalisés
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 Préconfigurés
ADK-Telemetry fournit des fonctions d'assistance pour les opérations courantes :
Span d'Exécution d'Agent
use adk_telemetry::agent_run_span;
let span = agent_run_span("my_agent", "inv-123");
let _enter = span.enter();
// Agent execution code here
// All logs within this scope inherit the span context
Span d'Appel de ModĂšle
use adk_telemetry::model_call_span;
let span = model_call_span("gemini-2.5-flash");
let _enter = span.enter();
// Model API call here
Span d'Exécution d'Outil
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
Ajout d'Attributs de Contexte
Ajoutez le contexte utilisateur et de session au span actuel :
use adk_telemetry::add_context_attributes;
add_context_attributes("user-456", "sess-789");
Suivi de l'Utilisation des Tokens LLM
Suivez la consommation de jetons de tous les fournisseurs LLM avec les conventions sémantiques OpenTelemetry GenAI. Le llm_generate_span crée une portée (span) avec des champs gen_ai.usage.* prédéclarés, et record_llm_usage les remplit aprÚs l'arrivée de la réponse :
use adk_telemetry::{llm_generate_span, record_llm_usage, LlmUsage};
let span = llm_generate_span("openai", "gpt-5-mini", true);
let _enter = span.enter();
// After receiving the LLM response with usage metadata:
record_llm_usage(&LlmUsage {
input_tokens: 100,
output_tokens: 50,
total_tokens: 150,
cache_read_tokens: Some(80),
..Default::default()
});
Tous les fournisseurs de modĂšles ADK (Gemini, OpenAI, Anthropic, Ollama, Bedrock, DeepSeek, Groq, Azure AI et tous les fournisseurs compatibles OpenAI) enregistrent automatiquement l'utilisation des jetons Ă chaque appel de generate_content. Aucune instrumentation manuelle n'est nĂ©cessaire â le suivi est intĂ©grĂ© Ă la couche du fournisseur.
Les champs de portée (span) enregistrés suivent les conventions OpenTelemetry GenAI :
| Champ | Description |
|---|---|
gen_ai.usage.input_tokens | Nombre de jetons d'invite / d'entrée |
gen_ai.usage.output_tokens | Nombre de jetons de complétion / de sortie |
gen_ai.usage.total_tokens | Nombre total de jetons |
gen_ai.usage.cache_read_tokens | Jetons lus du cache d'invite |
gen_ai.usage.cache_creation_tokens | Jetons utilisés pour créer le cache |
gen_ai.usage.thinking_tokens | Jetons de raisonnement de chaßne de pensée |
gen_ai.usage.audio_input_tokens | Nombre de jetons d'entrée audio |
gen_ai.usage.audio_output_tokens | Nombre de jetons de sortie audio |
Les champs optionnels ne sont enregistrés que lorsque le fournisseur les signale (non-None).
Création manuelle de portées (spans)
Pour une instrumentation personnalisée, créez des portées (spans) manuellement :
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
Attributs de portée (span)
Ajoutez des attributs dynamiquement :
use adk_telemetry::Span;
let span = Span::current();
span.record("result.count", 42);
span.record("result.status", "success");
Configuration OpenTelemetry
Point de terminaison OTLP
L'exportateur OTLP envoie les traces Ă un point de terminaison de collecteur :
use adk_telemetry::init_with_otlp;
// Local Jaeger (default OTLP port)
init_with_otlp("my-service", "http://localhost:4317")?;
// Cloud provider endpoint
init_with_otlp("my-service", "https://otlp.example.com:4317")?;
Exécution d'un collecteur local
Pour le développement, exécutez Jaeger avec la prise en charge OTLP :
docker run -d --name jaeger \
-p 4317:4317 \
-p 16686:16686 \
jaegertracing/all-in-one:latest
# View traces at http://localhost:16686
Visualisation des traces
Une fois configurées, les traces apparaissent dans votre backend d'observabilité, montrant :
- Hiérarchie d'exécution de l'Agent
- Latences d'appel du modĂšle
- Chronométrage de l'exécution de l'outil
- Propagation des erreurs
- Flux de contexte (ID utilisateur, ID de session, etc.)
Intégration avec ADK
Les composants ADK-Rust émettent automatiquement des données de télémétrie lorsque le systÚme de télémétrie est initialisé :
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(())
}
Les opérations d'Agent, de modÚle et d'outil émettront automatiquement des logs et des traces structurés.
Exemple de démonstration de télémétrie
Valider la sélection des fonctionnalités de télémétrie localement :
cargo check -p adk-telemetry --no-default-features
cargo check -p adk-telemetry --no-default-features --features otlp
Ouvrez l'ADK-Rust Playground intégré pour des exemples complets de télémétrie avec de vrais appels de modÚles.
Télémétrie personnalisée dans les Tools
Ajouter la télémétrie aux outils personnalisés :
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,
);
Télémétrie personnalisée dans les Callbacks
Ajouter l'observabilité aux 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()?;
Considérations de performance
Ăchantillonnage
Pour les systÚmes à haut débit, envisagez l'échantillonnage des traces :
// Note: Sampling configuration depends on your OpenTelemetry setup
// Configure sampling in your OTLP collector or backend
Spans asynchrones
Utilisez toujours #[instrument] sur les fonctions async pour assurer un contexte de span approprié :
use adk_telemetry::instrument;
// â
Correct - span context preserved across await points
#[instrument]
async fn async_operation() {
tokio::time::sleep(Duration::from_secs(1)).await;
}
// â Incorrect - manual span may lose context
async fn manual_span_operation() {
let span = tracing::info_span!("operation");
let _enter = span.enter();
tokio::time::sleep(Duration::from_secs(1)).await;
// Context may be lost after await
}
Niveau de log en production
Utilisez le niveau info ou warn en production pour réduire la surcharge :
export RUST_LOG=warn,my_app=info
Dépannage
Aucun log n'apparaĂźt
- Vérifiez que la variable d'environnement
RUST_LOGest définie - Assurez-vous que
init_telemetry()est appelé avant toute journalisation - Vérifiez que la télémétrie est initialisée une seule fois (utilise
Onceen interne)
Traces non exportées
- Vérifiez que le point de terminaison OTLP est accessible
- Vérifiez que le collecteur est en cours d'exécution et accepte les connexions
- Appelez
shutdown_telemetry()avant la sortie de l'application pour vider les spans en attente - Vérifiez les problÚmes de réseau/pare-feu
Contexte manquant dans les Spans
- Utiliser
#[instrument]sur les fonctions async - S'assurer que les spans sont entrés avec
let _enter = span.enter() - Garder le
_enterguard dans la portée pour la durée de l'opération
Bonnes Pratiques
- Initialiser TĂŽt : Appeler
init_telemetry()au début demain() - Utiliser des Champs Structurés : Ajouter du contexte avec des paires clé-valeur, pas d'interpolation de chaßne
- Instrumenter les Fonctions Async : Toujours utiliser
#[instrument]sur les fonctions async - Vider Ă la Sortie : Appeler
shutdown_telemetry()avant la terminaison de l'application - Niveaux de Log Appropriés : Utiliser
infopour les Ă©vĂ©nements importants,debugpour les dĂ©tails - Ăviter les DonnĂ©es Sensibles : Ignorer les paramĂštres sensibles avec
#[instrument(skip(...))] - Nommage Cohérent : Utiliser des noms de champs cohérents (par exemple,
user.id,session.id)
Articles Connexes
- Callbacks - Ajouter de la télémétrie aux rappels
- Tools - Instrumenter les outils personnalisés
- Deployment - Configuration de la télémétrie de production
PrĂ©cĂ©dent : â Events | Suivant : Launcher â