arcly_http/observability/
otel.rs1use opentelemetry::trace::{SpanContext, SpanId, TraceContextExt, TraceFlags, TraceId, TraceState};
8use opentelemetry::Context;
9
10use crate::web::context::RequestContext;
11
12pub struct OtelConfig {
14 pub service_name: &'static str,
15 pub service_version: &'static str,
16 pub otlp_endpoint: &'static str,
18}
19
20pub fn init_tracer(cfg: &OtelConfig) {
24 use opentelemetry::KeyValue;
25 use opentelemetry_otlp::WithExportConfig;
26 use opentelemetry_sdk::trace::TracerProvider;
27 use opentelemetry_sdk::Resource;
28
29 let resource = Resource::new(vec![
30 KeyValue::new("service.name", cfg.service_name),
31 KeyValue::new("service.version", cfg.service_version),
32 ]);
33
34 let exporter_result = opentelemetry_otlp::SpanExporter::builder()
35 .with_tonic()
36 .with_endpoint(cfg.otlp_endpoint)
37 .build();
38
39 match exporter_result {
40 Ok(exporter) => {
41 let provider = TracerProvider::builder()
42 .with_batch_exporter(exporter, opentelemetry_sdk::runtime::Tokio)
43 .with_resource(resource)
44 .build();
45
46 opentelemetry::global::set_tracer_provider(provider);
47
48 tracing::info!(
49 endpoint = cfg.otlp_endpoint,
50 service = cfg.service_name,
51 "OTLP tracer initialised"
52 );
53 }
54 Err(e) => {
55 tracing::warn!(
56 error = %e,
57 endpoint = cfg.otlp_endpoint,
58 "OTLP tracer failed to initialise — spans will not be exported"
59 );
60 }
61 }
62}
63
64pub fn parent_context_from(ctx: &RequestContext) -> Context {
73 let parent_span_id = match ctx.parent_span_id() {
74 Some(bytes) => SpanId::from_bytes(bytes),
75 None => return Context::current(), };
77
78 let span_context = SpanContext::new(
79 TraceId::from_bytes(ctx.trace_id()),
80 parent_span_id,
81 TraceFlags::SAMPLED,
82 true, TraceState::default(),
84 );
85 Context::current().with_remote_span_context(span_context)
86}