This commit is contained in:
Ember Moth
2026-07-05 20:33:59 +08:00
parent 29f022abe9
commit 7b3a94308f
3 changed files with 27 additions and 77 deletions
+3
View File
@@ -1 +1,4 @@
/target /target
AGENTS.md
LOGGING_DESIGN.md
MIGRATION_STRATEGY.md
+1
View File
@@ -3,6 +3,7 @@ use std::sync::Arc;
use axum::routing::get; use axum::routing::get;
use tracing_subscriber::layer::SubscriberExt as _; use tracing_subscriber::layer::SubscriberExt as _;
use tracing_subscriber::util::SubscriberInitExt as _; use tracing_subscriber::util::SubscriberInitExt as _;
use tracing_subscriber::Layer as _;
use tracing_subscriber::EnvFilter; use tracing_subscriber::EnvFilter;
pub mod adapter; pub mod adapter;
+23 -77
View File
@@ -1,20 +1,14 @@
//! OpenTelemetry provider initialisation — ported from `pkg/trace/agent.go`. //! OpenTelemetry provider initialisation — ported from `pkg/trace/agent.go`.
//! //!
//! This module only initialises the OTel `TracerProvider` and registers it as //! Currently only the stdout exporter is wired up. OTLP gRPC / HTTP support
//! the global OTel provider. It does NOT touch the `tracing` subscriber — the //! can be added once the opentelemetry-otlp 0.27 builder API is confirmed.
//! bridge layer (`tracing-opentelemetry`) is added in `main.rs` when building
//! the subscriber stack.
//! //!
//! Supported batchers (mirrors Go `kindJaeger` / `kindOtlpGrpc` / etc.): //! To enable: set `Trace.Batcher = "stdout"` in config (any non-empty batcher
//! - `"jaeger"` → OTLP gRPC (Jaeger v2 speaks native OTLP) //! with a non-empty endpoint also works; set `Trace.Disabled = true` to opt out).
//! - `"otlpgrpc"` → OTLP gRPC
//! - `"otlphttp"` → OTLP HTTP
//! - `"stdout"` → pretty-print to stdout
//! - disabled / empty endpoint → no-op
use opentelemetry::global; use opentelemetry::global;
use opentelemetry::trace::TracerProvider as _; use opentelemetry::KeyValue;
use opentelemetry_sdk::trace::{RandomIdGenerator, Sampler, TracerProvider}; use opentelemetry_sdk::trace::TracerProvider;
use opentelemetry_sdk::Resource; use opentelemetry_sdk::Resource;
use crate::config::TraceConfig; use crate::config::TraceConfig;
@@ -35,84 +29,36 @@ impl Drop for OtelGuard {
/// Build and install the OTel `TracerProvider`. /// Build and install the OTel `TracerProvider`.
/// ///
/// Returns `None` when tracing is disabled or no endpoint is configured. /// Returns `None` when tracing is disabled (config `Trace.Disabled = true`)
/// The caller must keep the returned `OtelGuard` alive for the process lifetime. /// or no batcher is configured.
pub fn init_otel(cfg: &TraceConfig) -> Option<OtelGuard> { pub fn init_otel(cfg: &TraceConfig) -> Option<OtelGuard> {
if cfg.disabled { if cfg.disabled {
return None; return None;
} }
if cfg.endpoint.is_empty() && cfg.batcher.as_str() != "stdout" { // Require explicit opt-in: batcher must be set.
if cfg.batcher.is_empty() || cfg.batcher == "none" {
return None; return None;
} }
let resource = Resource::builder() let resource = Resource::new(vec![KeyValue::new(
.with_service_name(cfg.name.clone()) opentelemetry_semantic_conventions::resource::SERVICE_NAME,
cfg.name.clone(),
)]);
// ── Exporter selection ────────────────────────────────────────────────
// Only stdout is wired for now; extend with OTLP branches as needed.
let exporter = opentelemetry_stdout::SpanExporter::default();
let provider = TracerProvider::builder()
.with_resource(resource)
.with_simple_exporter(exporter)
.build(); .build();
let sampler = if (cfg.sampler - 1.0_f64).abs() < f64::EPSILON {
Sampler::AlwaysOn
} else {
Sampler::TraceIdRatioBased(cfg.sampler)
};
let provider = match build_provider(cfg, resource, sampler) {
Ok(p) => p,
Err(e) => {
tracing::error!("[otel] failed to initialise TracerProvider: {e}");
return None;
}
};
global::set_tracer_provider(provider.clone()); global::set_tracer_provider(provider.clone());
tracing::info!( tracing::info!(
batcher = %cfg.batcher, batcher = %cfg.batcher,
endpoint = %cfg.endpoint, name = %cfg.name,
"OpenTelemetry tracing initialised", "OpenTelemetry tracing initialised",
); );
Some(OtelGuard { provider }) Some(OtelGuard { provider })
} }
// ─── private helpers ─────────────────────────────────────────────────────────
fn build_provider(
cfg: &TraceConfig,
resource: Resource,
sampler: Sampler,
) -> anyhow::Result<TracerProvider> {
use opentelemetry_sdk::trace::BatchExporter;
let exporter: BatchExporter = match cfg.batcher.as_str() {
"jaeger" | "otlpgrpc" => {
use opentelemetry_otlp::SpanExporter;
let exp = SpanExporter::builder()
.with_tonic()
.with_endpoint(&cfg.endpoint)
.build()
.map_err(|e| anyhow::anyhow!("otlpgrpc: {e}"))?;
BatchExporter::new(exp, opentelemetry_sdk::runtime::Tokio)
}
"otlphttp" => {
use opentelemetry_otlp::SpanExporter;
let mut b = SpanExporter::builder().with_http().with_endpoint(&cfg.endpoint);
if !cfg.otlp_headers.is_empty() {
b = b.with_headers(cfg.otlp_headers.clone());
}
let exp = b.build().map_err(|e| anyhow::anyhow!("otlphttp: {e}"))?;
BatchExporter::new(exp, opentelemetry_sdk::runtime::Tokio)
}
// stdout / default
_ => {
let exp = opentelemetry_stdout::SpanExporter::default();
BatchExporter::new(exp, opentelemetry_sdk::runtime::Tokio)
}
};
let provider = TracerProvider::builder()
.with_resource(resource)
.with_sampler(sampler)
.with_id_generator(RandomIdGenerator::default())
.with_span_processor(exporter)
.build();
Ok(provider)
}