[otel] RustでOpenTelemetryを使う
LT会の写し書きです.
- botcast-worker でスクリプト内の引数やOpenAI APIの所要時間等を知りたい
- 方法としてOpenTelemetryを利用した
- RustでOpenTelemetryを使う方法を紹介
log crate
- Rustでは
logcrateを使ってロギングを行う- I/Fと実装は分かれている(I/F:
logcrate, 実装:env_loggercrate,ferncrate 等)
- I/Fと実装は分かれている(I/F:
fn say_hello(id: u32) {
log::info!("Hello, {}", id); // Event
}
fn main() {
env_logger::init(); // 初期化
say_hello(123); // 使用
}
tracing crate
- コンテキスト(HTTPリクエスト情報等)を含むロギングは tracing crateを使う
Span: 処理を含む期間でコンテキスト情報を持てるEvent:Spanに記録するトレースしたい事象Subscriber:SpanとEventを収集する処理
#[tracing::instrument(skip(key))] // Span: say_hello
fn say_hello(key: &str, id: u32) {
tracing::info!("Hello, {} key={}", id, key); // Event
}
fn main() {
tracing_subscriber::fmt().init(); // 初期化
say_hello("secret", 123); // 使用
}
OpenTelemetry概要
Observability
- システムを調査するには、アプリケーションが適切にinstrumentedされている必要がある。
- instrumentedされている: アプリケーションがSignals(traces, metrics, logs等)を発していること
- → 問題発生時にアプリケーションに追加の変更を加えることなく調査が可能になる。
- なぜなら、調査に必要な情報は全て収集されているから。
OpenTelemetry
- OpenTelemetryとは、アプリケーションをinstrumentedにするための仕組み。
- プログラミング言語に依存しない仕様、言語ごとのSDK
- OpenTelemetryは4つのSignalsから成る
- Traces ←今回の話題
- Metrics
- Logs
- Baggage
構成
- app: OpenTelemetry Collector(
otel-collector:4317)にトレース情報を送る - opentelemetry-collector:
:4317でappからトレース情報を受け取り、jaeger(jaeger:5000) に送信する - jaeger: 可視化バックエンド
compose.yaml
services:
jaeger:
image: "jaegertracing/all-in-one:latest"
ports:
- "5000:5000" # gRPC server
- "16686:16686" # Web UI
command:
# ref: https://zenn.dev/hkdord/articles/oss-reading-jaeger
- "--collector.otlp.grpc.host-port=5000"
otel-collector:
image: otel/opentelemetry-collector:latest
command: ["--config=/etc/otel-collector-config.yaml", ""]
ports:
- "4317:4317"
otel-collector-config.yaml
receivers:
otlp:
protocols:
grpc:
# ref: https://github.com/open-telemetry/opentelemetry-rust/issues/861#issuecomment-2408304710
endpoint: 0.0.0.0:4317
exporters:
otlp:
endpoint: jaeger:5000
processors:
batch:
service:
pipelines:
traces:
receivers: [otlp]
processors: [batch]
exporters: [otlp, debug]
アプリ側の設定
fn init_tracing(otlp_collector_endpoint: String) -> anyhow::Result<()> {
let subscriber = tracing_subscriber::registry();
let exporter = opentelemetry_otlp::SpanExporter::builder()
.with_tonic()
.with_endpoint(otlp_collector_endpoint)
.build()?;
let tracer_provider = TracerProvider::builder()
.with_batch_exporter(exporter, Tokio)
.with_resource(Resource::new(vec![KeyValue::new(
"service.name",
crate_name.to_string(),
)]))
.build();
let otel_layer = OpenTelemetryLayer::new(tracer_provider.tracer("worker"));
let subscriber = subscriber
.with(otel_layer)
.with(EnvFilter::from_str(&format!("info,{}=trace", crate_name))?);
let fmt_layer = tracing_subscriber::fmt::layer().pretty();
let subscriber = subscriber.with(fmt_layer);
tracing::subscriber::set_global_default(subscriber)?;
Ok(())
}
結果


まとめ
- RustでOpenTelemetryを使う方法を紹介した
- LangfuseにもLLMのトレースを行う機能 (Ingestion API) があり、OTelとの互換性等は未調査