From ce469b4e6722a40c8a3b648924245db7524bb927 Mon Sep 17 00:00:00 2001 From: Zhongyang Wu Date: Wed, 2 Sep 2020 21:46:26 -0400 Subject: [PATCH] Add InstrumentationLibrary for instrumentation library information (#207) --- benches/trace.rs | 4 +-- examples/stdout.rs | 2 +- opentelemetry-jaeger/src/lib.rs | 2 +- .../propagation/composite_propagator.rs | 2 +- src/api/trace/context.rs | 2 +- src/api/trace/noop.rs | 2 +- src/api/trace/provider.rs | 4 +-- src/global/mod.rs | 9 +++-- src/global/trace.rs | 34 +++++++++++++++---- src/sdk/instrumentation.rs | 25 ++++++++++++++ src/sdk/mod.rs | 2 ++ src/sdk/trace/provider.rs | 12 ++++--- src/sdk/trace/tracer.rs | 26 ++++++++++---- 13 files changed, 96 insertions(+), 30 deletions(-) create mode 100644 src/sdk/instrumentation.rs diff --git a/benches/trace.rs b/benches/trace.rs index 240b1f6c76..9b8d7f97f8 100644 --- a/benches/trace.rs +++ b/benches/trace.rs @@ -74,7 +74,7 @@ fn trace_benchmark_group(c: &mut Criterion, name: &str, f: ..Default::default() }) .build() - .get_tracer("always-sample"); + .get_tracer("always-sample", None); b.iter(|| f(&always_sample)); }); @@ -86,7 +86,7 @@ fn trace_benchmark_group(c: &mut Criterion, name: &str, f: ..Default::default() }) .build() - .get_tracer("never-sample"); + .get_tracer("never-sample", None); b.iter(|| f(&never_sample)); }); diff --git a/examples/stdout.rs b/examples/stdout.rs index 5ca15c1049..7fbaafac7b 100644 --- a/examples/stdout.rs +++ b/examples/stdout.rs @@ -20,6 +20,6 @@ fn main() { global::set_provider(provider); global::trace_provider() - .get_tracer("component-main") + .get_tracer("component-main", None) .in_span("operation", |_cx| {}); } diff --git a/opentelemetry-jaeger/src/lib.rs b/opentelemetry-jaeger/src/lib.rs index decc982c67..a2004fabc3 100644 --- a/opentelemetry-jaeger/src/lib.rs +++ b/opentelemetry-jaeger/src/lib.rs @@ -304,7 +304,7 @@ impl PipelineBuilder { /// Install a Jaeger pipeline with the recommended defaults. pub fn install(self) -> Result> { let trace_provider = self.build()?; - let tracer = trace_provider.get_tracer("opentelemetry-jaeger"); + let tracer = trace_provider.get_tracer("opentelemetry-jaeger", None); global::set_provider(trace_provider); diff --git a/src/api/context/propagation/composite_propagator.rs b/src/api/context/propagation/composite_propagator.rs index a0bc60daf7..473288d3c2 100644 --- a/src/api/context/propagation/composite_propagator.rs +++ b/src/api/context/propagation/composite_propagator.rs @@ -35,7 +35,7 @@ use std::fmt::Debug; /// let mut injector = HashMap::new(); /// /// // And a given span -/// let example_span = sdk::TracerProvider::default().get_tracer("example-component").start("span-name"); +/// let example_span = sdk::TracerProvider::default().get_tracer("example-component", None).start("span-name"); /// /// // with the current context, call inject to add the headers /// composite_propagator.inject_context(&Context::current_with_span(example_span) diff --git a/src/api/trace/context.rs b/src/api/trace/context.rs index 9596d730c7..9e881cb575 100644 --- a/src/api/trace/context.rs +++ b/src/api/trace/context.rs @@ -31,7 +31,7 @@ pub trait TraceContextExt { /// // returns a reference to an empty span by default /// assert_eq!(Context::current().span().span_context(), api::SpanContext::empty_context()); /// - /// sdk::TracerProvider::default().get_tracer("my-component").in_span("my-span", |cx| { + /// sdk::TracerProvider::default().get_tracer("my-component", None).in_span("my-span", |cx| { /// // Returns a reference to the current span if set /// assert_ne!(cx.span().span_context(), api::SpanContext::empty_context()); /// }); diff --git a/src/api/trace/noop.rs b/src/api/trace/noop.rs index 89cbb14083..340c8e4f44 100644 --- a/src/api/trace/noop.rs +++ b/src/api/trace/noop.rs @@ -16,7 +16,7 @@ impl api::TracerProvider for NoopProvider { type Tracer = NoopTracer; /// Returns a new `NoopTracer` instance. - fn get_tracer(&self, _name: &'static str) -> Self::Tracer { + fn get_tracer(&self, _name: &'static str, _version: Option<&'static str>) -> Self::Tracer { NoopTracer {} } } diff --git a/src/api/trace/provider.rs b/src/api/trace/provider.rs index bbcb022a07..8e33b16971 100644 --- a/src/api/trace/provider.rs +++ b/src/api/trace/provider.rs @@ -18,7 +18,7 @@ //! the SDK to suppress telemetry produced by this library. //! //! Implementations might require the user to specify configuration properties at -//! `TracerProvider` creation time, or rely on external configuration. +//! `TracerProvider` creation time, or rely on external configurations. use crate::api; use std::fmt; @@ -29,5 +29,5 @@ pub trait TracerProvider: fmt::Debug + 'static { /// Creates a named tracer instance of `Self::Tracer`. /// If the name is an empty string then provider uses default name. - fn get_tracer(&self, name: &'static str) -> Self::Tracer; + fn get_tracer(&self, name: &'static str, version: Option<&'static str>) -> Self::Tracer; } diff --git a/src/global/mod.rs b/src/global/mod.rs index 0521325c85..5e715b6e04 100644 --- a/src/global/mod.rs +++ b/src/global/mod.rs @@ -27,10 +27,13 @@ //! // Then you can use the global provider to create a tracer via `tracer`. //! let _span = global::tracer("my-component").start("span-name"); //! +//! // You can also get the tracer via name and version. +//! let _tracer = global::tracer_with_version("another-component", "1.1.1"); +//! //! // Or access the configured provider via `trace_provider`. //! let provider = global::trace_provider(); -//! let _tracer_a = provider.get_tracer("my-component-a"); -//! let _tracer_b = provider.get_tracer("my-component-b"); +//! let _tracer_a = provider.get_tracer("my-component-a", None); +//! let _tracer_b = provider.get_tracer("my-component-b", None); //! } //! //! // in main or other app start @@ -84,4 +87,4 @@ pub use metrics::{meter, meter_provider, set_meter_provider}; #[cfg(feature = "trace")] pub use propagation::{get_text_map_propagator, set_text_map_propagator}; #[cfg(feature = "trace")] -pub use trace::{set_provider, trace_provider, tracer, GenericProvider}; +pub use trace::{set_provider, trace_provider, tracer, tracer_with_version, GenericProvider}; diff --git a/src/global/trace.rs b/src/global/trace.rs index e242f7e168..fe22dba7c5 100644 --- a/src/global/trace.rs +++ b/src/global/trace.rs @@ -10,6 +10,7 @@ use std::time::SystemTime; /// [`Span`]: ../api/trace/span/trait.Span.html #[derive(Debug)] pub struct BoxedSpan(Box); + type DynSpan = dyn api::Span + Send + Sync; impl api::Span for BoxedSpan { @@ -163,7 +164,11 @@ where /// [`GlobalProvider`]: struct.GlobalProvider.html pub trait GenericProvider: fmt::Debug + 'static { /// Creates a named tracer instance that is a trait object through the underlying `TracerProvider`. - fn get_tracer_boxed(&self, name: &'static str) -> Box; + fn get_tracer_boxed( + &self, + name: &'static str, + version: Option<&'static str>, + ) -> Box; } impl GenericProvider for P @@ -173,8 +178,12 @@ where P: api::TracerProvider, { /// Return a boxed generic tracer - fn get_tracer_boxed(&self, name: &'static str) -> Box { - Box::new(self.get_tracer(name)) + fn get_tracer_boxed( + &self, + name: &'static str, + version: Option<&'static str>, + ) -> Box { + Box::new(self.get_tracer(name, version)) } } @@ -207,8 +216,8 @@ impl api::TracerProvider for GlobalProvider { type Tracer = BoxedTracer; /// Find or create a named tracer using the global provider. - fn get_tracer(&self, name: &'static str) -> Self::Tracer { - BoxedTracer(self.provider.get_tracer_boxed(name)) + fn get_tracer(&self, name: &'static str, version: Option<&'static str>) -> Self::Tracer { + BoxedTracer(self.provider.get_tracer_boxed(name, version)) } } @@ -233,12 +242,23 @@ pub fn trace_provider() -> GlobalProvider { /// /// If the name is an empty string, the provider will use a default name. /// -/// This is a more convenient way of expressing `global::trace_provider().get_tracer(name)`. +/// This is a more convenient way of expressing `global::trace_provider().get_tracer(name, None)`. /// /// [`Tracer`]: ../api/trace/tracer/trait.Tracer.html /// [`GlobalProvider`]: struct.GlobalProvider.html pub fn tracer(name: &'static str) -> BoxedTracer { - trace_provider().get_tracer(name) + trace_provider().get_tracer(name, None) +} + +/// Creates a named instance of [`Tracer`] with version info via the configured [`GlobalProvider`] +/// +/// If the name is an empty string, the provider will use a default name. +/// If the version is an empty string, it will be used as part of instrumentation library information. +/// +/// [`Tracer`]: ../api/trace/tracer/trait.Tracer.html +/// [`GlobalProvider`]: struct.GlobalProvider.html +pub fn tracer_with_version(name: &'static str, version: &'static str) -> BoxedTracer { + trace_provider().get_tracer(name, Some(version)) } /// Sets the given [`TracerProvider`] instance as the current global provider. diff --git a/src/sdk/instrumentation.rs b/src/sdk/instrumentation.rs new file mode 100644 index 0000000000..11897c8f79 --- /dev/null +++ b/src/sdk/instrumentation.rs @@ -0,0 +1,25 @@ +//! Provides instrumentation information for both tracing and metric. +//! See `OTEPS-0083` for details. +//! +//! [OTEPS-0083](https://github.com/open-telemetry/oteps/blob/master/text/0083-component.md) + +/// InstrumentationLibrary contains information about instrumentation library. +/// +/// See `Instrumentation Libraries` for more information. +/// +/// [`Instrumentation Libraries`](https://github.com/open-telemetry/opentelemetry-specification/blob/master/specification/overview.md#instrumentation-libraries) +#[derive(Debug, Default, Hash, Copy, Clone, PartialEq, Eq)] +#[non_exhaustive] +pub struct InstrumentationLibrary { + /// instrumentation library name, cannot be empty + pub name: &'static str, + /// instrumentation library version, can be empty + pub version: Option<&'static str>, +} + +impl InstrumentationLibrary { + /// Create an InstrumentationLibrary from name and version. + pub fn new(name: &'static str, version: Option<&'static str>) -> InstrumentationLibrary { + InstrumentationLibrary { name, version } + } +} diff --git a/src/sdk/mod.rs b/src/sdk/mod.rs index 716b32d373..163cac8d78 100644 --- a/src/sdk/mod.rs +++ b/src/sdk/mod.rs @@ -8,6 +8,7 @@ //! `Meter` creation. pub mod env; pub mod export; +pub mod instrumentation; #[cfg(feature = "metrics")] pub mod metrics; pub mod resource; @@ -15,6 +16,7 @@ pub mod resource; pub mod trace; pub use env::EnvResourceDetector; +pub use instrumentation::InstrumentationLibrary; pub use resource::Resource; #[cfg(feature = "trace")] pub use trace::{ diff --git a/src/sdk/trace/provider.rs b/src/sdk/trace/provider.rs index ad70bdb08b..462e0a4b9b 100644 --- a/src/sdk/trace/provider.rs +++ b/src/sdk/trace/provider.rs @@ -19,7 +19,7 @@ const DEFAULT_COMPONENT_NAME: &str = "rust.opentelemetry.io/sdk/tracer"; /// TracerProvider inner type #[derive(Debug)] struct ProviderInner { - named_tracers: RwLock>, + named_tracers: RwLock>, processors: Vec>, config: sdk::Config, } @@ -66,7 +66,7 @@ impl api::TracerProvider for TracerProvider { type Tracer = sdk::Tracer; /// Find or create `Tracer` instance by name. - fn get_tracer(&self, name: &'static str) -> Self::Tracer { + fn get_tracer(&self, name: &'static str, version: Option<&'static str>) -> Self::Tracer { // Use default value if name is invalid empty string let component_name = if name.is_empty() { DEFAULT_COMPONENT_NAME @@ -74,21 +74,23 @@ impl api::TracerProvider for TracerProvider { name }; + let instrumentation_lib = sdk::InstrumentationLibrary::new(component_name, version); + // Return named tracer if already initialized if let Some(tracer) = self .inner .named_tracers .read() .expect("RwLock poisoned") - .get(&component_name) + .get(&instrumentation_lib) { 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()); + let new_tracer = sdk::Tracer::new(instrumentation_lib, self.clone()); + tracers.insert(instrumentation_lib, new_tracer.clone()); new_tracer } diff --git a/src/sdk/trace/tracer.rs b/src/sdk/trace/tracer.rs index a5672f54f7..352293665f 100644 --- a/src/sdk/trace/tracer.rs +++ b/src/sdk/trace/tracer.rs @@ -17,7 +17,7 @@ use std::time::SystemTime; /// `Tracer` implementation to create and manage spans #[derive(Clone)] pub struct Tracer { - name: &'static str, + instrumentation_lib: sdk::InstrumentationLibrary, provider: sdk::TracerProvider, } @@ -25,21 +25,35 @@ impl fmt::Debug for Tracer { /// Formats the `Tracer` using the given formatter. /// Omitting `provider` here is necessary to avoid cycles. fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("Tracer").field("name", &self.name).finish() + f.debug_struct("Tracer") + .field("name", &self.instrumentation_lib.name) + .field("version", &self.instrumentation_lib.version) + .finish() } } impl Tracer { - /// Create a new tracer (used internally by `TracerProvider`s. - pub(crate) fn new(name: &'static str, provider: sdk::TracerProvider) -> Self { - Tracer { name, provider } + /// Create a new tracer (used internally by `TracerProvider`s). + pub(crate) fn new( + instrumentation_lib: sdk::InstrumentationLibrary, + provider: sdk::TracerProvider, + ) -> Self { + Tracer { + instrumentation_lib, + provider, + } } - /// TracerProvider associated with this tracer + /// TracerProvider associated with this tracer. pub fn provider(&self) -> &sdk::TracerProvider { &self.provider } + /// instrumentation library information of this tracer. + pub fn instrumentation_library(&self) -> &sdk::InstrumentationLibrary { + &self.instrumentation_lib + } + /// Make a sampling decision using the provided sampler for the span and context. #[allow(clippy::too_many_arguments)] fn make_sampling_decision(