Skip to content

Commit

Permalink
Try using a builder pattern for all signal providers
Browse files Browse the repository at this point in the history
  • Loading branch information
izquierdo committed Feb 28, 2024
1 parent 5e67cae commit e176589
Show file tree
Hide file tree
Showing 8 changed files with 250 additions and 22 deletions.
18 changes: 12 additions & 6 deletions opentelemetry-sdk/src/logs/log_emitter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,12 +43,18 @@ impl opentelemetry::logs::LoggerProvider for LoggerProvider {
name
};

self.library_logger(Arc::new(InstrumentationLibrary::new(
component_name,
version,
schema_url,
attributes,
)))
let mut builder = InstrumentationLibrary::builder(component_name);
if let Some(v) = version {
builder = builder.with_version(v);
}
if let Some(s) = schema_url {
builder = builder.with_schema_url(s);
}
if let Some(a) = attributes {
builder = builder.with_attributes(a);
}

self.library_logger(Arc::new(builder.build()))
}

fn library_logger(&self, library: Arc<InstrumentationLibrary>) -> Self::Logger {
Expand Down
14 changes: 13 additions & 1 deletion opentelemetry-sdk/src/metrics/meter_provider.rs
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,19 @@ impl MeterProvider for SdkMeterProvider {
return Meter::new(Arc::new(NoopMeterCore::new()));
}

let scope = Scope::new(name, version, schema_url, attributes);
let mut builder = Scope::builder(name);

if let Some(v) = version {
builder = builder.with_version(v);
}
if let Some(s) = schema_url {
builder = builder.with_schema_url(s);
}
if let Some(a) = attributes {
builder = builder.with_attributes(a);
}

let scope = builder.build();

if let Ok(mut meters) = self.meters.lock() {
let meter = meters
Expand Down
19 changes: 13 additions & 6 deletions opentelemetry-sdk/src/trace/provider.rs
Original file line number Diff line number Diff line change
Expand Up @@ -136,12 +136,19 @@ impl opentelemetry::trace::TracerProvider for TracerProvider {
name
};

self.library_tracer(Arc::new(InstrumentationLibrary::new(
component_name,
version,
schema_url,
attributes,
)))
let mut builder = InstrumentationLibrary::builder(component_name);

if let Some(v) = version {
builder = builder.with_version(v);
}
if let Some(s) = schema_url {
builder = builder.with_schema_url(s);
}
if let Some(a) = attributes {
builder = builder.with_attributes(a);
}

self.library_tracer(Arc::new(builder.build()))
}

fn library_tracer(&self, library: Arc<InstrumentationLibrary>) -> Self::Tracer {
Expand Down
65 changes: 65 additions & 0 deletions opentelemetry/src/common.rs
Original file line number Diff line number Diff line change
Expand Up @@ -487,7 +487,10 @@ impl hash::Hash for InstrumentationLibrary {
}

impl InstrumentationLibrary {
/// Deprecated, use [`InstrumentationLibrary::builder()`]
///
/// Create an new instrumentation library.
#[deprecated]
pub fn new(
name: impl Into<Cow<'static, str>>,
version: Option<impl Into<Cow<'static, str>>>,
Expand All @@ -501,4 +504,66 @@ impl InstrumentationLibrary {
attributes: attributes.unwrap_or_default(),
}
}

/// Create a new builder to create an [InstrumentationLibrary]
pub fn builder(name: impl Into<Cow<'static, str>>) -> InstrumentationLibraryBuilder {
InstrumentationLibraryBuilder::new(name)
}
}

/// Configuration options for [InstrumentationLibrary].
///
/// An instrumentation library is a library or crate providing instrumentation.
/// It should be named to follow any naming conventions of the instrumented
/// library (e.g. 'middleware' for a web framework).
///
/// Apart from the name, all other fields are optional.
///
/// See the [instrumentation libraries] spec for more information.
///
/// [instrumentation libraries]: https://github.com/open-telemetry/opentelemetry-specification/blob/v1.9.0/specification/overview.md#instrumentation-libraries
#[derive(Debug)]
pub struct InstrumentationLibraryBuilder {
name: Cow<'static, str>,

version: Option<Cow<'static, str>>,

schema_url: Option<Cow<'static, str>>,

attributes: Option<Vec<KeyValue>>,
}

impl InstrumentationLibraryBuilder {
pub fn new(name: impl Into<Cow<'static, str>>) -> Self {

Check failure on line 537 in opentelemetry/src/common.rs

View workflow job for this annotation

GitHub Actions / lint

missing documentation for an associated function
InstrumentationLibraryBuilder {
name: name.into(),
version: None,
schema_url: None,
attributes: None,
}
}

pub fn with_version(mut self, version: impl Into<Cow<'static, str>>) -> Self {

Check failure on line 546 in opentelemetry/src/common.rs

View workflow job for this annotation

GitHub Actions / lint

missing documentation for a method
self.version = Some(version.into());
self
}

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

Check failure on line 551 in opentelemetry/src/common.rs

View workflow job for this annotation

GitHub Actions / lint

missing documentation for a method
self.schema_url = Some(schema_url.into());
self
}

pub fn with_attributes(mut self, attributes: impl Into<Vec<KeyValue>>) -> Self {

Check failure on line 556 in opentelemetry/src/common.rs

View workflow job for this annotation

GitHub Actions / lint

missing documentation for a method
self.attributes = Some(attributes.into());
self
}

pub fn build(self) -> InstrumentationLibrary {

Check failure on line 561 in opentelemetry/src/common.rs

View workflow job for this annotation

GitHub Actions / lint

missing documentation for a method
InstrumentationLibrary {
name: self.name,
version: self.version,
schema_url: self.schema_url,
attributes: self.attributes.unwrap_or_default(),
}
}
}
5 changes: 4 additions & 1 deletion opentelemetry/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -222,7 +222,10 @@ mod common;
#[doc(hidden)]
pub mod testing;

pub use common::{Array, ExportError, InstrumentationLibrary, Key, KeyValue, StringValue, Value};
pub use common::{
Array, ExportError, InstrumentationLibrary, InstrumentationLibraryBuilder, Key, KeyValue,
StringValue, Value,
};

#[cfg(feature = "metrics")]
#[cfg_attr(docsrs, doc(cfg(feature = "metrics")))]
Expand Down
14 changes: 11 additions & 3 deletions opentelemetry/src/logs/logger.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,9 +37,17 @@ pub trait LoggerProvider {
schema_url: Option<Cow<'static, str>>,
attributes: Option<Vec<KeyValue>>,
) -> Self::Logger {
self.library_logger(Arc::new(InstrumentationLibrary::new(
name, version, schema_url, attributes,
)))
let mut builder = InstrumentationLibrary::builder(name);
if let Some(v) = version {
builder = builder.with_version(v);
}
if let Some(s) = schema_url {
builder = builder.with_schema_url(s);
}
if let Some(a) = attributes {
builder = builder.with_attributes(a);
}
self.library_logger(Arc::new(builder.build()))
}

/// Returns a new versioned logger with the given instrumentation library.
Expand Down
2 changes: 1 addition & 1 deletion opentelemetry/src/trace/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -182,7 +182,7 @@ pub use self::{
span::{Span, SpanKind, Status},
span_context::{SpanContext, SpanId, TraceFlags, TraceId, TraceState},
tracer::{SamplingDecision, SamplingResult, SpanBuilder, Tracer},
tracer_provider::TracerProvider,
tracer_provider::{TracerBuilder2, TracerProvider},
};
use crate::{ExportError, KeyValue};
use std::sync::PoisonError;
Expand Down
135 changes: 131 additions & 4 deletions opentelemetry/src/trace/tracer_provider.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use crate::{trace::Tracer, InstrumentationLibrary, KeyValue};
use crate::{trace::Tracer, InstrumentationLibrary, InstrumentationLibraryBuilder, KeyValue};
use std::{borrow::Cow, sync::Arc};

/// Types that can create instances of [`Tracer`].
Expand Down Expand Up @@ -76,9 +76,47 @@ pub trait TracerProvider {
schema_url: Option<impl Into<Cow<'static, str>>>,
attributes: Option<Vec<KeyValue>>,
) -> Self::Tracer {
self.library_tracer(Arc::new(InstrumentationLibrary::new(
name, version, schema_url, attributes,
)))
let mut builder = InstrumentationLibrary::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);
}

