Skip to main content

aptu_coder/
otel.rs

1// SPDX-FileCopyrightText: 2026 aptu-coder contributors
2// SPDX-License-Identifier: Apache-2.0
3
4use opentelemetry::global;
5use opentelemetry_otlp::{Protocol, WithExportConfig};
6use opentelemetry_sdk::Resource;
7use opentelemetry_sdk::logs::SdkLoggerProvider;
8use opentelemetry_sdk::metrics::SdkMeterProvider;
9use opentelemetry_sdk::trace::SdkTracerProvider;
10use tracing::warn;
11
12/// Builds the standard service resource attached to all three signal providers.
13fn service_resource() -> Resource {
14    Resource::builder()
15        .with_attribute(opentelemetry::KeyValue::new("service.name", "aptu-coder"))
16        .with_attribute(opentelemetry::KeyValue::new(
17            "service.version",
18            env!("CARGO_PKG_VERSION"),
19        ))
20        .build()
21}
22
23/// Initializes OpenTelemetry with OTLP export if OTEL_EXPORTER_OTLP_ENDPOINT is set.
24///
25/// Returns `Some(provider)` if initialization succeeds, or `None` if:
26/// - The env var is unset (noop provider, zero overhead)
27/// - The exporter fails to build (logs warning, graceful failure)
28///
29/// The provider is registered globally via `opentelemetry::global::set_tracer_provider`.
30pub fn init_otel() -> Option<SdkTracerProvider> {
31    let endpoint = std::env::var("OTEL_EXPORTER_OTLP_ENDPOINT").ok()?;
32
33    // Build the OTLP exporter with HTTP proto transport
34    let exporter = match opentelemetry_otlp::SpanExporter::builder()
35        .with_http()
36        .with_protocol(Protocol::HttpBinary)
37        .with_endpoint(&endpoint)
38        .build()
39    {
40        Ok(exp) => exp,
41        Err(e) => {
42            warn!("Failed to build OTLP exporter: {}", e);
43            return None;
44        }
45    };
46
47    // Build provider with batch exporter for async export
48    let provider = SdkTracerProvider::builder()
49        .with_batch_exporter(exporter)
50        .with_resource(service_resource())
51        .build();
52
53    // Register globally
54    global::set_tracer_provider(provider.clone());
55
56    Some(provider)
57}
58
59/// Initializes OpenTelemetry log appender if OTEL_EXPORTER_OTLP_ENDPOINT is set.
60///
61/// Returns `Some(provider)` if initialization succeeds, or `None` if:
62/// - The env var is unset (noop, zero overhead)
63/// - The exporter fails to build (logs warning, graceful failure)
64///
65/// The provider is returned for use with OpenTelemetryTracingBridge layer.
66pub fn init_log_appender() -> Option<SdkLoggerProvider> {
67    let endpoint = std::env::var("OTEL_EXPORTER_OTLP_ENDPOINT").ok()?;
68
69    // Build the OTLP log exporter with HTTP proto transport
70    let exporter = match opentelemetry_otlp::LogExporter::builder()
71        .with_http()
72        .with_protocol(Protocol::HttpBinary)
73        .with_endpoint(&endpoint)
74        .build()
75    {
76        Ok(exp) => exp,
77        Err(e) => {
78            warn!("Failed to build OTLP log exporter: {}", e);
79            return None;
80        }
81    };
82
83    // Build provider with batch processor for async export
84    let provider = SdkLoggerProvider::builder()
85        .with_batch_exporter(exporter)
86        .with_resource(service_resource())
87        .build();
88
89    Some(provider)
90}
91
92/// Initializes OpenTelemetry metrics SDK if OTEL_EXPORTER_OTLP_ENDPOINT is set.
93///
94/// Returns `Some(provider)` if initialization succeeds, or `None` if:
95/// - The env var is unset (noop, zero overhead)
96/// - The exporter fails to build (logs warning, graceful failure)
97///
98/// The provider is registered globally via `opentelemetry::global::set_meter_provider`.
99pub fn init_meter() -> Option<SdkMeterProvider> {
100    let endpoint = std::env::var("OTEL_EXPORTER_OTLP_ENDPOINT").ok()?;
101
102    // Build the OTLP metrics exporter with HTTP proto transport
103    let exporter = match opentelemetry_otlp::MetricExporter::builder()
104        .with_http()
105        .with_protocol(Protocol::HttpBinary)
106        .with_endpoint(&endpoint)
107        .build()
108    {
109        Ok(exp) => exp,
110        Err(e) => {
111            warn!("Failed to build OTLP metrics exporter: {}", e);
112            return None;
113        }
114    };
115
116    // Build provider with periodic reader for async export
117    let provider = SdkMeterProvider::builder()
118        .with_reader(opentelemetry_sdk::metrics::PeriodicReader::builder(exporter).build())
119        .with_resource(service_resource())
120        .build();
121
122    // Register globally
123    global::set_meter_provider(provider.clone());
124
125    Some(provider)
126}