テレメトリー
ADK-Rust は、tracing エコシステムと OpenTelemetry を使用して構造化されたロギングと分散トレーシングを統合する adk-telemetry クレートを通じて、本番環境レベルの可観測性を提供します。
概要
テレメトリーシステムは以下を可能にします。
- 構造化ロギング: コンテキスト情報を含む、リッチでクエリ可能なログ
- 分散トレーシング: agent 階層とサービス境界を越えたリクエストの追跡
- OpenTelemetry Integration: 可観測性バックエンド (Jaeger, Datadog, Honeycomb など) へのトレースのエクスポート
- Automatic Context Propagation: Session、user、invocation ID がすべての操作を流れる
- Pre-configured Spans: 一般的な 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(())
}
これにより、構造化ロギングが sensible defaults で標準出力に設定されます。
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 コレクターのエンドポイントにエクスポートされます。
ログレベル
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
}
// "process_request"という名前のスパンを作成し、user_idとmessageをフィールドとして含めます
機密パラメータのスキップ
トレースから機密データを除外します。
use adk_telemetry::instrument;
#[instrument(skip(api_key))]
async fn call_external_api(api_key: &str, query: &str) {
// api_keyはトレースに表示されません
}
カスタムスパン名
use adk_telemetry::instrument;
#[instrument(name = "external_api_call")]
async fn fetch_data(url: &str) {
// スパンは"fetch_data"の代わりに"external_api_call"という名前になります
}
事前設定されたスパン
ADK-Telemetryは、一般的な操作のためのヘルパー関数を提供します。
Agent実行スパン
use adk_telemetry::agent_run_span;
let span = agent_run_span("my_agent", "inv-123");
let _enter = span.enter();
// ここにAgentの実行コード
// このスコープ内のすべてのログはスパンコンテキストを継承します
モデル呼び出しスパン
use adk_telemetry::model_call_span;
let span = model_call_span("gemini-2.0-flash");
let _enter = span.enter();
// ここにモデルAPI呼び出し
ツール実行スパン
use adk_telemetry::tool_execute_span;
let span = tool_execute_span("weather_tool");
let _enter = span.enter();
// ここにツールの実行コード
コールバックスパン
use adk_telemetry::callback_span;
let span = callback_span("before_model");
let _enter = span.enter();
// ここにコールバックロジック
コンテキスト属性の追加
現在のスパンにユーザーおよびセッションのコンテキストを追加します。
use adk_telemetry::add_context_attributes;
add_context_attributes("user-456", "sess-789");
手動スパン作成
カスタム計測の場合、スパンを手動で作成します。
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");
// ここに操作コード
スパン属性
属性を動的に追加します。
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
# http://localhost:16686でトレースを表示
トレースの可視化
設定が完了すると、トレースはオブザーバビリティバックエンドに次のように表示されます。
- Agentの実行階層
- モデル呼び出しのレイテンシ
- ツールの実行タイミング
- エラー伝播
- コンテキストフロー (ユーザーID、セッションIDなど)
ADKとの統合
テレメトリーシステムが初期化されると、adk-rustコンポーネントは自動的にテレメトリーを出力します。
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の操作は、構造化されたログとトレースを自動的に出力します。
Toolにおけるカスタムテレメトリー
カスタムToolにテレメトリーを追加します。
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,
);
Callbackにおけるカスタムテレメトリー
Callbackに可観測性を追加します。
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()?;
パフォーマンスに関する考慮事項
サンプリング
高スループットシステムでは、トレースのサンプリングを検討してください。
// 注: サンプリング設定はOpenTelemetryのセットアップに依存します
// OTLPコレクターまたはバックエンドでサンプリングを設定してください
Asyncスパン
適切なスパンコンテキストを確保するために、async関数では常に#[instrument]を使用してください。
use adk_telemetry::instrument;
// ✅ 正しい - awaitポイントをまたいでスパンコンテキストが保持されます
#[instrument]
async fn async_operation() {
tokio::time::sleep(Duration::from_secs(1)).await;
}
// ❌ 不正確 - 手動スパンはコンテキストを失う可能性があります
async fn manual_span_operation() {
let span = tracing::info_span!("operation");
let _enter = span.enter();
tokio::time::sleep(Duration::from_secs(1)).await;
// await後にコンテキストが失われる可能性があります
}
本番環境でのログレベル
オーバーヘッドを削減するために、本番環境ではinfoまたはwarnレベルを使用してください。
export RUST_LOG=warn,my_app=info
トラブルシューティング
ログが表示されない
RUST_LOG環境変数が設定されているか確認してください- ロギングの前に
init_telemetry()が呼び出されていることを確認してください - テレメトリが一度だけ初期化されていることを確認してください (
Onceを内部的に使用しています)
トレースがエクスポートされない
- OTLP エンドポイントに到達可能か確認してください
- コレクタが実行中で接続を受け入れているか確認してください
- アプリケーション終了前に
shutdown_telemetry()を呼び出して、保留中のスパンをフラッシュしてください - ネットワーク/ファイアウォールの問題を確認してください
スパン内のコンテキストが欠落している
- async 関数で
#[instrument]を使用してください - スパンが
let _enter = span.enter()で入力されていることを確認してください - 操作の期間中、
_enterガードをスコープ内に保持してください
ベストプラクティス
- 早期初期化:
main()の開始時にinit_telemetry()を呼び出してください - 構造化フィールドの使用: 文字列補間ではなく、キーと値のペアでコンテキストを追加してください
- async 関数の計測: async 関数では常に
#[instrument]を使用してください - 終了時のフラッシュ: アプリケーション終了前に
shutdown_telemetry()を呼び出してください - 適切なログレベル: 重要なイベントには
infoを、詳細にはdebugを使用してください - 機密データの回避:
#[instrument(skip(...))]を使用して機密パラメーターをスキップしてください - 一貫した命名: 一貫したフィールド名 (例:
user.id、session.id) を使用してください
関連
- Callbacks - コールバックにテレメトリを追加する
- Tools - カスタムツールを計測する
- Deployment - 本番環境のテレメトリ設定
前へ: ← Events | 次へ: Launcher →