Skip to main content

tdm_server_rust/telemetry/
otlp.rs

1//! OTLP LoggerProvider 构建(Trace 默认走 SW 原生 Segment)
2
3use crate::config::TelemetryConfig;
4use opentelemetry::{KeyValue};
5use opentelemetry_otlp::{LogExporter, SpanExporter, WithExportConfig};
6use opentelemetry_sdk::{
7    logs::LoggerProvider,
8    trace::{Sampler, TracerProvider},
9    Resource,
10};
11
12/// OTel 导出器句柄
13pub struct OtelProviders {
14    /// Trace 导出(仅 export_otlp_traces=true 时存在)
15    pub tracer_provider: Option<TracerProvider>,
16    /// Log 导出 Provider
17    pub logger_provider: LoggerProvider,
18}
19
20/// 构建 LoggerProvider;按需构建 TracerProvider
21pub fn build_providers(profile: &str, cfg: &TelemetryConfig) -> anyhow::Result<OtelProviders> {
22    let endpoint = resolve_endpoint(cfg)?;
23    let resource = Resource::new(vec![
24        KeyValue::new("service.name", cfg.service_name.clone()),
25        KeyValue::new("deployment.environment", profile.to_string()),
26    ]);
27
28    let tracer_provider = if cfg.export_otlp_traces {
29        let sampler = if cfg.sample_ratio >= 1.0 {
30            Sampler::AlwaysOn
31        } else {
32            Sampler::TraceIdRatioBased(cfg.sample_ratio)
33        };
34        let span_exporter = SpanExporter::builder()
35            .with_tonic()
36            .with_endpoint(endpoint.clone())
37            .build()?;
38        Some(
39            TracerProvider::builder()
40                .with_batch_exporter(span_exporter, opentelemetry_sdk::runtime::Tokio)
41                .with_sampler(sampler)
42                .with_resource(resource.clone())
43                .build(),
44        )
45    } else {
46        None
47    };
48
49    let log_exporter = LogExporter::builder()
50        .with_tonic()
51        .with_endpoint(endpoint)
52        .build()?;
53
54    let logger_provider = LoggerProvider::builder()
55        .with_batch_exporter(log_exporter, opentelemetry_sdk::runtime::Tokio)
56        .with_resource(resource)
57        .build();
58
59    Ok(OtelProviders {
60        tracer_provider,
61        logger_provider,
62    })
63}
64
65/// 解析 OTLP 端点(环境变量优先)
66fn resolve_endpoint(cfg: &TelemetryConfig) -> anyhow::Result<String> {
67    if let Ok(ep) = std::env::var("OTEL_EXPORTER_OTLP_ENDPOINT") {
68        let trimmed = ep.trim();
69        if !trimmed.is_empty() {
70            return Ok(trimmed.to_string());
71        }
72    }
73    if !cfg.otlp_endpoint.trim().is_empty() {
74        return Ok(cfg.otlp_endpoint.trim().to_string());
75    }
76    if !cfg.skywalking.endpoint.trim().is_empty() {
77        return Ok(cfg.skywalking.endpoint.trim().to_string());
78    }
79    anyhow::bail!("telemetry.otlp_endpoint 未配置")
80}