kona_cli/
tracing.rs

1//! [tracing_subscriber] utilities.
2
3use tracing_subscriber::{
4    Layer,
5    prelude::__tracing_subscriber_SubscriberExt,
6    util::{SubscriberInitExt, TryInitError},
7};
8
9use serde::{Deserialize, Serialize};
10use tracing_subscriber::EnvFilter;
11
12use crate::log::{LogConfig, LogRotation};
13
14/// The format of the logs.
15#[derive(
16    Default, Debug, Clone, Copy, PartialEq, Eq, Hash, clap::ValueEnum, Serialize, Deserialize,
17)]
18#[serde(rename_all = "lowercase")]
19#[clap(rename_all = "lowercase")]
20pub enum LogFormat {
21    /// Full format (default).
22    #[default]
23    Full,
24    /// JSON format.
25    Json,
26    /// Pretty format.
27    Pretty,
28    /// Compact format.
29    Compact,
30}
31
32impl LogConfig {
33    /// Initializes the tracing subscriber
34    ///
35    /// # Arguments
36    /// * `verbosity_level` - The verbosity level (0-5). If `0`, no logs are printed.
37    /// * `env_filter` - Optional environment filter for the subscriber.
38    ///
39    /// # Returns
40    /// * `Result<()>` - Ok if successful, Err otherwise.
41    pub fn init_tracing_subscriber(
42        &self,
43        env_filter: Option<EnvFilter>,
44    ) -> Result<(), TryInitError> {
45        let file_layer = self.file_logs.as_ref().map(|file_logs| {
46            let directory_path = file_logs.directory_path.clone();
47
48            let appender = match file_logs.rotation {
49                LogRotation::Minutely => {
50                    tracing_appender::rolling::minutely(directory_path, "kona.log")
51                }
52                LogRotation::Hourly => {
53                    tracing_appender::rolling::hourly(directory_path, "kona.log")
54                }
55                LogRotation::Daily => tracing_appender::rolling::daily(directory_path, "kona.log"),
56                LogRotation::Never => tracing_appender::rolling::never(directory_path, "kona.log"),
57            };
58
59            match file_logs.format {
60                LogFormat::Full => tracing_subscriber::fmt::layer().with_writer(appender).boxed(),
61                LogFormat::Json => {
62                    tracing_subscriber::fmt::layer().json().with_writer(appender).boxed()
63                }
64                LogFormat::Pretty => {
65                    tracing_subscriber::fmt::layer().pretty().with_writer(appender).boxed()
66                }
67                LogFormat::Compact => {
68                    tracing_subscriber::fmt::layer().compact().with_writer(appender).boxed()
69                }
70            }
71        });
72
73        let stdout_layer = self.stdout_logs.as_ref().map(|stdout_logs| match stdout_logs.format {
74            LogFormat::Full => tracing_subscriber::fmt::layer().boxed(),
75            LogFormat::Json => tracing_subscriber::fmt::layer().json().boxed(),
76            LogFormat::Pretty => tracing_subscriber::fmt::layer().pretty().boxed(),
77            LogFormat::Compact => tracing_subscriber::fmt::layer().compact().boxed(),
78        });
79
80        let env_filter = env_filter
81            .unwrap_or(EnvFilter::from_default_env())
82            .add_directive(self.global_level.into());
83
84        tracing_subscriber::registry()
85            .with(env_filter)
86            .with(file_layer)
87            .with(stdout_layer)
88            .try_init()?;
89
90        Ok(())
91    }
92}
93
94/// This provides function for init tracing in testing
95///
96/// # Functions
97/// - `init_test_tracing`: A helper function for initializing tracing in test environments.
98/// - `init_tracing_subscriber`: Initializes the tracing subscriber with a specified verbosity level
99///   and optional environment filter.
100pub fn init_test_tracing() {
101    let _ = LogConfig::default().init_tracing_subscriber(None::<EnvFilter>);
102}