wasmcloud_control_interface/
otel.rs

1// COPIED DIRECTLY FROM https://github.com/wasmCloud/weld/blob/wasmbus-rpc-v0.13.0/rpc-rs/src/otel.rs (minus unused functionality)
2
3//! Contains helpers and code for enabling [OpenTelemetry](https://opentelemetry.io/) tracing for
4//! wasmcloud-invocations. Please note that right now this is only supported for providers. This
5//! module is only available with the `otel` feature enabled
6
7use std::str::FromStr;
8
9use async_nats::header::{HeaderMap, HeaderName, HeaderValue};
10use opentelemetry::propagation::{Injector, TextMapPropagator};
11use opentelemetry_sdk::propagation::TraceContextPropagator;
12use tracing::span::Span;
13use tracing_opentelemetry::OpenTelemetrySpanExt;
14
15use crate::Result;
16
17/// A convenience type that wraps a NATS [`HeaderMap`] and implements the [`Injector`] trait
18#[derive(Debug, Default)]
19#[non_exhaustive]
20pub struct HeaderInjector {
21    inner: HeaderMap,
22}
23
24impl HeaderInjector {
25    /// Creates a new header injector from an iterator of string tuples
26    pub fn from(headers: impl IntoIterator<Item = (String, String)>) -> Result<Self> {
27        let inner = headers
28            .into_iter()
29            .map(
30                |(h, v)| match (HeaderName::from_str(&h), HeaderValue::from_str(&v)) {
31                    (Ok(h), Ok(v)) => Ok((h, v)),
32                    (Err(e), _) => Err(format!("failed to build header name: {e}").into()),
33                    (_, Err(e)) => Err(format!("failed to build header name: {e}").into()),
34                },
35            )
36            .collect::<Result<HeaderMap>>()?;
37        Ok(HeaderInjector { inner })
38    }
39
40    /// Creates a new injector using the given [`HeaderMap`]
41    pub fn new(headers: HeaderMap) -> Self {
42        HeaderInjector { inner: headers }
43    }
44
45    /// Convenience constructor that returns a new injector with the current span context already
46    /// injected into the given header map
47    pub fn new_with_span(headers: HeaderMap) -> Self {
48        let mut header_map = Self::new(headers);
49        header_map.inject_context();
50        header_map
51    }
52
53    /// Convenience constructor that returns a new injector with the current span context already
54    /// injected into a default [`HeaderMap`]
55    pub fn default_with_span() -> Self {
56        let mut header_map = Self::default();
57        header_map.inject_context();
58        header_map
59    }
60
61    /// Injects the current context from the span into the headers
62    pub fn inject_context(&mut self) {
63        let ctx_propagator = TraceContextPropagator::new();
64        ctx_propagator.inject_context(&Span::current().context(), self);
65    }
66}
67
68impl Injector for HeaderInjector {
69    fn set(&mut self, key: &str, value: String) {
70        self.inner.insert(key, value.as_ref());
71    }
72}
73
74impl AsRef<HeaderMap> for HeaderInjector {
75    fn as_ref(&self) -> &HeaderMap {
76        &self.inner
77    }
78}
79
80impl From<HeaderMap> for HeaderInjector {
81    fn from(headers: HeaderMap) -> Self {
82        HeaderInjector::new(headers)
83    }
84}
85
86impl From<HeaderInjector> for HeaderMap {
87    fn from(inj: HeaderInjector) -> Self {
88        inj.inner
89    }
90}