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
use crate::{trace::Tracer, InstrumentationLibrary, InstrumentationLibraryBuilder, KeyValue};
use std::{borrow::Cow, sync::Arc};

/// Types that can create instances of [`Tracer`].
///
/// See the [`global`] module for examples of storing and retrieving tracer
/// provider instances.
///
/// [`global`]: crate::global
pub trait TracerProvider {
    /// The [`Tracer`] type that this provider will return.
    type Tracer: Tracer;

    /// Returns a new tracer with the given name.
    ///
    /// The `name` should be the application name or the name of the library
    /// providing instrumentation. If the name is empty, then an
    /// implementation-defined default name may be used instead.
    ///
    /// # Examples
    ///
    /// ```
    /// use opentelemetry::{global, trace::TracerProvider};
    /// use opentelemetry::KeyValue;
    ///
    /// let provider = global::tracer_provider();
    ///
    /// // tracer used in applications/binaries
    /// let tracer = provider.tracer("my_app");
    ///
    /// // tracer used in libraries/crates that optionally includes version and schema url
    /// let tracer = provider.tracer_builder("my_library").
    ///     with_version(env!("CARGO_PKG_VERSION")).
    ///     with_schema_url("https://opentelemetry.io/schema/1.0.0").
    ///     with_attributes(vec![KeyValue::new("key", "value")]).
    ///     build();
    /// ```
    fn tracer(&self, name: impl Into<Cow<'static, str>>) -> Self::Tracer {
        self.tracer_builder(name).build()
    }

    /// Deprecated, use [`TracerProvider::tracer_builder()`]
    ///
    /// Returns a new versioned tracer with a given name.
    ///
    /// The `name` should be the application name or the name of the library
    /// providing instrumentation. If the name is empty, then an
    /// implementation-defined default name may be used instead.
    ///
    /// # Examples
    ///
    /// ```
    /// use opentelemetry::{global, trace::TracerProvider};
    ///
    /// let provider = global::tracer_provider();
    ///
    /// // tracer used in applications/binaries
    /// let tracer = provider.tracer("my_app");
    ///
    /// // tracer used in libraries/crates that optionally includes version and schema url
    /// let tracer = provider.versioned_tracer(
    ///     "my_library",
    ///     Some(env!("CARGO_PKG_VERSION")),
    ///     Some("https://opentelemetry.io/schema/1.0.0"),
    ///     None,
    /// );
    /// ```
    #[deprecated(since = "0.23.0", note = "Please use tracer_builder() instead")]
    fn versioned_tracer(
        &self,
        name: impl Into<Cow<'static, str>>,
        version: Option<impl Into<Cow<'static, str>>>,
        schema_url: Option<impl Into<Cow<'static, str>>>,
        attributes: Option<Vec<KeyValue>>,
    ) -> Self::Tracer {
        let mut builder = self.tracer_builder(name);
        if let Some(v) = version {
            builder = builder.with_version(v);
        }
        if let Some(s) = schema_url {
            builder = builder.with_version(s);
        }
        if let Some(a) = attributes {
            builder = builder.with_attributes(a);
        }

        builder.build()
    }

    /// Returns a new builder for creating a [`Tracer`] instance
    ///
    /// The `name` should be the application name or the name of the library
    /// providing instrumentation. If the name is empty, then an
    /// implementation-defined default name may be used instead.
    ///
    /// # Examples
    ///
    /// ```
    /// use opentelemetry::{global, trace::TracerProvider};
    ///
    /// let provider = global::tracer_provider();
    ///
    /// // tracer used in applications/binaries
    /// let tracer = provider.tracer_builder("my_app").build();
    ///
    /// // tracer used in libraries/crates that optionally includes version and schema url
    /// let tracer = provider.tracer_builder("my_library")
    ///     .with_version(env!("CARGO_PKG_VERSION"))
    ///     .with_schema_url("https://opentelemetry.io/schema/1.0.0")
    ///     .build();
    /// ```
    fn tracer_builder(&self, name: impl Into<Cow<'static, str>>) -> TracerBuilder<'_, Self> {
        TracerBuilder {
            provider: self,
            library_builder: InstrumentationLibrary::builder(name),
        }
    }

    /// Returns a new versioned tracer with the given instrumentation library.
    ///
    /// # Examples
    ///
    /// ```
    /// use opentelemetry::{global, InstrumentationLibrary, trace::TracerProvider};
    ///
    /// let provider = global::tracer_provider();
    ///
    /// // tracer used in applications/binaries
    /// let tracer = provider.tracer("my_app");
    ///
    /// // tracer used in libraries/crates that optionally includes version and schema url
    /// let library = std::sync::Arc::new(
    ///     InstrumentationLibrary::builder(env!("CARGO_PKG_NAME"))
    ///         .with_version(env!("CARGO_PKG_VERSION"))
    ///         .with_schema_url("https://opentelemetry.io/schema/1.0.0")
    ///         .build(),
    /// );
    ///
    /// let tracer = provider.library_tracer(library);
    /// ```
    fn library_tracer(&self, library: Arc<InstrumentationLibrary>) -> Self::Tracer;
}

#[derive(Debug)]
pub struct TracerBuilder<'a, T: TracerProvider + ?Sized> {
    provider: &'a T,
    library_builder: InstrumentationLibraryBuilder,
}

impl<'a, T: TracerProvider + ?Sized> TracerBuilder<'a, T> {
    pub fn with_version(mut self, version: impl Into<Cow<'static, str>>) -> Self {
        self.library_builder = self.library_builder.with_version(version);
        self
    }

    pub fn with_schema_url(mut self, schema_url: impl Into<Cow<'static, str>>) -> Self {
        self.library_builder = self.library_builder.with_schema_url(schema_url);
        self
    }

    pub fn with_attributes<I>(mut self, attributes: I) -> Self
    where
        I: IntoIterator<Item = KeyValue>,
    {
        self.library_builder = self.library_builder.with_attributes(attributes);
        self
    }

    pub fn build(self) -> T::Tracer {
        self.provider
            .library_tracer(Arc::new(self.library_builder.build()))
    }
}