linera_service/tracing/
opentelemetry.rs1use opentelemetry::{global, trace::TracerProvider};
7use opentelemetry_otlp::{SpanExporter, WithExportConfig};
8#[cfg(with_testing)]
9use opentelemetry_sdk::trace::InMemorySpanExporter;
10use opentelemetry_sdk::{trace::SdkTracerProvider, Resource};
11use tracing_opentelemetry::OpenTelemetryLayer;
12use tracing_subscriber::{
13 filter::{filter_fn, FilterFn},
14 layer::Layer,
15 prelude::__tracing_subscriber_SubscriberExt as _,
16 util::SubscriberInitExt,
17};
18
19fn opentelemetry_skip_filter() -> FilterFn<impl Fn(&tracing::Metadata<'_>) -> bool> {
39 filter_fn(|metadata| {
40 if !metadata.is_span() {
41 return false;
42 }
43 metadata.fields().field("opentelemetry.skip").is_none()
44 })
45}
46
47fn init_with_tracer_provider(log_name: &str, tracer_provider: SdkTracerProvider) {
51 global::set_tracer_provider(tracer_provider.clone());
52 let tracer = tracer_provider.tracer("linera");
53
54 let opentelemetry_layer =
55 OpenTelemetryLayer::new(tracer).with_filter(opentelemetry_skip_filter());
56
57 let config = crate::tracing::get_env_config(log_name);
58 let maybe_log_file_layer = config.maybe_log_file_layer();
59 let stderr_layer = config.stderr_layer();
60
61 tracing_subscriber::registry()
62 .with(opentelemetry_layer)
63 .with(config.env_filter)
64 .with(maybe_log_file_layer)
65 .with(stderr_layer)
66 .init();
67}
68
69#[cfg(with_testing)]
74pub fn build_opentelemetry_layer_with_test_exporter(
75 log_name: &str,
76) -> (
77 impl tracing_subscriber::Layer<tracing_subscriber::Registry>,
78 InMemorySpanExporter,
79 SdkTracerProvider,
80) {
81 let exporter = InMemorySpanExporter::default();
82 let exporter_clone = exporter.clone();
83
84 let resource = Resource::builder()
85 .with_service_name(log_name.to_string())
86 .build();
87
88 let tracer_provider = SdkTracerProvider::builder()
89 .with_resource(resource)
90 .with_simple_exporter(exporter)
91 .with_sampler(opentelemetry_sdk::trace::Sampler::AlwaysOn)
92 .build();
93
94 global::set_tracer_provider(tracer_provider.clone());
95 let tracer = tracer_provider.tracer("linera");
96 let opentelemetry_layer =
97 OpenTelemetryLayer::new(tracer).with_filter(opentelemetry_skip_filter());
98
99 (opentelemetry_layer, exporter_clone, tracer_provider)
100}
101
102pub fn init(log_name: &str, otlp_endpoint: Option<&str>) {
109 let endpoint = match otlp_endpoint {
111 Some(ep) if !ep.is_empty() => ep.to_string(),
112 _ => match std::env::var("LINERA_OTLP_EXPORTER_ENDPOINT") {
113 Ok(ep) if !ep.is_empty() => ep,
114 _ => {
115 eprintln!(
116 "LINERA_OTLP_EXPORTER_ENDPOINT not set and no endpoint provided. \
117 Falling back to standard tracing without OpenTelemetry support."
118 );
119 crate::tracing::init(log_name);
120 return;
121 }
122 },
123 };
124
125 let resource = Resource::builder()
126 .with_service_name(log_name.to_string())
127 .build();
128
129 let exporter = SpanExporter::builder()
130 .with_tonic()
131 .with_endpoint(endpoint)
132 .build()
133 .expect("Failed to create OTLP exporter");
134
135 let tracer_provider = SdkTracerProvider::builder()
136 .with_resource(resource)
137 .with_batch_exporter(exporter)
138 .with_sampler(opentelemetry_sdk::trace::Sampler::AlwaysOn)
139 .build();
140
141 init_with_tracer_provider(log_name, tracer_provider);
142}