Sürüm: 1.0.0Bu dokümantasyon Spitfire 1.0.0 içindir.
Rust servisini OTel ile bağlamak
Rust derlenen bir dil ve ajanı yok: servise bir dosya ve birkaç satır ekleyip yeniden derlersiniz.
Servisin tracing span ve event'leri bundan sonra Spitfire'a trace ve log olarak, HTTP istekleri
metrik olarak gider; adresler ve token'lar diğer rehberlerdeki gibi ortamdan gelir. Değerler ve
genel kurallar: Servisleri OTel ile bağlamak: genel.
Sürüm tablosu
| Rust | Crate'ler | Not |
|---|---|---|
| 1.88 ve sonrası | opentelemetry, opentelemetry_sdk, opentelemetry-otlp, opentelemetry-http, opentelemetry-appender-tracing 0.33.1; tracing-opentelemetry 0.34.0; tracing 0.1.44, tracing-subscriber 0.3.23 |
OTel crate'leri 1.75 der, ama çektikleri crate'lerin güncel sürümleri Rust 1.88 ister (Rust 2024 edition, ICU crate'leri) |
| 1.87 ve öncesi | desteklenmiyor | Toolchain'i yükseltin (rustup update) |
Sürümünüzü bulun: derleme makinesinde rustc --version (ya da Cargo.toml'daki rust-version).
Aşağıdaki örnekler axum 0.8 içindir; başka bir framework'te 1. adımdaki middleware aynı şekilde
yazılır (istek başlıklarından traceparent'ı alın, span'i o parent ile açın).
Doğrulandı: 2026-11-03. Kaynak: Rust başlangıç belgesi, opentelemetry-otlp (özellikler, ortam değişkenleri), tracing-opentelemetry, crate sürümleri.
Gerekenler
- Spitfire adresi
https://<spitfire>ve OTLP alıcısı anahtarısfotlp_… - Tower adresi
http://<tower>:4318ve Collector token'ısfcol_… - Protokol
http/protobuf - Servis adı
<service-name>, sürümü<service-version>, ortamı<environment> - Özel CA varsa CA sertifikası makinenin (ya da image'ın) sistem güven deposunda
- Proxy varsa Tower ve Spitfire
NO_PROXYiçinde - Örnekleme
parentbased_traceidratio,0.1 - Servisin kaynak kodu ve derlendiği makine
Linux (systemd)
src/otel.rsdosyasını oluşturun, şunu yapıştırın:
use std::sync::OnceLock;
use axum::{extract::Request, middleware::Next, response::Response};
use opentelemetry::{global, metrics::{Counter, Histogram}, trace::TracerProvider as _, KeyValue};
use opentelemetry_appender_tracing::layer::OpenTelemetryTracingBridge;
use opentelemetry_http::HeaderExtractor;
use opentelemetry_otlp::{LogExporter, MetricExporter, SpanExporter};
use opentelemetry_sdk::{logs::SdkLoggerProvider, metrics::SdkMeterProvider, propagation::TraceContextPropagator, trace::SdkTracerProvider, Resource};
use tracing::{level_filters::LevelFilter, Instrument};
use tracing_opentelemetry::OpenTelemetrySpanExt;
use tracing_subscriber::{filter::Targets, layer::SubscriberExt, util::SubscriberInitExt};
/// Sends what is left when dropped: keep it until main returns.
pub struct Otel {
tp: SdkTracerProvider,
mp: SdkMeterProvider,
lp: SdkLoggerProvider,
}
impl Drop for Otel {
fn drop(&mut self) {
let _ = self.tp.shutdown();
let _ = self.mp.shutdown();
let _ = self.lp.shutdown();
}
}
/// IS_OTEL_ENABLED=true turns OTel on; any other value leaves it off.
/// Addresses, tokens, sampling and the service name come from the OTEL_*
/// environment values.
pub fn setup() -> Option<Otel> {
// The exporters' own crates stay out, or every export would log again.
let filter = Targets::new()
.with_default(LevelFilter::INFO)
.with_target("hyper", LevelFilter::OFF)
.with_target("h2", LevelFilter::OFF)
.with_target("reqwest", LevelFilter::OFF)
.with_target("opentelemetry", LevelFilter::OFF);
if std::env::var("IS_OTEL_ENABLED").as_deref() != Ok("true") {
tracing_subscriber::registry().with(filter).with(tracing_subscriber::fmt::layer()).init();
return None;
}
let resource = Resource::builder().build();
let tp = SdkTracerProvider::builder()
.with_batch_exporter(SpanExporter::builder().with_http().build().expect("OTLP span exporter"))
.with_resource(resource.clone())
.build();
let mp = SdkMeterProvider::builder()
.with_periodic_exporter(MetricExporter::builder().with_http().build().expect("OTLP metric exporter"))
.with_resource(resource.clone())
.build();
let lp = SdkLoggerProvider::builder()
.with_batch_exporter(LogExporter::builder().with_http().build().expect("OTLP log exporter"))
.with_resource(resource)
.build();
global::set_text_map_propagator(TraceContextPropagator::new());
global::set_tracer_provider(tp.clone());
global::set_meter_provider(mp.clone());
tracing_subscriber::registry()
.with(filter)
.with(tracing_subscriber::fmt::layer())
.with(tracing_opentelemetry::layer().with_tracer(tp.tracer("otel")))
.with(OpenTelemetryTracingBridge::new(&lp))
.init();
Some(Otel { tp, mp, lp })
}
/// axum middleware: a server span per request, continuing an incoming
/// traceparent (Spitfire's test), and the request count and duration as metrics.
pub async fn trace_http(req: Request, next: Next) -> Response {
static DURATION: OnceLock<Histogram<f64>> = OnceLock::new();
static REQUESTS: OnceLock<Counter<u64>> = OnceLock::new();
let duration = DURATION.get_or_init(|| {
global::meter("otel").f64_histogram("http.server.request.duration").with_unit("s").build()
});
let requests = REQUESTS.get_or_init(|| {
global::meter("otel").u64_counter("http.server.requests").with_unit("{request}").build()
});
let parent = global::get_text_map_propagator(|p| p.extract(&HeaderExtractor(req.headers())));
let method = req.method().to_string();
let path = req.uri().path().to_string();
let span = tracing::info_span!("request", otel.name = %format!("{method} {path}"), otel.kind = "server",
http.request.method = %method, url.path = %path, http.response.status_code = tracing::field::Empty);
let _ = span.set_parent(parent);
let start = std::time::Instant::now();
let res = next.run(req).instrument(span.clone()).await;
let status = res.status().as_u16();
span.record("http.response.status_code", status);
let attrs = [
KeyValue::new("http.request.method", method),
KeyValue::new("http.response.status_code", i64::from(status)),
];
duration.record(start.elapsed().as_secs_f64(), &attrs);
requests.add(1, &attrs);
res
}src/main.rs'te modülü ekleyin, öncesetup'ı çağırın ve middleware'i router'a koyun:
mod otel;
// at the start of main; keep it until main returns:
let _otel = otel::setup();
// on the router (axum::middleware):
let app = Router::new()
.route("/", get(handler))
.layer(axum::middleware::from_fn(otel::trace_http)); Servis tracing_subscriber'ı zaten kuruyorsa o satırı silin: setup bunu yapar.
Cargo.toml'da[dependencies]altına bu satırları ekleyin ve servisi yeniden derleyin (cargo build --release):
opentelemetry = "=0.33.1"
opentelemetry_sdk = "=0.33.1"
opentelemetry-otlp = { version = "=0.33.1", features = ["reqwest-rustls"] }
opentelemetry-http = "=0.33.1"
opentelemetry-appender-tracing = "=0.33.1"
tracing-opentelemetry = "=0.34.0"
tracing = "=0.1.44"
tracing-subscriber = "=0.3.23" https:// adresleri için reqwest-rustls gerekir; sistemin güven deposunu kullanır.
- Klasörü, ardından
/etc/spitfire-otel/<service-name>.envdosyasını oluşturun, şunu yapıştırın:
sudo mkdir -p /etc/spitfire-otelIS_OTEL_ENABLED=true
OTEL_SERVICE_NAME=<service-name>
OTEL_RESOURCE_ATTRIBUTES=service.version=<service-version>,deployment.environment=<environment>
OTEL_EXPORTER_OTLP_PROTOCOL=http/protobuf
OTEL_EXPORTER_OTLP_TRACES_ENDPOINT=https://<spitfire>/otlp/v1/traces
OTEL_EXPORTER_OTLP_TRACES_HEADERS=authorization=sfotlp_…
OTEL_EXPORTER_OTLP_LOGS_ENDPOINT=https://<spitfire>/otlp/v1/logs
OTEL_EXPORTER_OTLP_LOGS_HEADERS=authorization=sfotlp_…
OTEL_EXPORTER_OTLP_METRICS_ENDPOINT=http://<tower>:4318/v1/metrics
OTEL_EXPORTER_OTLP_METRICS_HEADERS=authorization=sfcol_…
OTEL_TRACES_SAMPLER=parentbased_traceidratio
OTEL_TRACES_SAMPLER_ARG=0.1
NO_PROXY=<tower>,<spitfire>- İzni kısın:
sudo chmod 600 /etc/spitfire-otel/<service-name>.env sudo systemctl edit <unit>açın, şunu yapıştırın:
[Service]
EnvironmentFile=/etc/spitfire-otel/<service-name>.env- Yeni binary'yi yerine koyup yeniden başlatın:
sudo systemctl daemon-reload && sudo systemctl restart <unit> - Başladığını görün:
journalctl -u <unit> -n 50çıktısındaOTLP span exporterolmamalı (exporter kurulamazsa servis bu mesajla durur).
Özel CA varsa CA'yı sistem güven deposuna ekleyin
(sudo cp ca.pem /usr/local/share/ca-certificates/spitfire-ca.crt && sudo update-ca-certificates);
Rust exporter'ı OTEL_EXPORTER_OTLP_CERTIFICATE değerini okumaz.
Docker
- Kod değişikliklerini yapın (Linux 1–3. adım);
Dockerfile'a yeni satır gerekmez, crate'ler binary'nin içine derlenir. - Son image'da
https://<spitfire>için CA sertifikaları olmalı (Debian/Ubuntu'da:RUN apt-get update && apt-get install -y ca-certificates); özel CA varsa onu da kopyalayıpupdate-ca-certificatesçalıştırın. - Ortam dosyasını (Linux 4. adım) Docker makinesinde
/etc/spitfire-otel/<service-name>.envolarak kaydedin. - Çalıştırın:
docker run --env-file /etc/spitfire-otel/<service-name>.env …ya da compose'da servisin altınaenv_file: /etc/spitfire-otel/<service-name>.env. - Ortam dosyası değişince konteyneri yeniden oluşturun (
restartyetmez):docker compose up -d --force-recreate <service>
Kubernetes
- Image'ı Docker bölümündeki gibi hazırlayın.
- Ortam dosyasını (Linux 4. adım)
<service-name>.envolarak kaydedip Secret yapın:
kubectl create secret generic <service-name>-otel --from-env-file=<service-name>.env \
--dry-run=client -o yaml | kubectl apply -f -- Deployment'ta container'ın altına ekleyin:
envFrom:
- secretRef:
name: <service-name>-otel- Yeniden başlatın:
kubectl rollout restart deployment/<deployment>
Windows (servis)
- Kod değişikliklerini yapın (Linux 1–3. adım) ve
.exe'yi yeniden derleyin. - Yönetici PowerShell'de
<windows-service>yerine servisin adını (Get-Servicelistesindeki Name) yazıp çalıştırın:
$Service = "<windows-service>"
$IS_OTEL_ENABLED = "true"
$Otel = @(
"IS_OTEL_ENABLED=$IS_OTEL_ENABLED",
"OTEL_SERVICE_NAME=<service-name>",
"OTEL_RESOURCE_ATTRIBUTES=service.version=<service-version>,deployment.environment=<environment>",
"OTEL_EXPORTER_OTLP_PROTOCOL=http/protobuf",
"OTEL_EXPORTER_OTLP_TRACES_ENDPOINT=https://<spitfire>/otlp/v1/traces",
"OTEL_EXPORTER_OTLP_TRACES_HEADERS=authorization=sfotlp_…",
"OTEL_EXPORTER_OTLP_LOGS_ENDPOINT=https://<spitfire>/otlp/v1/logs",
"OTEL_EXPORTER_OTLP_LOGS_HEADERS=authorization=sfotlp_…",
"OTEL_EXPORTER_OTLP_METRICS_ENDPOINT=http://<tower>:4318/v1/metrics",
"OTEL_EXPORTER_OTLP_METRICS_HEADERS=authorization=sfcol_…",
"OTEL_TRACES_SAMPLER=parentbased_traceidratio",
"OTEL_TRACES_SAMPLER_ARG=0.1",
"NO_PROXY=<tower>,<spitfire>"
)
$Key = "HKLM:\SYSTEM\CurrentControlSet\Services\$Service"
$Keep = @((Get-ItemProperty $Key).Environment | Where-Object { $_ -and $_ -notmatch '^(IS_OTEL_ENABLED|OTEL_|NO_PROXY)=' })
Set-ItemProperty $Key -Name Environment -Type MultiString -Value ($Keep + $Otel)
Restart-Service -Name $Service -ForceKapatma ve kaldırma
- Kapatmak: ortam dosyasında (Windows'ta betikte)
IS_OTEL_ENABLED=falseyapın ve servisi yeniden başlatın (Linux 7. adım, Docker 5. adım, Kubernetes 4. adım ya da Windows betiğini yeniden çalıştırın). Kod kalır;setupo zaman log'ları yalnız stdout'a yazar. - Kaldırmak:
src/otel.rsdosyasını,mod otel;,setupvelayersatırlarını veCargo.toml'a eklenen crate'leri silip yeniden derleyin;sudo systemctl revert <unit>vesudo rm -r /etc/spitfire-otel; Windows'ta servisinEnvironmentdeğerinden OTel satırlarını silin.
Sık karşılaşılan sorunlar
| Belirti | Neden | Çözüm |
|---|---|---|
feature edition2024 is required ya da requires rustc 1.88 |
Toolchain çok eski | rustup update (sürüm tablosuna bakın) |
opentelemetry tipleri arasında the trait bound … is not satisfied |
Derlemede opentelemetry crate'lerinin iki sürümü var |
Bütün crate'leri yukarıdaki sürümlerle (=) yazın; cargo tree -d çiftleri gösterir |
invalid peer certificate: UnknownIssuer |
Özel CA güven deposunda değil | Linux notundaki gibi ekleyin |
a global default trace dispatcher has already been set |
Servis tracing_subscriber'ı kendisi de kuruyor |
O satırı silin (Linux 2. adım) |
| Trace ya da metrik gelmiyor | Adres, token ya da ağ | Doğrulama adımlarını uygulayın |