टेलीमेट्री

ADK-Rust adk-telemetry क्रेट के माध्यम से प्रोडक्शन-ग्रेड ऑब्जर्वेबिलिटी प्रदान करता है, जो tracing इकोसिस्टम और OpenTelemetry का उपयोग करके संरचित लॉगिंग और वितरित ट्रेसिंग को एकीकृत करता है।

अवलोकन

टेलीमेट्री सिस्टम सक्षम बनाता है:

  • संरचित लॉगिंग: प्रासंगिक जानकारी के साथ समृद्ध, क्वेरी करने योग्य लॉग
  • वितरित ट्रेसिंग: एजेंट पदानुक्रम और सेवा सीमाओं में अनुरोधों को ट्रैक करें
  • OpenTelemetry एकीकरण: ऑब्जर्वेबिलिटी बैकएंड (Jaeger, Datadog, Honeycomb, आदि) पर ट्रेस निर्यात करें
  • स्वचालित संदर्भ प्रसार: सत्र, उपयोगकर्ता और आह्वान आईडी सभी ऑपरेशनों के माध्यम से प्रवाहित होते हैं
  • पूर्व-कॉन्फ़िगर किए गए स्पैन: सामान्य ADK ऑपरेशनों के लिए सहायक फ़ंक्शन

त्वरित शुरुआत

मूल कंसोल लॉगिंग

विकास और सरल डिप्लॉयमेंट के लिए, कंसोल लॉगिंग को इनिशियलाइज़ करें:

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(())
}

यह समझदार डिफॉल्ट्स के साथ stdout पर संरचित लॉगिंग को कॉन्फ़िगर करता है।

OpenTelemetry निर्यात

वितरित ट्रेसिंग के साथ प्रोडक्शन डिप्लॉयमेंट के लिए:

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(())
}

यह ट्रेस और मेट्रिक्स को एक OpenTelemetry कलेक्टर एंडपॉइंट पर निर्यात करता है।

कंपोजेबल लेयर (उन्नत)

यदि आपके पास पहले से ही एक tracing सब्सक्राइबर कॉन्फ़िगर है, तो वैश्विक सब्सक्राइबर को इनिशियलाइज़ करने के बजाय एक कंपोजेबल लेयर प्राप्त करने के लिए build_otlp_layer का उपयोग करें:

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();

लॉग स्तर

RUST_LOG एनवायरनमेंट वेरिएबल का उपयोग करके लॉगिंग वर्बोसिटी को नियंत्रित करें:

स्तरविवरणउपयोग का मामला
errorकेवल त्रुटियाँउत्पादन (न्यूनतम)
warnचेतावनी और त्रुटियाँउत्पादन (डिफ़ॉल्ट)
infoजानकारीपूर्ण संदेशविकास, स्टेजिंग
debugविस्तृत डीबगिंग जानकारीस्थानीय विकास
traceबहुत विस्तृत ट्रेसिंगगहन डीबगिंग

लॉग स्तर सेट करना

# 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

यदि RUST_LOG सेट नहीं है, तो टेलीमेट्री सिस्टम डिफ़ॉल्ट रूप से info स्तर पर होता है।

लॉगिंग मैक्रोज़

लॉगिंग के लिए मानक tracing मैक्रोज़ का उपयोग करें:

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");

संरचित फ़ील्ड

बेहतर फ़िल्टरिंग और विश्लेषण के लिए लॉग संदेशों में प्रासंगिक फ़ील्ड जोड़ें:

use adk_telemetry::info;

info!(
    agent.name = "customer_support",
    user.id = "user-456",
    session.id = "sess-789",
    invocation.id = "inv-abc",
    "Agent execution started"
);

ये फ़ील्ड आपके ऑब्ज़र्वेबिलिटी बैकएंड में क्वेरी करने योग्य बन जाते हैं।

इंस्ट्रूमेंटेशन

स्वचालित इंस्ट्रूमेंटेशन

फ़ंक्शंस के लिए स्वचालित रूप से स्पैन बनाने के लिए #[instrument] विशेषता का उपयोग करें:

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

संवेदनशील पैरामीटर छोड़ें

