tracing_jaeger/
opentelemetry.rs

1use crate::visitor::{event_to_values, span_to_values, OpenTelemetryVisitor};
2use opentelemetry::api::trace::{self, span_context::SpanId, span_context::TraceId};
3use opentelemetry::sdk::trace::config::Config;
4use opentelemetry::sdk::trace::evicted_hash_map::EvictedHashMap;
5use opentelemetry::sdk::EvictedQueue;
6use std::collections::HashMap;
7use std::sync::{Arc, Mutex};
8use tracing_distributed::{Event, Span, Telemetry};
9
10/// Telemetry capability that publishes events and spans to some OpenTelemetry backend
11#[derive(Debug)]
12pub struct OpenTelemetry {
13    pub(crate) exporter: Box<dyn opentelemetry::exporter::trace::SpanExporter>,
14    // TODO: should have some eviction strategy so this doesn't grow forever
15    pub(crate) events: Mutex<HashMap<SpanId, EvictedQueue<trace::event::Event>>>,
16    pub(crate) config: Config,
17}
18
19impl Telemetry for OpenTelemetry {
20    type Visitor = OpenTelemetryVisitor;
21    type TraceId = TraceId;
22    type SpanId = SpanId;
23
24    // FIXME/NOTE: each event on a span is also allowed to have max_attributes_per_span attrs
25    fn mk_visitor(&self) -> Self::Visitor {
26        OpenTelemetryVisitor(EvictedHashMap::new(self.config.max_attributes_per_span))
27    }
28
29    fn report_span(&self, span: Span<Self::Visitor, Self::SpanId, Self::TraceId>) {
30        // succeed or die. failure is unrecoverable (mutex poisoned)
31        let mut events = self.events.lock().unwrap();
32
33        let events = events
34            .remove(&span.id)
35            .unwrap_or_else(|| EvictedQueue::new(0));
36        let data = span_to_values(span, events);
37        self.exporter.export(vec![Arc::new(data)]); // TODO: batch
38    }
39
40    fn report_event(&self, event: Event<Self::Visitor, Self::SpanId, Self::TraceId>) {
41        match event.parent_id {
42            Some(id) => {
43                let mut events = self.events.lock().unwrap();
44
45                if let Some(q) = events.get_mut(&id) {
46                    q.append_vec(&mut vec![event_to_values(event)]);
47                } else {
48                    let mut q = EvictedQueue::new(self.config.max_events_per_span);
49                    q.append_vec(&mut vec![event_to_values(event)]);
50                    events.insert(id, q);
51                }
52            }
53            None => {
54                // events are reported as part of spandata, event must have a parent to be recorded
55            }
56        }
57    }
58}