diff --git a/Cargo.lock b/Cargo.lock
index dbaad3473..30ae55f64 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -3272,6 +3272,7 @@ dependencies = [
"opentelemetry-semantic-conventions",
"opentelemetry_sdk",
"pin-project",
+ "rstest",
"snafu 0.8.5",
"stackable-webhook",
"tokio",
diff --git a/crates/stackable-telemetry/Cargo.toml b/crates/stackable-telemetry/Cargo.toml
index 7d1c5d03d..e1de94107 100644
--- a/crates/stackable-telemetry/Cargo.toml
+++ b/crates/stackable-telemetry/Cargo.toml
@@ -25,6 +25,7 @@ tracing-subscriber = { workspace = true, features = ["env-filter"] }
[dev-dependencies]
tokio.workspace = true
tracing-opentelemetry.workspace = true
+rstest.workspace = true
stackable-webhook = { path = "../stackable-webhook" }
[package.metadata.cargo-udeps.ignore]
diff --git a/crates/stackable-telemetry/src/tracing/mod.rs b/crates/stackable-telemetry/src/tracing/mod.rs
index 43c943599..8493d8106 100644
--- a/crates/stackable-telemetry/src/tracing/mod.rs
+++ b/crates/stackable-telemetry/src/tracing/mod.rs
@@ -18,7 +18,7 @@ use snafu::{ResultExt as _, Snafu};
use tracing::subscriber::SetGlobalDefaultError;
use tracing_subscriber::{filter::Directive, layer::SubscriberExt, EnvFilter, Layer, Registry};
-use settings::{ConsoleLogSettings, OtlpLogSettings, OtlpTraceSettings};
+use settings::*;
pub mod settings;
@@ -40,11 +40,46 @@ pub enum Error {
SetGlobalDefaultSubscriber { source: SetGlobalDefaultError },
}
-/// Easily initialize a set of preconfigured [`Subscriber`][1] layers.
+/// Easily initialize a set of pre-configured [`Subscriber`][1] layers.
///
-/// # Usage:
+/// # Usage
+///
+/// There are two different styles to configure individual subscribers: Using the sophisticated
+/// [`SettingsBuilder`] or the simplified tuple style for basic configuration. Currently, three
+/// different subscribers are supported: console output, OTLP log export, and OTLP trace export.
+///
+/// The subscribers are active as long as the tracing guard returned by [`Tracing::init`] is in
+/// scope and not dropped. Dropping it results in subscribers being shut down, which can lead to
+/// loss of telemetry data when done before exiting the application. This is why it is important
+/// to hold onto the guard as long as required.
+///
+///
+/// Name the guard variable appropriately, do not just use let _ =, as that will drop
+/// immediately.
+///
+///
+/// ```
+/// # use stackable_telemetry::tracing::{Tracing, Error};
+/// #[tokio::main]
+/// async fn main() -> Result<(), Error> {
+/// let _tracing_guard = Tracing::builder() // < Scope starts here
+/// .service_name("test") // |
+/// .build() // |
+/// .init()?; // |
+/// // |
+/// tracing::info!("log a message"); // |
+/// Ok(()) // < Scope ends here, guard is dropped
+/// }
/// ```
-/// use stackable_telemetry::tracing::{Tracing, Error, settings::{Build as _, Settings}};
+///
+/// ## Basic configuration
+///
+/// A basic configuration of subscribers can be done by using 2-tuples or 3-tuples, also called
+/// doubles and triples. Using tuples, the subscriber can be enabled/disabled and it's environment
+/// variable and default level can be set.
+///
+/// ```
+/// use stackable_telemetry::tracing::{Tracing, Error, settings::Settings};
/// use tracing_subscriber::filter::LevelFilter;
///
/// #[tokio::main]
@@ -54,8 +89,36 @@ pub enum Error {
/// // runtime.
/// let otlp_log_flag = false;
///
-/// // IMPORTANT: Name the guard variable appropriately, do not just use
-/// // `let _ =`, as that will drop immediately.
+/// let _tracing_guard = Tracing::builder()
+/// .service_name("test")
+/// .with_console_output(("TEST_CONSOLE", LevelFilter::INFO))
+/// .with_otlp_log_exporter(("TEST_OTLP_LOG", LevelFilter::DEBUG, otlp_log_flag))
+/// .build()
+/// .init()?;
+///
+/// tracing::info!("log a message");
+///
+/// Ok(())
+/// }
+/// ```
+///
+/// ## Advanced configuration
+///
+/// More advanced configurations can be done via the [`Settings::builder`] function. Each
+/// subscriber provides specific settings based on a common set of options. These options can be
+/// customized via the following methods:
+///
+/// - [`SettingsBuilder::console_log_settings_builder`]
+/// - [`SettingsBuilder::otlp_log_settings_builder`]
+/// - [`SettingsBuilder::otlp_trace_settings_builder`]
+///
+/// ```
+/// # use stackable_telemetry::tracing::{Tracing, Error, settings::Settings};
+/// # use tracing_subscriber::filter::LevelFilter;
+/// #[tokio::main]
+/// async fn main() -> Result<(), Error> {
+/// let otlp_log_flag = false;
+///
/// let _tracing_guard = Tracing::builder()
/// .service_name("test")
/// .with_console_output(
@@ -164,8 +227,10 @@ impl Tracing {
/// Initialise the configured tracing subscribers, returning a guard that
/// will shutdown the subscribers when dropped.
///
- /// IMPORTANT: Name the guard variable appropriately, do not just use
- /// `let _ =`, as that will drop immediately.
+ ///
+ /// Name the guard variable appropriately, do not just use let _ =, as that will drop
+ /// immediately.
+ ///
pub fn init(mut self) -> Result {
let mut layers: Vec + Sync + Send>> = Vec::new();
@@ -374,11 +439,11 @@ impl TracingBuilder {
/// [1]: tracing_subscriber::filter::LevelFilter
pub fn with_console_output(
self,
- console_log_settings: ConsoleLogSettings,
+ console_log_settings: impl Into,
) -> TracingBuilder {
TracingBuilder {
service_name: self.service_name,
- console_log_settings,
+ console_log_settings: console_log_settings.into(),
otlp_log_settings: self.otlp_log_settings,
otlp_trace_settings: self.otlp_trace_settings,
_marker: self._marker,
@@ -394,12 +459,12 @@ impl TracingBuilder {
/// [1]: tracing_subscriber::filter::LevelFilter
pub fn with_otlp_log_exporter(
self,
- otlp_log_settings: OtlpLogSettings,
+ otlp_log_settings: impl Into,
) -> TracingBuilder {
TracingBuilder {
service_name: self.service_name,
console_log_settings: self.console_log_settings,
- otlp_log_settings,
+ otlp_log_settings: otlp_log_settings.into(),
otlp_trace_settings: self.otlp_trace_settings,
_marker: self._marker,
}
@@ -414,13 +479,13 @@ impl TracingBuilder {
/// [1]: tracing_subscriber::filter::LevelFilter
pub fn with_otlp_trace_exporter(
self,
- otlp_trace_settings: OtlpTraceSettings,
+ otlp_trace_settings: impl Into,
) -> TracingBuilder {
TracingBuilder {
service_name: self.service_name,
console_log_settings: self.console_log_settings,
otlp_log_settings: self.otlp_log_settings,
- otlp_trace_settings,
+ otlp_trace_settings: otlp_trace_settings.into(),
_marker: self._marker,
}
}
@@ -452,7 +517,8 @@ fn env_filter_builder(env_var: &str, default_directive: impl Into) ->
#[cfg(test)]
mod test {
- use settings::{Build as _, Settings};
+ use rstest::rstest;
+ use settings::Settings;
use tracing::level_filters::LevelFilter;
use super::*;
@@ -499,6 +565,48 @@ mod test {
assert!(!trace_guard.otlp_trace_settings.enabled);
}
+ #[test]
+ fn builder_with_console_output_double() {
+ let trace_guard = Tracing::builder()
+ .service_name("test")
+ .with_console_output(("ABC_A", LevelFilter::TRACE))
+ .build();
+
+ assert_eq!(
+ trace_guard.console_log_settings,
+ ConsoleLogSettings {
+ common_settings: Settings {
+ environment_variable: "ABC_A",
+ default_level: LevelFilter::TRACE,
+ enabled: true
+ },
+ log_format: Default::default()
+ }
+ )
+ }
+
+ #[rstest]
+ #[case(false)]
+ #[case(true)]
+ fn builder_with_console_output_triple(#[case] enabled: bool) {
+ let trace_guard = Tracing::builder()
+ .service_name("test")
+ .with_console_output(("ABC_A", LevelFilter::TRACE, enabled))
+ .build();
+
+ assert_eq!(
+ trace_guard.console_log_settings,
+ ConsoleLogSettings {
+ common_settings: Settings {
+ environment_variable: "ABC_A",
+ default_level: LevelFilter::TRACE,
+ enabled
+ },
+ log_format: Default::default()
+ }
+ )
+ }
+
#[test]
fn builder_with_all() {
let trace_guard = Tracing::builder()
diff --git a/crates/stackable-telemetry/src/tracing/settings/console_log.rs b/crates/stackable-telemetry/src/tracing/settings/console_log.rs
index 0ba059592..dc26379fd 100644
--- a/crates/stackable-telemetry/src/tracing/settings/console_log.rs
+++ b/crates/stackable-telemetry/src/tracing/settings/console_log.rs
@@ -2,7 +2,9 @@
use std::ops::Deref;
-use super::{Build, Settings, SettingsBuilder};
+use tracing::level_filters::LevelFilter;
+
+use super::{Settings, SettingsBuilder};
/// Configure specific settings for the Console Log subscriber.
#[derive(Debug, Default, PartialEq)]
@@ -74,12 +76,36 @@ impl From for ConsoleLogSettingsBuilder {
}
}
-/// This implementation is used to build console log settings from common settings without
-/// specifying console log specific settings.
-impl Build for SettingsBuilder {
- fn build(self) -> ConsoleLogSettings {
+impl From for ConsoleLogSettings {
+ fn from(common_settings: Settings) -> Self {
ConsoleLogSettings {
- common_settings: self.build(),
+ common_settings,
+ ..Default::default()
+ }
+ }
+}
+
+impl From<(&'static str, LevelFilter)> for ConsoleLogSettings {
+ fn from(value: (&'static str, LevelFilter)) -> Self {
+ Self {
+ common_settings: Settings {
+ environment_variable: value.0,
+ default_level: value.1,
+ enabled: true,
+ },
+ ..Default::default()
+ }
+ }
+}
+
+impl From<(&'static str, LevelFilter, bool)> for ConsoleLogSettings {
+ fn from(value: (&'static str, LevelFilter, bool)) -> Self {
+ Self {
+ common_settings: Settings {
+ environment_variable: value.0,
+ default_level: value.1,
+ enabled: value.2,
+ },
..Default::default()
}
}
diff --git a/crates/stackable-telemetry/src/tracing/settings/mod.rs b/crates/stackable-telemetry/src/tracing/settings/mod.rs
index aaf71c6bb..88deb9d73 100644
--- a/crates/stackable-telemetry/src/tracing/settings/mod.rs
+++ b/crates/stackable-telemetry/src/tracing/settings/mod.rs
@@ -51,22 +51,6 @@ pub struct SettingsBuilder {
default_level: LevelFilter,
}
-/// Finalizer to be implemented on builders.
-pub trait Build {
- /// Finalize settings.
- fn build(self) -> T;
-}
-
-impl Build for SettingsBuilder {
- fn build(self) -> Settings {
- Settings {
- environment_variable: self.environment_variable,
- default_level: self.default_level,
- enabled: self.enabled,
- }
- }
-}
-
impl SettingsBuilder {
/// Set the environment variable used for overriding the [`Settings::default_level`].
///
@@ -114,6 +98,15 @@ impl SettingsBuilder {
pub fn otlp_trace_settings_builder(self) -> OtlpTraceSettingsBuilder {
self.into()
}
+
+ /// Consumes self and constructs valid [`Settings`].
+ pub fn build(self) -> Settings {
+ Settings {
+ environment_variable: self.environment_variable,
+ default_level: self.default_level,
+ enabled: self.enabled,
+ }
+ }
}
impl Default for SettingsBuilder {
diff --git a/crates/stackable-telemetry/src/tracing/settings/otlp_log.rs b/crates/stackable-telemetry/src/tracing/settings/otlp_log.rs
index 6015e0564..e885faaaa 100644
--- a/crates/stackable-telemetry/src/tracing/settings/otlp_log.rs
+++ b/crates/stackable-telemetry/src/tracing/settings/otlp_log.rs
@@ -2,7 +2,9 @@
use std::ops::Deref;
-use super::{Build, Settings, SettingsBuilder};
+use tracing::level_filters::LevelFilter;
+
+use super::{Settings, SettingsBuilder};
#[derive(Debug, Default, PartialEq)]
pub struct OtlpLogSettings {
@@ -39,13 +41,32 @@ impl From for OtlpLogSettingsBuilder {
}
}
-/// This implementation is used to build OTLP log settings from common settings without
-/// specifying OTLP log specific settings.
-impl Build for SettingsBuilder {
- fn build(self) -> OtlpLogSettings {
- OtlpLogSettings {
- common_settings: self.build(),
- // ..Default::default()
+impl From for OtlpLogSettings {
+ fn from(common_settings: Settings) -> Self {
+ Self { common_settings }
+ }
+}
+
+impl From<(&'static str, LevelFilter)> for OtlpLogSettings {
+ fn from(value: (&'static str, LevelFilter)) -> Self {
+ Self {
+ common_settings: Settings {
+ environment_variable: value.0,
+ default_level: value.1,
+ enabled: true,
+ },
+ }
+ }
+}
+
+impl From<(&'static str, LevelFilter, bool)> for OtlpLogSettings {
+ fn from(value: (&'static str, LevelFilter, bool)) -> Self {
+ Self {
+ common_settings: Settings {
+ environment_variable: value.0,
+ default_level: value.1,
+ enabled: value.2,
+ },
}
}
}
diff --git a/crates/stackable-telemetry/src/tracing/settings/otlp_trace.rs b/crates/stackable-telemetry/src/tracing/settings/otlp_trace.rs
index df13a9e2b..98f9ab6fa 100644
--- a/crates/stackable-telemetry/src/tracing/settings/otlp_trace.rs
+++ b/crates/stackable-telemetry/src/tracing/settings/otlp_trace.rs
@@ -2,7 +2,9 @@
use std::ops::Deref;
-use super::{Build, Settings, SettingsBuilder};
+use tracing::level_filters::LevelFilter;
+
+use super::{Settings, SettingsBuilder};
#[derive(Debug, Default, PartialEq)]
pub struct OtlpTraceSettings {
@@ -39,13 +41,32 @@ impl From for OtlpTraceSettingsBuilder {
}
}
-/// This implementation is used to build OTLP trace settings from common settings without
-/// specifying OTLP trace specific settings.
-impl Build for SettingsBuilder {
- fn build(self) -> OtlpTraceSettings {
- OtlpTraceSettings {
- common_settings: self.build(),
- // ..Default::default()
+impl From for OtlpTraceSettings {
+ fn from(common_settings: Settings) -> Self {
+ Self { common_settings }
+ }
+}
+
+impl From<(&'static str, LevelFilter)> for OtlpTraceSettings {
+ fn from(value: (&'static str, LevelFilter)) -> Self {
+ Self {
+ common_settings: Settings {
+ environment_variable: value.0,
+ default_level: value.1,
+ enabled: true,
+ },
+ }
+ }
+}
+
+impl From<(&'static str, LevelFilter, bool)> for OtlpTraceSettings {
+ fn from(value: (&'static str, LevelFilter, bool)) -> Self {
+ Self {
+ common_settings: Settings {
+ environment_variable: value.0,
+ default_level: value.1,
+ enabled: value.2,
+ },
}
}
}