Télémétrie
ADK-Rust fournit une observabilitĂ© de niveau production via la crate adk-telemetry, qui intĂšgre la journalisation structurĂ©e et la traçabilitĂ© distribuĂ©e Ă lâaide de lâĂ©cosystĂšme tracing et de OpenTelemetry.
Vue dâensemble
Le systÚme de télémétrie permet :
- Journalisation structurée : journaux riches et interrogeables contenant des informations contextuelles
- TraçabilitĂ© distribuĂ©e : suivi des requĂȘtes Ă travers les hiĂ©rarchies dâagents et les frontiĂšres entre services
- IntĂ©gration OpenTelemetry : exportation des traces vers des backends dâobservabilitĂ© (Jaeger, Datadog, Honeycomb, etc.)
- Propagation automatique du contexte : les identifiants de session, dâutilisateur et dâinvocation sont transmis Ă travers toutes les opĂ©rations
- Spans prĂ©configurĂ©s : fonctions dâaide pour les opĂ©rations courantes de ADK
Démarrage rapide
Journalisation console de base
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(())
}
Cela configure la journalisation structurée vers stdout avec des valeurs par défaut adaptées.
Exportation OpenTelemetry
Pour les déploiements de production avec traçabilité distribuée :
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(())
}
Cela exporte les traces et les métriques vers un point de terminaison de collecteur OpenTelemetry.
Couche composable (avancé)
Si vous disposez dĂ©jĂ dâun subscriber tracing configurĂ©, utilisez build_otlp_layer pour obtenir une couche composable au lieu dâinitialiser un subscriber 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 le niveau de verbositĂ© de la journalisation Ă lâaide de la variable dâenvironnement RUST_LOG :
| Niveau | Description | Cas dâutilisation |
|---|---|---|
error | Erreurs uniquement | Production (minimal) |
warn | Avertissements et erreurs | Production (par défaut) |
info | Messages dâinformation | DĂ©veloppement, prĂ©production |
debug | Informations détaillées de débogage | Développement local |
trace | Traces trÚs verbeuses | Débogage approfondi |
Configuration des niveaux de journalisation
# 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
La journalisation dans la console utilise info par défaut si RUST_LOG n'est pas défini. La collecte des spans d'exécution configurée par init_with_adk_exporter est indépendante de ce filtre de console : RUST_LOG=warn conserve toujours les spans des agents, des modÚles, des outils et des équipes portables pour l'interface de télémétrie des sessions du serveur.
Télémétrie des sessions au sein du processus
Les serveurs peuvent exposer des traces sans infrastructure via l'interface utilisateur d'exécution intégrée :
let exporter = adk_telemetry::init_with_adk_exporter("my-agent")?;
let config = ServerConfig::new(agent_loader, session_service)
.with_span_exporter(exporter);
La réponse détaillée de l'agent conserve le booléen services.telemetry existant et ajoute services.telemetryStatus :
disabledâ aucun exportateur n'est configurĂ© ;configuredâ l'exportateur est prĂȘt, mais n'a conservĂ© aucun span pris en charge ;collectingâ au moins un span d'exĂ©cution pris en charge a Ă©tĂ© conservĂ©.
Appeler init_with_adk_exporter plusieurs fois renvoie le mĂȘme exportateur enregistrĂ©. Si un autre mode de tĂ©lĂ©mĂ©trie global a Ă©tĂ© initialisĂ© auparavant, une erreur exploitable est renvoyĂ©e au lieu d'un exportateur dĂ©connectĂ© qui ne pourra jamais recevoir de spans.
Macros de journalisation
Utilisez les macros tracing standard pour la journalisation :
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 journalisation pour améliorer le filtrage et l'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 peuvent ĂȘtre interrogĂ©s 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 spans 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 utilitaires pour les opérations courantes :
Span d'exécution de l'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 du modĂšle
use adk_telemetry::model_call_span;
let span = model_call_span("gemini-3.7-flash");
let _enter = span.enter();
// Model API call here
Span d'exécution de l'outil
use adk_telemetry::tool_execute_span;
let span = tool_execute_span("weather_tool");
let _enter = span.enter();
// Tool execution code here
Span de rappel
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 de l'utilisateur et de la session au span actuel :
use adk_telemetry::add_context_attributes;
add_context_attributes("user-456", "sess-789");
LLM Suivi de lâutilisation des jetons
Suivez la consommation de jetons sur tous les fournisseurs LLM avec les conventions sémantiques OpenTelemetry GenAI. Le llm_generate_span crée une étendue avec des champs gen_ai.usage.* prédéclarés, et record_llm_usage les renseigne aprÚs réception de la réponse :
use adk_telemetry::{llm_generate_span, record_llm_usage, LlmUsage};
let span = llm_generate_span("openai", "gpt-5.6-terra", 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 avec OpenAI) enregistrent automatiquement lâutilisation des jetons lors de chaque appel generate_content. Aucune instrumentation manuelle nâest nĂ©cessaire â le suivi est intĂ©grĂ© Ă la couche des fournisseurs.
Les champs dâĂ©tendue enregistrĂ©s suivent les conventions OpenTelemetry GenAI :
| Champ | Description |
|---|---|
gen_ai.usage.input_tokens | Nombre de jetons de lâ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 depuis le 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 la chaßne de pensée |
gen_ai.usage.audio_input_tokens | Nombre de tokens dâentrĂ©e audio |
gen_ai.usage.audio_output_tokens | Nombre de tokens de sortie audio |
Les champs facultatifs ne sont enregistrés que lorsque le fournisseur les signale (non-None).
Création manuelle de spans
Pour une instrumentation personnalisée, créez des 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 des spans
Ajoutez des attributs dynamiquement :
use adk_telemetry::Span;
let span = Span::current();
span.record("result.count", 42);
span.record("result.status", "success");
Configuration de 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 dâ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Ă© et affichent :
- HiĂ©rarchie dâexĂ©cution de lâagent
- Latences des appels au modĂšle
- Temps dâexĂ©cution des outils
- Propagation des erreurs
- Flux du 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-3.7-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 de lâagent, du modĂšle et des outils Ă©mettent automatiquement des journaux et des traces structurĂ©s.
Exemple de démonstration de télémétrie
Validez localement la sélection des fonctionnalités de télémétrie :
cargo check -p adk-telemetry --no-default-features
cargo check -p adk-telemetry --no-default-features --features otlp
Consultez le dépÎt adk-playground pour une démonstration complÚte de la télémétrie avec de véritables appels Gemini.
Télémétrie personnalisée dans les outils
Ajoutez de 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
Ajoutez de 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 relatives aux performances
Ă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 asynchrones afin de garantir 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 journalisation en production
Utilisez le niveau info ou warn en production afin de réduire la surcharge :
export RUST_LOG=warn,my_app=info
Résolution des problÚmes
Aucun journal nâapparaĂźt
- VĂ©rifiez que la variable dâenvironnement
RUST_LOGest définie - Assurez-vous que
init_telemetry()est appelé avant toute journalisation - Initialisez le mode global de télémétrie souhaité avant de construire le serveur
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 fin de lâapplication afin de vider les spans en attente - VĂ©rifiez les problĂšmes de rĂ©seau ou de pare-feu
Pour lâinterface utilisateur du runtime intĂ©grĂ©, vĂ©rifiez services.telemetryStatus. configured
signifie que lâexportateur est attachĂ©, mais que la session sĂ©lectionnĂ©e nâa pas produit de
span de runtime conservé ; collecting confirme que le collecteur a reçu les données.
Contexte manquant dans les spans
- Utilisez
#[instrument]sur les fonctions asynchrones - Assurez-vous que les spans sont activés avec
let _enter = span.enter() - Conservez la protection
_enterdans la portĂ©e pendant toute la durĂ©e de lâopĂ©ration
Bonnes pratiques
- Initialiser tĂŽt : appelez
init_telemetry()au dĂ©but demain() - Utiliser des champs structurĂ©s : ajoutez le contexte avec des paires clĂ©-valeur, plutĂŽt quâavec une interpolation de chaĂźnes
- Instrumenter les fonctions asynchrones : utilisez toujours
#[instrument]sur les fonctions asynchrones - Vider les données à la fin : appelez
shutdown_telemetry()avant lâarrĂȘt de lâapplication - Niveaux de journalisation appropriĂ©s : utilisez
infopour les Ă©vĂ©nements importants etdebugpour les dĂ©tails - Ăviter les donnĂ©es sensibles : ignorez les paramĂštres sensibles avec
#[instrument(skip(...))] - Nommage cohérent : utilisez des noms de champs cohérents (par exemple,
user.id,session.id)
Rubriques associées
- Télémétrie vers Google Cloud - Export direct vers Cloud Trace et journalisation Cloud JSON
- Rappels - Ajoutez de la télémétrie aux rappels
- Outils - Instrumentez les outils personnalisés
- Déploiement - Configuration de la télémétrie en production
PrĂ©cĂ©dent : â ĂvĂ©nements | Suivant : Lanceur â