diff --git a/opentelemetry-jaeger/src/lib.rs b/opentelemetry-jaeger/src/lib.rs index 12fc34e3ab..4b4818c657 100644 --- a/opentelemetry-jaeger/src/lib.rs +++ b/opentelemetry-jaeger/src/lib.rs @@ -217,7 +217,7 @@ impl Builder { /// Assign the collector endpoint. #[cfg(feature = "collector_client")] - pub fn with_collector_endpoint>(self, collector_endpoint: T) -> Self { + pub fn with_collector_endpoint>(self, collector_endpoint: S) -> Self { Builder { collector_endpoint: Some(collector_endpoint.into()), ..self @@ -226,7 +226,7 @@ impl Builder { /// Assign the collector username #[cfg(feature = "collector_client")] - pub fn with_collector_username>(self, collector_username: T) -> Self { + pub fn with_collector_username>(self, collector_username: S) -> Self { Builder { collector_username: Some(collector_username.into()), ..self @@ -235,7 +235,7 @@ impl Builder { /// Assign the collector password #[cfg(feature = "collector_client")] - pub fn with_collector_password>(self, collector_password: T) -> Self { + pub fn with_collector_password>(self, collector_password: S) -> Self { Builder { collector_password: Some(collector_password.into()), ..self diff --git a/opentelemetry-jaeger/src/thrift/agent.rs b/opentelemetry-jaeger/src/thrift/agent.rs index 87fbad705b..d4784b4e23 100644 --- a/opentelemetry-jaeger/src/thrift/agent.rs +++ b/opentelemetry-jaeger/src/thrift/agent.rs @@ -68,7 +68,7 @@ impl TAgentSyncClient for C { { self.increment_sequence_number(); let message_ident = TMessageIdentifier::new("emitZipkinBatch", TMessageType::OneWay, self.sequence_number()); - let call_args = AgentEmitZipkinBatchArgs { spans: spans }; + let call_args = AgentEmitZipkinBatchArgs { spans }; self.o_prot_mut().write_message_begin(&message_ident)?; call_args.write_to_out_protocol(self.o_prot_mut())?; self.o_prot_mut().write_message_end()?; @@ -82,7 +82,7 @@ impl TAgentSyncClient for C { { self.increment_sequence_number(); let message_ident = TMessageIdentifier::new("emitBatch", TMessageType::OneWay, self.sequence_number()); - let call_args = AgentEmitBatchArgs { batch: batch }; + let call_args = AgentEmitBatchArgs { batch }; self.o_prot_mut().write_message_begin(&message_ident)?; call_args.write_to_out_protocol(self.o_prot_mut())?; self.o_prot_mut().write_message_end()?; diff --git a/opentelemetry-jaeger/src/thrift/jaeger.rs b/opentelemetry-jaeger/src/thrift/jaeger.rs index 51b1f2d8e1..314674fb87 100644 --- a/opentelemetry-jaeger/src/thrift/jaeger.rs +++ b/opentelemetry-jaeger/src/thrift/jaeger.rs @@ -119,8 +119,8 @@ pub struct Tag { impl Tag { pub fn new(key: String, v_type: TagType, v_str: F3, v_double: F4, v_bool: F5, v_long: F6, v_binary: F7) -> Tag where F3: Into>, F4: Into>>, F5: Into>, F6: Into>, F7: Into>> { Tag { - key: key, - v_type: v_type, + key, + v_type, v_str: v_str.into(), v_double: v_double.into(), v_bool: v_bool.into(), @@ -259,8 +259,8 @@ pub struct Log { impl Log { pub fn new(timestamp: i64, fields: Vec) -> Log { Log { - timestamp: timestamp, - fields: fields, + timestamp, + fields, } } pub fn read_from_in_protocol(i_prot: &mut dyn TInputProtocol) -> thrift::Result { @@ -336,10 +336,10 @@ pub struct SpanRef { impl SpanRef { pub fn new(ref_type: SpanRefType, trace_id_low: i64, trace_id_high: i64, span_id: i64) -> SpanRef { SpanRef { - ref_type: ref_type, - trace_id_low: trace_id_low, - trace_id_high: trace_id_high, - span_id: span_id, + ref_type, + trace_id_low, + trace_id_high, + span_id, } } pub fn read_from_in_protocol(i_prot: &mut dyn TInputProtocol) -> thrift::Result { @@ -432,15 +432,15 @@ pub struct Span { impl Span { pub fn new(trace_id_low: i64, trace_id_high: i64, span_id: i64, parent_span_id: i64, operation_name: String, references: F6, flags: i32, start_time: i64, duration: i64, tags: F10, logs: F11) -> Span where F6: Into>>, F10: Into>>, F11: Into>> { Span { - trace_id_low: trace_id_low, - trace_id_high: trace_id_high, - span_id: span_id, - parent_span_id: parent_span_id, - operation_name: operation_name, + trace_id_low, + trace_id_high, + span_id, + parent_span_id, + operation_name, references: references.into(), - flags: flags, - start_time: start_time, - duration: duration, + flags, + start_time, + duration, tags: tags.into(), logs: logs.into(), } @@ -638,7 +638,7 @@ pub struct Process { impl Process { pub fn new(service_name: String, tags: F2) -> Process where F2: Into>> { Process { - service_name: service_name, + service_name, tags: tags.into(), } } @@ -717,8 +717,8 @@ pub struct Batch { impl Batch { pub fn new(process: Process, spans: Vec) -> Batch { Batch { - process: process, - spans: spans, + process, + spans, } } pub fn read_from_in_protocol(i_prot: &mut dyn TInputProtocol) -> thrift::Result { @@ -791,7 +791,7 @@ pub struct BatchSubmitResponse { impl BatchSubmitResponse { pub fn new(ok: bool) -> BatchSubmitResponse { BatchSubmitResponse { - ok: ok, + ok, } } pub fn read_from_in_protocol(i_prot: &mut dyn TInputProtocol) -> thrift::Result { @@ -869,7 +869,7 @@ impl TCollectorSyncClient for C { self.increment_sequence_number(); let message_ident = TMessageIdentifier::new("submitBatches", TMessageType::Call, self.sequence_number()); - let call_args = CollectorSubmitBatchesArgs { batches: batches }; + let call_args = CollectorSubmitBatchesArgs { batches }; self.o_prot_mut().write_message_begin(&message_ident)?; call_args.write_to_out_protocol(self.o_prot_mut())?; self.o_prot_mut().write_message_end()?; diff --git a/opentelemetry-jaeger/src/thrift/zipkincore.rs b/opentelemetry-jaeger/src/thrift/zipkincore.rs index d9719756af..30285b77c8 100644 --- a/opentelemetry-jaeger/src/thrift/zipkincore.rs +++ b/opentelemetry-jaeger/src/thrift/zipkincore.rs @@ -735,7 +735,8 @@ pub struct Response { impl Response { pub fn new(ok: bool) -> Response { Response { - ok: ok, + ok, + } } pub fn read_from_in_protocol(i_prot: &mut dyn TInputProtocol) -> thrift::Result { @@ -845,7 +846,7 @@ impl TZipkinCollectorSyncC { self.increment_sequence_number(); let message_ident = TMessageIdentifier::new("submitZipkinBatch", TMessageType::Call, self.sequence_number()); - let call_args = ZipkinCollectorSubmitZipkinBatchArgs { spans: spans }; + let call_args = ZipkinCollectorSubmitZipkinBatchArgs { spans }; self.o_prot_mut().write_message_begin(&message_ident)?; call_args.write_to_out_protocol(self.o_prot_mut())?; self.o_prot_mut().write_message_end()?; diff --git a/opentelemetry-jaeger/src/transport/http.rs b/opentelemetry-jaeger/src/transport/http.rs index 8d9cc15bbc..43a1641190 100644 --- a/opentelemetry-jaeger/src/transport/http.rs +++ b/opentelemetry-jaeger/src/transport/http.rs @@ -1,6 +1,5 @@ //! Thrift HTTP transport use reqwest::header; -use std::error::Error; use std::fmt; use std::sync::{Arc, Mutex}; use thrift::{TransportError, TransportErrorKind}; @@ -48,7 +47,7 @@ impl THttpChannel { .map_err(|err| { thrift::Error::Transport(TransportError::new( TransportErrorKind::Unknown, - err.description(), + err.to_string(), )) })?; @@ -87,7 +86,7 @@ impl std::io::Read for THttpChannel { let mut data = self .read_buffer .lock() - .map_err(|err| std::io::Error::new(std::io::ErrorKind::Other, err.description()))?; + .map_err(|err| std::io::Error::new(std::io::ErrorKind::Other, err.to_string()))?; let amt = data.as_slice().read(buf)?; if amt > 0 { @@ -109,7 +108,7 @@ impl std::io::Write for THttpChannel { let mut write_buffer = self .write_buffer .lock() - .map_err(|err| std::io::Error::new(std::io::ErrorKind::Other, err.description()))?; + .map_err(|err| std::io::Error::new(std::io::ErrorKind::Other, err.to_string()))?; write_buffer.extend_from_slice(buf); Ok(buf.len()) @@ -120,7 +119,7 @@ impl std::io::Write for THttpChannel { let mut write_buffer = self .write_buffer .lock() - .map_err(|err| std::io::Error::new(std::io::ErrorKind::Other, err.description()))?; + .map_err(|err| std::io::Error::new(std::io::ErrorKind::Other, err.to_string()))?; let mut req = self.client.post(&self.endpoint).body(write_buffer.clone()); if let (Some(username), Some(password)) = (self.username.as_ref(), self.password.as_ref()) { req = req.basic_auth(username, Some(password)); @@ -142,7 +141,7 @@ impl std::io::Write for THttpChannel { let mut read_buffer = self .read_buffer .lock() - .map_err(|err| std::io::Error::new(std::io::ErrorKind::Other, err.description()))?; + .map_err(|err| std::io::Error::new(std::io::ErrorKind::Other, err.to_string()))?; resp.copy_to(&mut *read_buffer) .map_err(|err| std::io::Error::new(std::io::ErrorKind::Other, err))?; diff --git a/opentelemetry-zipkin/src/lib.rs b/opentelemetry-zipkin/src/lib.rs index 74f0bbddde..f4d74a23ba 100644 --- a/opentelemetry-zipkin/src/lib.rs +++ b/opentelemetry-zipkin/src/lib.rs @@ -31,6 +31,8 @@ //! } //! ``` //! +#![deny(missing_docs, unreachable_pub, missing_debug_implementations)] +#![cfg_attr(test, deny(warnings))] #[macro_use] extern crate typed_builder; @@ -83,6 +85,7 @@ impl Default for ExporterConfigBuilder { } impl ExporterConfig { + /// Create an export config builder pub fn builder() -> ExporterConfigBuilder { ExporterConfigBuilder::default() } diff --git a/opentelemetry-zipkin/src/model/endpoint.rs b/opentelemetry-zipkin/src/model/endpoint.rs index 025b26d7c1..94436206fd 100644 --- a/opentelemetry-zipkin/src/model/endpoint.rs +++ b/opentelemetry-zipkin/src/model/endpoint.rs @@ -3,7 +3,7 @@ use std::net::{Ipv4Addr, Ipv6Addr}; #[derive(TypedBuilder, Clone, Debug, Serialize)] #[serde(rename_all = "camelCase")] -pub struct Endpoint { +pub(crate) struct Endpoint { #[builder(setter(strip_option), default)] #[serde(skip_serializing_if = "Option::is_none")] service_name: Option, diff --git a/opentelemetry-zipkin/src/model/span.rs b/opentelemetry-zipkin/src/model/span.rs index 11ed6b400a..3ce4131dfd 100644 --- a/opentelemetry-zipkin/src/model/span.rs +++ b/opentelemetry-zipkin/src/model/span.rs @@ -3,11 +3,11 @@ use serde::Serialize; use std::collections::HashMap; #[derive(Serialize)] -pub struct ListOfSpans(pub(crate) Vec); +pub(crate) struct ListOfSpans(pub(crate) Vec); #[derive(Clone, Debug, Serialize)] #[serde(rename_all = "SCREAMING_SNAKE_CASE")] -pub enum Kind { +pub(crate) enum Kind { Client, Server, Producer, @@ -16,7 +16,7 @@ pub enum Kind { #[derive(TypedBuilder, Clone, Debug, Serialize)] #[serde(rename_all = "camelCase")] -pub struct Span { +pub(crate) struct Span { #[builder(setter(strip_option), default)] #[serde(skip_serializing_if = "Option::is_none")] trace_id: Option, diff --git a/opentelemetry-zipkin/src/uploader.rs b/opentelemetry-zipkin/src/uploader.rs index 68de7f3803..23e06c48f4 100644 --- a/opentelemetry-zipkin/src/uploader.rs +++ b/opentelemetry-zipkin/src/uploader.rs @@ -6,7 +6,7 @@ use opentelemetry::exporter::trace; static API_V2_COLLECTOR_ROUTE: &str = "/api/v2/spans"; #[derive(Clone, Debug)] -pub enum UploaderFormat { +pub(crate) enum UploaderFormat { HTTP, } diff --git a/scripts/lint.sh b/scripts/lint.sh index ce482f4b3c..5d00ee485c 100755 --- a/scripts/lint.sh +++ b/scripts/lint.sh @@ -3,7 +3,7 @@ set -eu if rustup component add clippy; then - cargo clippy --all-targets --all -- \ + cargo clippy --all-targets --all-features --workspace -- \ `# Exit with a nonzero code if there are clippy warnings` \ -Dwarnings \ "$@" diff --git a/src/api/metrics/measure.rs b/src/api/metrics/measure.rs index 1548899379..9c1b41a343 100644 --- a/src/api/metrics/measure.rs +++ b/src/api/metrics/measure.rs @@ -14,7 +14,7 @@ //! durations and sizes. //! //! When passing `MetricOptions`, measures can be declared as -//! `with_abslute(false)` to indicate support for positive and negative values. +//! `with_absolute(false)` to indicate support for positive and negative values. use crate::api::metrics; /// An interface for recording values where the count or rate of diff --git a/src/api/mod.rs b/src/api/mod.rs index 490746d7c8..9fd167a82f 100644 --- a/src/api/mod.rs +++ b/src/api/mod.rs @@ -27,9 +27,9 @@ pub use metrics::{ value::MeasurementValue, Instrument, InstrumentHandle, LabelSet, Measurement, Meter, MetricOptions, }; -pub use propagation::{binary_propagator::BinaryFormat, text_propagator::HttpTextFormat, Carrier}; -#[cfg(feature="base64_format")] +#[cfg(feature = "base64_format")] pub use propagation::base64_format::Base64Format; +pub use propagation::{binary_propagator::BinaryFormat, text_propagator::HttpTextFormat, Carrier}; pub use trace::{ b3_propagator::B3Propagator, event::Event, diff --git a/src/api/trace/noop.rs b/src/api/trace/noop.rs index 3627ecc854..ca8d7f956f 100644 --- a/src/api/trace/noop.rs +++ b/src/api/trace/noop.rs @@ -77,7 +77,7 @@ impl api::Span for NoopSpan { // Ignored } - /// Ignors name updates + /// Ignores name updates fn update_name(&mut self, _new_name: String) { // Ignored } diff --git a/src/api/trace/provider.rs b/src/api/trace/provider.rs index 64307ef7c9..d1561f7f64 100644 --- a/src/api/trace/provider.rs +++ b/src/api/trace/provider.rs @@ -20,9 +20,10 @@ //! Implementations might require the user to specify configuration properties at //! `Provider` creation time, or rely on external configuration. use crate::api; +use std::fmt; /// An interface to create `Tracer` instances. -pub trait Provider: Send + Sync { +pub trait Provider: fmt::Debug + 'static { /// The `Tracer` type that this `Provider` will return. type Tracer: api::Tracer; diff --git a/src/api/trace/span.rs b/src/api/trace/span.rs index 185679d8e0..dd3f36cd25 100644 --- a/src/api/trace/span.rs +++ b/src/api/trace/span.rs @@ -18,10 +18,11 @@ use crate::api; #[cfg(feature = "serialize")] use serde::{Deserialize, Serialize}; +use std::fmt; use std::time::SystemTime; /// Interface for a single operation within a trace. -pub trait Span: Send + Sync + std::fmt::Debug { +pub trait Span: fmt::Debug + 'static { /// An API to record events in the context of a given `Span`. /// /// Events have a time associated with the moment when they are diff --git a/src/api/trace/tracer.rs b/src/api/trace/tracer.rs index e610e7144a..e434698ab8 100644 --- a/src/api/trace/tracer.rs +++ b/src/api/trace/tracer.rs @@ -22,10 +22,11 @@ //! //! Docs: https://github.com/open-telemetry/opentelemetry-specification/blob/master/specification/api-tracing.md#tracer use crate::api::{self, Span}; +use std::fmt; use std::time::SystemTime; /// Interface for constructing `Span`s. -pub trait Tracer: Send + Sync { +pub trait Tracer: fmt::Debug + 'static { /// The `Span` type used by this `Tracer`. type Span: api::Span; diff --git a/src/global.rs b/src/global.rs index 47312f7172..425dd08ede 100644 --- a/src/global.rs +++ b/src/global.rs @@ -1,46 +1,123 @@ -//! OpenTelemetry global `Tracer` and `Meter` singletons. +//! # OpenTelemetry Global API +//! +//! The global API **provides applications access to their configured +//! [`Provider`] instance from anywhere in the codebase**. This allows +//! applications to be less coupled to the specific Open Telemetry SDK as +//! well as not manually pass references to each part of the code that needs +//! to create [`Span`]s. Additionally, **3rd party middleware** or **library code** +//! can be written against this generic API and not constrain users to a +//! specific implementation choice. +//! +//! ## Usage +//! +//! ```rust +//! use opentelemetry::api::{Provider, Tracer}; +//! use opentelemetry::global; +//! +//! fn init_tracer() { +//! let provider = opentelemetry::api::NoopProvider {}; +//! +//! // Configure the global `Provider` singleton when your app starts +//! // (there is a no-op default if this is not set by your application) +//! global::set_provider(provider); +//! } +//! +//! fn do_something_tracked() { +//! // Then you can access the configured provider via `trace_provider`. +//! let provider = global::trace_provider(); +//! let _span = provider.get_tracer("my-component").start("span-name", None); +//! } +//! +//! // in main or other app start +//! init_tracer(); +//! do_something_tracked(); +//! ``` +//! +//! ## Implementation +//! +//! This module provides types for working with the Open Telemetry API in an +//! abstract implementation-agnostic way through the use of [trait objects]. +//! There is a **performance penalty** due to global synchronization as well +//! as heap allocation and dynamic dispatch (e.g. `Box` vs +//! `sdk::Span`), but for many applications this overhead is likely either +//! insignificant or unavoidable as it is in the case of 3rd party integrations +//! that do not know the span type at compile time. +//! +//! ### Generic interface +//! +//! The generic interface is provided by the [`GlobalProvider`] struct which +//! can be accessed anywhere via [`trace_provider`] and allows applications to +//! use the [`BoxedTracer`] and [`BoxedSpan`] instances that implement +//! [`Tracer`] and [`Span`]. They wrap a boxed dyn [`GenericProvider`], +//! [`GenericTracer`], and [`Span`] respectively allowing the underlying +//! implementation to be set at runtime. +//! +//! [`Provider`]: ../api/trace/provider/trait.Provider.html +//! [`Tracer`]: ../api/trace/tracer/trait.Tracer.html +//! [`Span`]: ../api/trace/span/trait.Span.html +//! [`GenericProvider`]: trait.GenericProvider.html +//! [`GenericTracer`]: trait.GenericTracer.html +//! [`GlobalProvider`]: struct.GlobalProvider.html +//! [`BoxedTracer`]: struct.BoxedTracer.html +//! [`BoxedSpan`]: struct.BoxedSpan.html +//! [`trace_provider`]: fn.trace_provider.html +//! [trait objects]: https://doc.rust-lang.org/reference/types/trait-object.html#trait-objects use crate::api; use std::any::Any; +use std::fmt; 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. +/// Wraps the [`BoxedTracer`]'s [`Span`] so it can be used generically by +/// applications without knowing the underlying type. +/// +/// [`BoxedTracer`]: struct.BoxedTracer.html +/// [`Span`]: ../api/trace/span/trait.Span.html #[derive(Debug)] pub struct BoxedSpan(Box); impl api::Span for BoxedSpan { - /// Delegates to inner span.0 + /// Records events at a specific time in the context of a given `Span`. + /// + /// Note that the OpenTelemetry project documents certain ["standard event names and + /// keys"](https://github.com/open-telemetry/opentelemetry-specification/blob/master/specification/data-semantic-conventions.md) + /// which have prescribed semantic meanings. fn add_event_with_timestamp(&mut self, message: String, timestamp: SystemTime) { self.0.add_event_with_timestamp(message, timestamp) } - /// Delegates to inner span. + /// Returns the `SpanContext` for the given `Span`. fn get_context(&self) -> api::SpanContext { self.0.get_context() } - /// Delegates to inner span. + /// Returns true if this `Span` is recording information like events with the `add_event` + /// operation, attributes using `set_attributes`, status with `set_status`, etc. fn is_recording(&self) -> bool { self.0.is_recording() } - /// Delegates to inner span. + /// Sets a single `Attribute` where the attribute properties are passed as arguments. + /// + /// Note that the OpenTelemetry project documents certain ["standard + /// attributes"](https://github.com/open-telemetry/opentelemetry-specification/blob/master/specification/data-semantic-conventions.md) + /// that have prescribed semantic meanings. fn set_attribute(&mut self, attribute: api::KeyValue) { self.0.set_attribute(attribute) } - /// Delegates to inner span. + /// Sets the status of the `Span`. If used, this will override the default `Span` + /// status, which is `OK`. fn set_status(&mut self, status: api::SpanStatus) { self.0.set_status(status) } - /// Delegates to inner span. + /// Updates the `Span`'s name. fn update_name(&mut self, new_name: String) { self.0.update_name(new_name) } - /// Delegates to inner span. + /// Finishes the span. fn end(&mut self) { self.0.end() } @@ -50,19 +127,89 @@ impl api::Span for BoxedSpan { self } - /// Mark span as currently active + /// Mark span as active fn mark_as_active(&self) { self.0.mark_as_active() } - /// Mark span as no longer active + /// Mark span as inactive fn mark_as_inactive(&self) { self.0.mark_as_inactive() } } -/// `GenericTracer` allows `BoxedTracer`'s to contain and use a `Tracer` trait object. -pub trait GenericTracer: Send + Sync { +/// Wraps the [`GlobalProvider`]'s [`Tracer`] so it can be used generically by +/// applications without knowing the underlying type. +/// +/// [`GlobalProvider`]: struct.GlobalProvider.html +/// [`Tracer`]: ../api/trace/tracer/trait.Tracer.html +#[derive(Debug)] +pub struct BoxedTracer(Box); + +impl api::Tracer for BoxedTracer { + /// 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 inactive `SpanContext`. Used by functions that + /// need to return a default span like `get_active_span` if no span is present. + fn invalid(&self) -> Self::Span { + BoxedSpan(self.0.invalid_boxed()) + } + + /// Starts a new `Span`. + /// + /// Each span has zero or one parent spans and zero or more child spans, which + /// represent causally related operations. A tree of related spans comprises a + /// trace. A span is said to be a _root span_ if it does not have a parent. Each + /// trace includes a single root span, which is the shared ancestor of all other + /// spans in the trace. + fn start(&self, name: &str, parent_span: Option) -> Self::Span { + BoxedSpan(self.0.start_boxed(name, parent_span)) + } + + /// Creates a span builder + /// + /// An ergonomic way for attributes to be configured before the `Span` is started. + fn span_builder(&self, name: &str) -> api::SpanBuilder { + api::SpanBuilder::from_name(name.to_string()) + } + + /// Create a span from a `SpanBuilder` + fn build(&self, builder: api::SpanBuilder) -> Self::Span { + BoxedSpan(self.0.build_boxed(builder)) + } + + /// Returns the current active span. + /// + /// When getting the current `Span`, the `Tracer` will return a placeholder + /// `Span` with an invalid `SpanContext` if there is no currently active `Span`. + fn get_active_span(&self) -> Self::Span { + BoxedSpan(self.0.get_active_span_boxed()) + } + + /// Mark a given `Span` as active. + fn mark_span_as_active(&self, span: &Self::Span) { + self.0.mark_span_as_active_boxed(span) + } + + /// Mark a given `Span` as inactive. + fn mark_span_as_inactive(&self, span_id: api::SpanId) { + self.0.mark_span_as_inactive_boxed(span_id) + } + + /// Clone span + fn clone_span(&self, span: &Self::Span) -> Self::Span { + BoxedSpan(self.0.clone_span_boxed(span)) + } +} + +/// Allows a specific [`Tracer`] to be used generically by [`BoxedTracer`] +/// instances by mirroring the interface and boxing the return types. +/// +/// [`Tracer`]: ../api/trace/tracer/trait.Tracer.html +/// [`BoxedTracer`]: struct.BoxedTracer.html +pub trait GenericTracer: fmt::Debug + 'static { /// Create a new invalid span for use in cases where there are no active spans. fn invalid_boxed(&self) -> Box; @@ -87,7 +234,11 @@ pub trait GenericTracer: Send + Sync { fn clone_span_boxed(&self, span: &dyn api::Span) -> Box; } -impl GenericTracer for Box> { +impl GenericTracer for T +where + S: api::Span, + T: api::Tracer, +{ /// Create a new invalid span for use in cases where there are no active spans. fn invalid_boxed(&self) -> Box { Box::new(self.invalid()) @@ -132,157 +283,49 @@ impl GenericTracer for Box> { } } -impl api::Tracer for dyn GenericTracer { - /// 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: &str, parent_span: Option) -> Self::Span { - BoxedSpan(self.start_boxed(name, parent_span)) - } - - /// Creates a span builder - /// - /// An ergonomic way for attributes to be configured before the `Span` is started. - fn span_builder(&self, name: &str) -> api::SpanBuilder { - api::SpanBuilder::from_name(name.to_string()) - } - - /// Create a span from a `SpanBuilder` - fn build(&self, builder: api::SpanBuilder) -> Self::Span { - BoxedSpan(self.build_boxed(builder)) - } - - /// 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: api::SpanId) { - self.mark_span_as_inactive_boxed(span_id) - } - - /// Clone span - fn clone_span(&self, span: &Self::Span) -> Self::Span { - BoxedSpan(self.clone_span_boxed(&(*span.0))) - } -} - -/// BoxedTracer is an instance of a generic tracer that can be returned by the -/// global provider to represent. -#[allow(missing_debug_implementations)] -pub struct BoxedTracer(Box); - -impl api::Tracer for BoxedTracer { - /// 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.0.invalid() - } - - /// Starts a new `Span`. - fn start(&self, name: &str, parent_span: Option) -> Self::Span { - self.0.start(name, parent_span) - } - - /// Creates a span builder - /// - /// An ergonomic way for attributes to be configured before the `Span` is started. - fn span_builder(&self, name: &str) -> api::SpanBuilder { - api::SpanBuilder::from_name(name.to_string()) - } - - /// Create a span from a `SpanBuilder` - fn build(&self, builder: api::SpanBuilder) -> Self::Span { - self.0.build(builder) - } - - /// Returns the current active span. - fn get_active_span(&self) -> Self::Span { - self.0.get_active_span() - } - - /// Mark a given `Span` as active. - fn mark_span_as_active(&self, span: &Self::Span) { - self.0.mark_span_as_active(span) - } - - /// Mark a given `Span` as inactive. - fn mark_span_as_inactive(&self, span_id: api::SpanId) { - self.0.mark_span_as_inactive(span_id) - } - - /// Clone span - fn clone_span(&self, span: &Self::Span) -> Self::Span { - self.0.clone_span(span) - } -} - -/// `GenericProvider` allows `GlobalProvider`'s to contain and use a `Provider` trait object. -pub trait GenericProvider: Send + Sync { +/// Allows a specific [`Provider`] to be used generically by the +/// [`GlobalProvider`] by mirroring the interface and boxing the return types. +/// +/// [`Provider`]: ../api/trace/provider/trait.Provider.html +/// [`GlobalProvider`]: struct.GlobalProvider.html +pub trait GenericProvider: fmt::Debug + 'static { /// Creates a named tracer instance that is a trait object through the underlying `Provider`. fn get_tracer_boxed(&self, name: &'static str) -> Box; } -impl api::Provider for dyn GenericProvider { - /// Tracer is a boxed tracer so it can wrap any implementation of `Tracer`. - type Tracer = BoxedTracer; - - /// Find or create a named instance of `BoxedTracer`. - fn get_tracer(&self, name: &'static str) -> Self::Tracer { - BoxedTracer(self.get_tracer_boxed(name)) - } -} - -impl GenericProvider for Box> +impl GenericProvider for P where - S: api::Span + 'static, - T: api::Tracer + 'static, + S: api::Span, + T: api::Tracer, + P: api::Provider, { - /// Return a boxed generic tracer, used + /// Return a boxed generic tracer fn get_tracer_boxed(&self, name: &'static str) -> Box { - // Has to first be boxed to impl `GenericTracer` - let generic_tracer: Box> = Box::new(self.get_tracer(name)); - // Then boxed again to impl `Box`. - Box::new(generic_tracer) + Box::new(self.get_tracer(name)) } } -/// GlobalProvider maintains a global singleton that allows any thread to access -/// the same generic `Provider` implementation. -#[allow(missing_debug_implementations)] +/// Represents the globally configured [`Provider`] instance for this +/// application. This allows generic tracing through the returned +/// [`BoxedTracer`] instances. +/// +/// [`Provider`]: ../api/trace/provider/trait.Provider.html +/// [`BoxedTracer`]: struct.BoxedTracer.html +#[derive(Clone, Debug)] pub struct GlobalProvider { - provider: Box, + provider: Arc, } impl GlobalProvider { /// Create a new GlobalProvider instance from a struct that implements `Provider`. fn new(provider: P) -> Self where - S: api::Span + 'static, - T: api::Tracer + 'static, - P: api::Provider + 'static, + S: api::Span, + T: api::Tracer, + P: api::Provider + Send + Sync, { - // Has to first be boxed to impl `GenericProvider`. - let generic_provider: Box> = Box::new(provider); - - // Then boxed again to for `Box`. GlobalProvider { - provider: Box::new(generic_provider), + provider: Arc::new(provider), } } } @@ -292,37 +335,45 @@ impl api::Provider for GlobalProvider { /// Find or create a named tracer using the global provider. fn get_tracer(&self, name: &'static str) -> Self::Tracer { - self.provider.get_tracer(name) + BoxedTracer(self.provider.get_tracer_boxed(name)) } } lazy_static::lazy_static! { /// The global `Tracer` singleton. - static ref GLOBAL_TRACER_PROVIDER: RwLock> = RwLock::new(Arc::new(GlobalProvider::new(api::NoopProvider {}))); + static ref GLOBAL_TRACER_PROVIDER: RwLock = RwLock::new(GlobalProvider::new(api::NoopProvider {})); } -/// Returns a reference to the global `Provider` -pub fn trace_provider() -> Arc { +/// Returns an instance of the currently configured global [`Provider`] through +/// [`GlobalProvider`]. +/// +/// [`Provider`]: ../api/trace/provider/trait.Provider.html +/// [`GlobalProvider`]: struct.GlobalProvider.html +pub fn trace_provider() -> GlobalProvider { GLOBAL_TRACER_PROVIDER .read() .expect("GLOBAL_TRACER_PROVIDER RwLock poisoned") .clone() } -/// Assigns the global `Tracer` +/// Sets the given [`Provider`] instance as the current global provider. +/// +/// [`Provider`]: ../api/trace/provider/trait.Provider.html pub fn set_provider(new_provider: P) where - S: api::Span + 'static, - T: api::Tracer + 'static, - P: api::Provider + 'static, + S: api::Span, + T: api::Tracer, + P: api::Provider + Send + Sync, { let mut global_provider = GLOBAL_TRACER_PROVIDER .write() .expect("GLOBAL_TRACER_PROVIDER RwLock poisoned"); - *global_provider = Arc::new(GlobalProvider::new(new_provider)); + *global_provider = GlobalProvider::new(new_provider); } -/// Returns `NoopMeter` for now +/// Returns [`NoopMeter`] for now +/// +/// [`NoopMeter`]: ../api/trace/noop/struct.NoopMeter.html pub fn global_meter() -> crate::api::NoopMeter { crate::api::NoopMeter {} }