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
//! # Trace Provider SDK
//!
//! ## Tracer Creation
//!
//! New `Tracer` instances are always created through a `Provider`.
//!
//! All configuration objects and extension points (span processors,
//! propagators) are provided by the `Provider`. `Tracer` instances do
//! not duplicate this data to avoid that different `Tracer` instances
//! of the `Provider` have different versions of these data.
use crate::exporter::trace::SpanExporter;
use crate::{api, sdk};
use std::collections::HashMap;
use std::sync::{Arc, RwLock};

/// Default tracer name if empty string is provided.
const DEFAULT_COMPONENT_NAME: &str = "rust.opentelemetry.io/sdk/tracer";

/// Provider
#[derive(Debug)]
struct ProviderInner {
    named_tracers: RwLock<HashMap<&'static str, sdk::Tracer>>,
    processors: Vec<Box<dyn api::SpanProcessor>>,
    config: sdk::Config,
}

/// Creator and registry of named `Tracer` instances.
#[derive(Clone, Debug)]
pub struct Provider {
    inner: Arc<ProviderInner>,
}

impl Default for Provider {
    fn default() -> Self {
        Provider::builder().build()
    }
}

impl Provider {
    /// Create a new `Provider` builder.
    pub fn builder() -> Builder {
        Builder::default()
    }

    /// Span processors associated with this provider
    pub fn span_processors(&self) -> &Vec<Box<dyn api::SpanProcessor>> {
        &self.inner.processors
    }

    /// Config associated with this tracer
    pub fn config(&self) -> &sdk::Config {
        &self.inner.config
    }
}

impl api::Provider for Provider {
    /// This implementation of `api::Provider` produces `sdk::Tracer` instances.
    type Tracer = sdk::Tracer;

    /// Find or create `Tracer` instance by name.
    fn get_tracer(&self, name: &'static str) -> Self::Tracer {
        // Use default value if name is invalid empty string
        let component_name = if name.is_empty() {
            DEFAULT_COMPONENT_NAME
        } else {
            name
        };

        // Return named tracer if already initialized
        if let Some(tracer) = self
            .inner
            .named_tracers
            .read()
            .expect("RwLock poisoned")
            .get(&component_name)
        {
            return tracer.clone();
        };

        // Else construct new named tracer
        let mut tracers = self.inner.named_tracers.write().expect("RwLock poisoned");
        let new_tracer = sdk::Tracer::new(name, self.clone());
        tracers.insert(component_name, new_tracer.clone());

        new_tracer
    }
}

/// Builder for provider attributes.
#[derive(Default, Debug)]
pub struct Builder {
    processors: Vec<Box<dyn api::SpanProcessor>>,
    config: sdk::Config,
}

impl Builder {
    /// The `SpanExporter` that this provider should use.
    pub fn with_simple_exporter<T: SpanExporter + 'static>(self, exporter: T) -> Self {
        let mut processors = self.processors;
        processors.push(Box::new(sdk::SimpleSpanProcessor::new(Box::new(exporter))));

        Builder { processors, ..self }
    }

    /// The sdk `Config` that this provider will use.
    pub fn with_config(self, config: sdk::Config) -> Self {
        Builder { config, ..self }
    }

    /// Create a new provider from this configuration.
    pub fn build(self) -> Provider {
        Provider {
            inner: Arc::new(ProviderInner {
                named_tracers: Default::default(),
                processors: self.processors,
                config: self.config,
            }),
        }
    }
}