retrom_telemetry/
lib.rs

1use opentelemetry::{global, trace::TracerProvider, KeyValue};
2use opentelemetry_otlp::OTEL_EXPORTER_OTLP_ENDPOINT;
3use opentelemetry_sdk::{
4    metrics::{MeterProviderBuilder, PeriodicReader, SdkMeterProvider},
5    propagation::TraceContextPropagator,
6    resource::{EnvResourceDetector, SdkProvidedResourceDetector, TelemetryResourceDetector},
7    trace::{RandomIdGenerator, Sampler, SdkTracerProvider},
8    Resource,
9};
10use opentelemetry_semantic_conventions::attribute::{SERVICE_NAME, SERVICE_VERSION};
11use std::{fs::OpenOptions, path::Path};
12use tracing_opentelemetry::{MetricsLayer, OpenTelemetryLayer};
13use tracing_subscriber::{layer::SubscriberExt, prelude::*, util::SubscriberInitExt};
14
15pub mod grpc;
16
17#[tracing::instrument(skip(log_path))]
18pub async fn init_tracing_subscriber<Logfile: AsRef<Path>>(
19    telemetry_enabled: bool,
20    log_path: Logfile,
21) {
22    global::set_text_map_propagator(TraceContextPropagator::new());
23
24    let fmt_layer = tracing_subscriber::fmt::layer()
25        .with_ansi(true)
26        .with_target(true)
27        .boxed();
28
29    let mut layers = vec![fmt_layer];
30
31    if telemetry_enabled {
32        let tracer_provider = get_tracer_provider();
33        let meter_provider = init_meter_provider();
34        let tracer = tracer_provider.tracer("main");
35
36        let metrics_layer = MetricsLayer::new(meter_provider).boxed();
37        let telemetry_layer = OpenTelemetryLayer::new(tracer).boxed();
38
39        layers.push(metrics_layer);
40        layers.push(telemetry_layer);
41    }
42
43    let log_file = OpenOptions::new()
44        .write(true)
45        .create(true)
46        .truncate(true)
47        .open(log_path)
48        .expect("failed to open log file");
49
50    let file_layer = tracing_subscriber::fmt::layer()
51        .json()
52        .with_writer(log_file)
53        .boxed();
54
55    layers.push(file_layer);
56
57    let env_filter = tracing_subscriber::EnvFilter::try_from_default_env()
58        .unwrap_or_else(|_| "info,".into())
59        .add_directive("tokio_postgres=info".parse().unwrap())
60        .add_directive("hyper=info".parse().unwrap())
61        // .add_directive("tower_http=debug".parse().unwrap())
62        .add_directive("axum::rejection=trace".parse().unwrap())
63        .add_directive("hyper_util=info".parse().unwrap());
64
65    tracing_subscriber::registry()
66        .with(layers)
67        .with(env_filter)
68        .init();
69}
70
71pub fn resource() -> Resource {
72    let environment = if cfg!(debug_assertions) {
73        "debug"
74    } else {
75        "release"
76    };
77
78    let svc_name =
79        std::env::var("SERVICE_NAME").unwrap_or_else(|_| env!("CARGO_PKG_NAME").to_string());
80
81    let svc_version =
82        std::env::var("SERVICE_VERSION").unwrap_or_else(|_| env!("CARGO_PKG_VERSION").to_string());
83
84    Resource::builder_empty()
85        .with_detectors(&[
86            Box::new(SdkProvidedResourceDetector),
87            Box::new(EnvResourceDetector::new()),
88            Box::new(TelemetryResourceDetector),
89        ])
90        .with_attributes([
91            KeyValue::new(SERVICE_NAME, svc_name),
92            KeyValue::new(SERVICE_VERSION, svc_version),
93            KeyValue::new("deployment.environment.name", environment),
94        ])
95        .build()
96}
97
98pub fn init_meter_provider() -> SdkMeterProvider {
99    let exporter = opentelemetry_otlp::MetricExporter::builder()
100        .with_http()
101        .with_temporality(opentelemetry_sdk::metrics::Temporality::default())
102        .build()
103        .unwrap();
104
105    let reader = PeriodicReader::builder(exporter)
106        .with_interval(std::time::Duration::from_secs(30))
107        .build();
108
109    let meter_provider = MeterProviderBuilder::default()
110        .with_resource(resource())
111        .with_reader(reader)
112        .build();
113
114    global::set_meter_provider(meter_provider.clone());
115
116    meter_provider
117}
118
119pub fn get_tracer_provider() -> SdkTracerProvider {
120    let exporter = opentelemetry_otlp::SpanExporter::builder()
121        .with_http()
122        .build()
123        .unwrap();
124
125    let tracer_provider = SdkTracerProvider::builder()
126        .with_batch_exporter(exporter)
127        .with_sampler(Sampler::AlwaysOn)
128        .with_id_generator(RandomIdGenerator::default())
129        .with_max_events_per_span(64)
130        .with_max_attributes_per_span(16)
131        .with_resource(resource())
132        .build();
133
134    global::set_tracer_provider(tracer_provider.clone());
135
136    tracing::info!(
137        "OpenTelemetry Tracer Provider initialized: {}",
138        OTEL_EXPORTER_OTLP_ENDPOINT
139    );
140
141    tracer_provider
142}