arminius_lib_nats/
opentelemetry.rs1mod tests;
8
9use async_nats::Message;
10use tracing_opentelemetry::OpenTelemetrySpanExt as _;
11
12struct NatsHeaderInjector<'a>(pub &'a mut async_nats::HeaderMap);
14
15impl opentelemetry::propagation::Injector for NatsHeaderInjector<'_> {
16 fn set(&mut self, key: &str, value: String) {
17 self.0.insert(key, value);
18 }
19}
20
21struct NatsHeaderExtractor<'a>(pub &'a Option<async_nats::HeaderMap>);
23
24impl opentelemetry::propagation::Extractor for NatsHeaderExtractor<'_> {
25 fn get(&self, key: &str) -> Option<&str> {
27 match self.0 {
28 Some(map) => map.get(key).map(AsRef::as_ref),
29 None => None,
30 }
31 }
32
33 fn keys(&self) -> Vec<&str> {
35 match self.0 {
36 Some(map) => map.iter().map(|(name, _value)| name.as_ref()).collect::<Vec<_>>(),
37 None => Vec::new(),
38 }
39 }
40}
41
42pub(crate) fn extract_otel_context(message: &Message) -> opentelemetry::Context {
48 if message.headers.is_some() {
49 opentelemetry::global::get_text_map_propagator(|propagator| {
50 propagator.extract(&NatsHeaderExtractor(&message.headers))
51 })
52 } else {
53 opentelemetry::Context::current()
54 }
55}
56
57#[must_use]
64pub fn span_from_nats_message(message: &Message) -> tracing::span::Span {
65 let span = tracing::span!(
66 tracing::Level::INFO,
67 "NATS message",
68 nats.subject = message.subject.as_str(),
69 nats.length = message.length,
70 nats.message = tracing::field::debug(&message.payload),
71 nats.headers = tracing::field::debug(&message.headers)
72 );
73
74 let _ = span.set_parent(extract_otel_context(message));
75
76 span
77}
78
79#[must_use]
81pub fn span_to_nats_headers() -> async_nats::HeaderMap {
82 let mut headers = async_nats::HeaderMap::new();
83 let ctx = tracing::Span::current().context();
84 opentelemetry::global::get_text_map_propagator(|propagator| {
85 propagator.inject_context(&ctx, &mut NatsHeaderInjector(&mut headers));
86 });
87
88 headers
89}