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
use std::{borrow::Cow, sync::Arc};

use crate::{logs::LogRecord, InstrumentationLibrary, InstrumentationLibraryBuilder, KeyValue};

#[cfg(feature = "logs_level_enabled")]
use super::Severity;

/// The interface for emitting [`LogRecord`]s.

pub trait Logger {
    /// Specifies the `LogRecord` type associated with this logger.
    type LogRecord: LogRecord;

    /// Creates a new log record builder.
    fn create_log_record(&self) -> Self::LogRecord;

    /// Emit a [`LogRecord`]. If there is active current thread's [`Context`],
    ///  the logger will set the record's `TraceContext` to the active trace context,
    ///
    /// [`Context`]: crate::Context
    fn emit(&self, record: Self::LogRecord);

    #[cfg(feature = "logs_level_enabled")]
    /// Check if the given log level is enabled.
    fn event_enabled(&self, level: Severity, target: &str) -> bool;
}

/// Interfaces that can create [`Logger`] instances.
pub trait LoggerProvider {
    /// The [`Logger`] type that this provider will return.
    type Logger: Logger;

    /// Deprecated, use [`LoggerProvider::logger_builder()`]
    ///
    /// Returns a new versioned logger 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.
    /// Create a new versioned `Logger` instance.
    #[deprecated(since = "0.23.0", note = "Please use logger_builder() instead")]
    fn versioned_logger(
        &self,
        name: impl Into<Cow<'static, str>>,
        version: Option<Cow<'static, str>>,
        schema_url: Option<Cow<'static, str>>,
        attributes: Option<Vec<KeyValue>>,
    ) -> Self::Logger {
        let mut builder = self.logger_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);
        }
        builder.build()
    }

    /// Returns a new builder for creating a [`Logger`] 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::InstrumentationLibrary;
    /// use crate::opentelemetry::logs::LoggerProvider;
    /// use opentelemetry_sdk::logs::LoggerProvider as SdkLoggerProvider;
    ///
    /// let provider = SdkLoggerProvider::builder().build();
    ///
    /// // logger used in applications/binaries
    /// let logger = provider.logger_builder("my_app").build();
    ///
    /// // logger used in libraries/crates that optionally includes version and schema url
    /// let logger = provider.logger_builder("my_library")
    ///     .with_version(env!("CARGO_PKG_VERSION"))
    ///     .with_schema_url("https://opentelemetry.io/schema/1.0.0")
    ///     .build();
    /// ```
    fn logger_builder(&self, name: impl Into<Cow<'static, str>>) -> LoggerBuilder<'_, Self> {
        LoggerBuilder {
            provider: self,
            library_builder: InstrumentationLibrary::builder(name),
        }
    }

    /// Returns a new versioned logger with the given instrumentation library.
    ///
    /// # Examples
    ///
    /// ```
    /// use opentelemetry::InstrumentationLibrary;
    /// use crate::opentelemetry::logs::LoggerProvider;
    /// use opentelemetry_sdk::logs::LoggerProvider as SdkLoggerProvider;
    ///
    /// let provider = SdkLoggerProvider::builder().build();
    ///
    /// // logger used in applications/binaries
    /// let logger = provider.logger("my_app");
    ///
    /// // logger 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 logger = provider.library_logger(library);
    /// ```
    fn library_logger(&self, library: Arc<InstrumentationLibrary>) -> Self::Logger;

    /// Returns a new logger 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.
    fn logger(&self, name: impl Into<Cow<'static, str>>) -> Self::Logger {
        self.logger_builder(name).build()
    }
}

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

impl<'a, T: LoggerProvider + ?Sized> LoggerBuilder<'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::Logger {
        self.provider
            .library_logger(Arc::new(self.library_builder.build()))
    }
}