ट्रेस से संवेदनशील डेटा को बाहर करें:

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
}

कस्टम स्पैन नाम

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"
}

पूर्व-कॉन्फ़िगर किए गए स्पैन

ADK-Telemetry सामान्य ऑपरेशनों के लिए सहायक फ़ंक्शन प्रदान करता है:

एजेंट निष्पादन स्पैन

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

मॉडल कॉल स्पैन

use adk_telemetry::model_call_span;

let span = model_call_span("gemini-2.5-flash");
let _enter = span.enter();

// Model API call here

टूल निष्पादन स्पैन

use adk_telemetry::tool_execute_span;

let span = tool_execute_span("weather_tool");
let _enter = span.enter();

// Tool execution code here

कॉलबैक स्पैन

use adk_telemetry::callback_span;

let span = callback_span("before_model");
let _enter = span.enter();

// Callback logic here

संदर्भ विशेषताएँ जोड़ना

वर्तमान स्पैन में उपयोगकर्ता और सत्र संदर्भ जोड़ें:

use adk_telemetry::add_context_attributes;

add_context_attributes("user-456", "sess-789");

LLM टोकन उपयोग ट्रैकिंग

OpenTelemetry GenAI सिमेंटिक कन्वेंशन्स के साथ सभी LLM प्रदाताओं में टोकन खपत को ट्रैक करें। llm_generate_span पूर्व-घोषित gen_ai.usage.* फ़ील्ड के साथ एक स्पैन बनाता है, और प्रतिक्रिया आने के बाद record_llm_usage उन्हें पॉप्युलेट करता है:

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()
});

सभी ADK मॉडल प्रदाता (Gemini, OpenAI, Anthropic, Ollama, Bedrock, DeepSeek, Groq, Azure AI, और सभी OpenAI-संगत प्रदाता) हर generate_content कॉल पर स्वचालित रूप से टोकन उपयोग रिकॉर्ड करते हैं। किसी मैन्युअल इंस्ट्रूमेंटेशन की आवश्यकता नहीं है — ट्रैकिंग प्रदाता परत में निर्मित है।

रिकॉर्ड किए गए स्पैन फ़ील्ड OpenTelemetry GenAI कन्वेंशन्स का पालन करते हैं:

फ़ील्डविवरण
gen_ai.usage.input_tokensप्रॉम्प्ट / इनपुट टोकन गणना
gen_ai.usage.output_tokensपूर्णता / आउटपुट टोकन गणना
gen_ai.usage.total_tokensकुल टोकन गणना
gen_ai.usage.cache_read_tokensप्रॉम्प्ट कैश से पढ़े गए टोकन
gen_ai.usage.cache_creation_tokensकैश बनाने के लिए उपयोग किए गए टोकन
gen_ai.usage.thinking_tokensचेन-ऑफ-थॉट तर्क टोकन
gen_ai.usage.audio_input_tokensऑडियो इनपुट टोकन गणना
gen_ai.usage.audio_output_tokensऑडियो आउटपुट टोकन गणना

प्रदाता द्वारा रिपोर्ट किए जाने पर ही वैकल्पिक फ़ील्ड रिकॉर्ड किए जाते हैं (गैर-None)।

मैन्युअल स्पैन निर्माण

कस्टम इंस्ट्रूमेंटेशन के लिए, स्पैन मैन्युअल रूप से बनाएं:

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

स्पैन विशेषताएँ

विशेषताएँ गतिशील रूप से जोड़ें:

use adk_telemetry::Span;

let span = Span::current();
span.record("result.count", 42);
span.record("result.status", "success");

OpenTelemetry कॉन्फ़िगरेशन

OTLP एंडपॉइंट

OTLP एक्सपोर्टर ट्रेस को एक कलेक्टर एंडपॉइंट पर भेजता है:

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")?;

एक स्थानीय कलेक्टर चलाना

विकास के लिए, OTLP समर्थन के साथ Jaeger चलाएँ:

docker run -d --name jaeger \
  -p 4317:4317 \
  -p 16686:16686 \
  jaegertracing/all-in-one:latest

# View traces at http://localhost:16686

ट्रेस विज़ुअलाइज़ेशन

