1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
//! OpenTelemetry global `Tracer` and `Meter` singletons.
use crate::api::{self, KeyValue, SpanContext, Tracer};
use std::any::Any;
use std::sync::{Arc, RwLock};
use std::time::SystemTime;

/// Boxed span wraps a generic trait object so that `BoxedTracer`s
/// can return whichever type of span they were configured to use.
#[derive(Debug)]
pub struct BoxedSpan(Box<dyn api::Span>);

impl api::Span for BoxedSpan {
    /// Delegates to inner span.0
    fn add_event_with_timestamp(&mut self, message: String, timestamp: SystemTime) {
        self.0.add_event_with_timestamp(message, timestamp)
    }

    /// Delegates to inner span.
    fn add_link(&mut self, link: api::SpanContext) {
        self.0.add_link(link)
    }

    /// Delegates to inner span.
    fn get_context(&self) -> SpanContext {
        self.0.get_context()
    }

    /// Delegates to inner span.
    fn is_recording(&self) -> bool {
        self.0.is_recording()
    }

    /// Delegates to inner span.
    fn set_attribute(&mut self, attribute: KeyValue) {
        self.0.set_attribute(attribute)
    }

    /// Delegates to inner span.
    fn set_status(&mut self, status: String) {
        self.0.set_status(status)
    }

    /// Delegates to inner span.
    fn update_name(&mut self, new_name: String) {
        self.0.update_name(new_name)
    }

    /// Delegates to inner span.
    fn end(&mut self) {
        self.0.end()
    }

    /// Returns self as any
    fn as_any(&self) -> &dyn Any {
        self
    }
}

/// Boxed Tracer allows `GlobalTracer`'s to contain and use a `Tracer` type object.
pub trait BoxedTracer: Send + Sync {
    /// Create a new invalid span for use in cases where there are no active spans.
    fn invalid_boxed(&self) -> Box<dyn api::Span>;

    /// Returns a trait object so the underlying implementation can be swapped
    /// out at runtime.
    fn start_boxed(
        &self,
        name: &'static str,
        parent: Option<api::SpanContext>,
    ) -> Box<dyn api::Span>;

    /// Returns the currently active span as a BoxedSpan
    fn get_active_span_boxed(&self) -> Box<dyn api::Span>;

    /// Returns the currently active span as a BoxedSpan
    fn mark_span_as_active_boxed(&self, span: &dyn api::Span);

    /// Marks the current span as inactive
    fn mark_span_as_inactive_boxed(&self, span_id: u64);
}

impl<S: api::Span + 'static> BoxedTracer for Box<dyn api::Tracer<Span = S>> {
    /// Create a new invalid span for use in cases where there are no active spans.
    fn invalid_boxed(&self) -> Box<dyn api::Span> {
        Box::new(self.invalid())
    }

    /// Returns a trait object so the underlying implementation can be swapped
    /// out at runtime.
    fn start_boxed(
        &self,
        name: &'static str,
        parent: Option<api::SpanContext>,
    ) -> Box<dyn api::Span> {
        Box::new(self.start(name, parent))
    }

    /// Returns the current active span.
    fn get_active_span_boxed(&self) -> Box<dyn api::Span> {
        Box::new(self.get_active_span())
    }

    /// Mark span as active.
    fn mark_span_as_active_boxed(&self, some_span: &dyn api::Span) {
        if let Some(span) = some_span.as_any().downcast_ref::<S>() {
            self.mark_span_as_active(span)
        };
    }

    /// Mark span as inactive.
    fn mark_span_as_inactive_boxed(&self, span_id: u64) {
        self.mark_span_as_inactive(span_id)
    }
}

impl Tracer for dyn BoxedTracer {
    /// BoxedTracer returns a BoxedSpan so that it doesn't need a generic type parameter.
    type Span = BoxedSpan;

    /// Returns an invalid boxed span
    fn invalid(&self) -> Self::Span {
        BoxedSpan(self.invalid_boxed())
    }

    /// Starts a new boxed span.
    fn start(&self, name: &'static str, parent_span: Option<api::SpanContext>) -> Self::Span {
        BoxedSpan(self.start_boxed(name, parent_span))
    }

    /// Returns the current active span.
    fn get_active_span(&self) -> Self::Span {
        BoxedSpan(self.get_active_span_boxed())
    }

    /// Marks a given `Span` as active.
    fn mark_span_as_active(&self, span: &Self::Span) {
        self.mark_span_as_active_boxed(&(*span.0))
    }

    /// Marks a given `Span` as inactive.
    fn mark_span_as_inactive(&self, span_id: u64) {
        self.mark_span_as_inactive_boxed(span_id)
    }
}

/// GlobalTracer maintains a global singleton that allows any thread to access
/// the same generic `Tracer` implementation.
#[allow(missing_debug_implementations)]
pub struct GlobalTracer {
    tracer: Box<dyn BoxedTracer>,
}

impl GlobalTracer {
    /// Create a new global tracer via any `Tracer`.
    fn new<S: api::Span + 'static>(tracer: Box<dyn api::Tracer<Span = S>>) -> Self {
        Self {
            tracer: Box::new(tracer),
        }
    }
}

impl api::Tracer for GlobalTracer {
    /// Global tracer uses `BoxedSpan`s so that it can be a global singleton,
    /// which is not possible if it takes generic type parameters.
    type Span = BoxedSpan;

    /// Returns a span with an invalid `SpanContext`.
    fn invalid(&self) -> Self::Span {
        self.tracer.invalid()
    }

    /// Starts a new `Span`.
    fn start(&self, name: &'static str, parent_span: Option<api::SpanContext>) -> Self::Span {
        self.tracer.start(name, parent_span)
    }

    /// Returns the current active span.
    fn get_active_span(&self) -> Self::Span {
        self.tracer.get_active_span()
    }

    /// Mark a given `Span` as active.
    fn mark_span_as_active(&self, span: &Self::Span) {
        self.tracer.mark_span_as_active(span)
    }

    /// Mark a given `Span` as inactive.
    fn mark_span_as_inactive(&self, span_id: u64) {
        self.tracer.mark_span_as_inactive(span_id)
    }
}

lazy_static::lazy_static! {
    /// The global `Tracer` singleton.
    static ref GLOBAL_TRACER: RwLock<Arc<GlobalTracer>> = RwLock::new(Arc::new(GlobalTracer::new(Box::new(api::NoopTracer {}))));
}

/// Returns a reference to the global `Tracer`
pub fn global_tracer() -> Arc<GlobalTracer> {
    GLOBAL_TRACER
        .read()
        .expect("GLOBAL_TRACER RwLock poisoned")
        .clone()
}

/// Assigns the global `Tracer`
pub fn set_tracer<S: api::Span + 'static>(new_tracer: Box<dyn api::Tracer<Span = S>>) {
    let mut global_tracer = GLOBAL_TRACER
        .write()
        .expect("GLOBAL_TRACER RwLock poisoned");
    *global_tracer = Arc::new(GlobalTracer::new(new_tracer));
}

/// Returns `NoopMeter` for now
pub fn global_meter() -> crate::api::NoopMeter {
    crate::api::NoopMeter {}
}