self.library_tracer(Arc::new(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>>) -> TracerBuilder1<Self>
where
Self: Clone,
{
TracerBuilder1::new(self.clone(), name)
}

/// Returns a new versioned tracer with the given instrumentation library.
Expand All @@ -104,3 +142,92 @@ pub trait TracerProvider {
/// ```
fn library_tracer(&self, library: Arc<InstrumentationLibrary>) -> Self::Tracer;
}

#[derive(Debug)]
pub struct TracerBuilder1<T: TracerProvider> {
provider: T,
library_builder: InstrumentationLibraryBuilder,
}

impl<T: TracerProvider> TracerBuilder1<T> {
pub fn new(provider: T, name: impl Into<Cow<'static, str>>) -> Self {
Self {
provider,
library_builder: InstrumentationLibraryBuilder::new(name),
}
}

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(mut self, attributes: impl Into<Vec<KeyValue>>) -> Self {
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()))
}
}

#[derive(Debug)]
pub struct TracerBuilder2 {

Check failure on line 182 in opentelemetry/src/trace/tracer_provider.rs

View workflow job for this annotation

GitHub Actions / lint

missing documentation for a struct
library_builder: InstrumentationLibraryBuilder,
}

impl TracerBuilder2 {
pub fn new(name: impl Into<Cow<'static, str>>) -> Self {

Check failure on line 187 in opentelemetry/src/trace/tracer_provider.rs

View workflow job for this annotation

GitHub Actions / lint

missing documentation for an associated function
Self {
library_builder: InstrumentationLibraryBuilder::new(name),
}
}

pub fn with_version(mut self, version: impl Into<Cow<'static, str>>) -> Self {

Check failure on line 193 in opentelemetry/src/trace/tracer_provider.rs

View workflow job for this annotation

GitHub Actions / lint

missing documentation for a method
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 {

Check failure on line 198 in opentelemetry/src/trace/tracer_provider.rs

View workflow job for this annotation

GitHub Actions / lint

missing documentation for a method
self.library_builder = self.library_builder.with_schema_url(schema_url);
self
}

pub fn with_attributes(mut self, attributes: impl Into<Vec<KeyValue>>) -> Self {

Check failure on line 203 in opentelemetry/src/trace/tracer_provider.rs

View workflow job for this annotation

GitHub Actions / lint

missing documentation for a method
self.library_builder = self.library_builder.with_attributes(attributes);
self
}

/// 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, TracerBuilder2}};
///
/// let provider = global::tracer_provider();
///
/// // tracer used in applications/binaries
/// let tracer = TracerBuilder2::new("name").build(provider);
///
/// // tracer used in libraries/crates that optionally includes version and schema url
/// let tracer = TracerBuilder2::new("my_library")
/// .with_version(env!("CARGO_PKG_VERSION"))
/// .with_schema_url("https://opentelemetry.io/schema/1.0.0");
/// .build(provider);
/// ```
pub fn build<T: Tracer>(self, provider: &impl TracerProvider<Tracer = T>) -> T {
provider.library_tracer(Arc::new(self.library_builder.build()))
}
}

0 comments on commit e176589

Please sign in to comment.