एक बार कॉन्फ़िगर होने के बाद, ट्रेस आपके ऑब्ज़र्वेबिलिटी बैकएंड में दिखाई देते हैं जो दिखाते हैं:

  • Agent निष्पादन पदानुक्रम
  • Model कॉल विलंबताएँ
  • Tool निष्पादन समय
  • त्रुटि प्रसार
  • संदर्भ प्रवाह (user ID, session ID, आदि)

ADK के साथ एकीकरण

जब telemetry सिस्टम इनिशियलाइज़ हो जाता है तो ADK-Rust घटक स्वचालित रूप से telemetry उत्सर्जित करते हैं:

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(())
}

agent, model, और tool ऑपरेशन स्वचालित रूप से संरचित logs और traces उत्सर्जित करेंगे।

Telemetry डेमो उदाहरण

स्थानीय रूप से telemetry सुविधा चयन को मान्य करें:

cargo check -p adk-telemetry --no-default-features
cargo check -p adk-telemetry --no-default-features --features otlp

वास्तविक मॉडल कॉल वाले पूर्ण telemetry उदाहरणों के लिए इस साइट में शामिल ADK-Rust Playground खोलें।

Tools में कस्टम Telemetry

कस्टम tools में telemetry जोड़ें:

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,
);

Callbacks में कस्टम Telemetry

callbacks में observability जोड़ें:

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()?;

प्रदर्शन संबंधी विचार

सैंपलिंग

उच्च-थ्रूपुट सिस्टम के लिए, trace sampling पर विचार करें:

// Note: Sampling configuration depends on your OpenTelemetry setup
// Configure sampling in your OTLP collector or backend

Async Spans

उचित span context सुनिश्चित करने के लिए async functions पर हमेशा #[instrument] का उपयोग करें:

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
}

Production में Log Level

overhead कम करने के लिए production में info या warn स्तर का उपयोग करें:

export RUST_LOG=warn,my_app=info

समस्या निवारण

कोई Logs दिखाई नहीं दे रहे हैं

  1. जाँच करें कि RUST_LOG environment variable सेट है
  2. सुनिश्चित करें कि किसी भी logging से पहले init_telemetry() को कॉल किया गया है
  3. सत्यापित करें कि telemetry केवल एक बार इनिशियलाइज़ किया गया है (आंतरिक रूप से Once का उपयोग करता है)

Traces निर्यात नहीं किए गए

  1. सत्यापित करें कि OTLP endpoint पहुँच योग्य है
  2. जाँच करें कि collector चल रहा है और कनेक्शन स्वीकार कर रहा है
  3. application exit से पहले shutdown_telemetry() को कॉल करें ताकि pending spans फ्लश हो जाएँ
  4. network/firewall समस्याओं की जाँच करें

Spans में संदर्भ गायब है

  1. async functions पर #[instrument] का उपयोग करें
  2. सुनिश्चित करें कि spans को let _enter = span.enter() के साथ दर्ज किया गया है
  3. operation की अवधि के लिए _enter guard को scope में रखें

सर्वोत्तम अभ्यास

  1. जल्दी इनिशियलाइज़ करें: main() की शुरुआत में init_telemetry() को कॉल करें
  2. संरचित फ़ील्ड का उपयोग करें: string interpolation के बजाय key-value pairs के साथ संदर्भ जोड़ें
  3. Async Functions को इंस्ट्रूमेंट करें: async functions पर हमेशा #[instrument] का उपयोग करें
  4. निकास पर फ्लश करें: application termination से पहले shutdown_telemetry() को कॉल करें
  5. उपयुक्त Log Levels: महत्वपूर्ण events के लिए info, विवरण के लिए debug का उपयोग करें
  6. संवेदनशील डेटा से बचें: #[instrument(skip(...))] के साथ संवेदनशील parameters को छोड़ दें
  7. सुसंगत नामकरण: सुसंगत field names का उपयोग करें (उदाहरण के लिए, user.id, session.id)
  • Callbacks - callbacks में telemetry जोड़ें
  • Tools - कस्टम tools को इंस्ट्रूमेंट करें
  • Deployment - Production telemetry सेटअप

पिछला: ← Events | अगला: Launcher →