drive_abci/logging/
level.rs

1use crate::logging::error::Error;
2use derive_more::Display;
3use serde::de::Visitor;
4use serde::{de, Deserialize, Deserializer, Serialize};
5use std::fmt;
6use tracing_subscriber::EnvFilter;
7
8/// Log level presets
9#[derive(Serialize, Debug, Clone, Default, Display)]
10#[serde(rename_all = "camelCase")]
11pub enum LogLevel {
12    /// No logs
13    Silent,
14    /// Uses RUST_LOG format to set verbosity level
15    Custom(String),
16    /// Only errors
17    Error,
18    /// Warnings and errors. Errors for 3rd party dependencies
19    Warn,
20    /// Info level and lower. Warnings for 3rd party dependencies
21    #[default]
22    Info,
23    /// Debug level and lower. Info level for 3rd party dependencies
24    Debug,
25    /// Trace level and lower. Debug level for 3rd party dependencies
26    Trace,
27    /// Trace level for everything
28    Paranoid,
29}
30
31/// Creates log level preset from string
32impl From<&str> for LogLevel {
33    fn from(value: &str) -> Self {
34        match value {
35            "silent" => LogLevel::Silent,
36            "error" => LogLevel::Error,
37            "warn" => LogLevel::Warn,
38            "info" => LogLevel::Info,
39            "debug" => LogLevel::Debug,
40            "trace" => LogLevel::Trace,
41            "paranoid" => LogLevel::Paranoid,
42            configuration => LogLevel::Custom(configuration.to_string()),
43        }
44    }
45}
46
47struct LogLevelPresetVisitor;
48
49impl Visitor<'_> for LogLevelPresetVisitor {
50    type Value = LogLevel;
51
52    fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
53        formatter.write_str("silent, error, warn, info, debug, trace, paranoid or custom level using RUST_LOG format")
54    }
55
56    fn visit_str<E>(self, value: &str) -> Result<LogLevel, E>
57    where
58        E: de::Error,
59    {
60        let level = LogLevel::from(value);
61
62        Ok(level)
63    }
64}
65
66impl<'de> Deserialize<'de> for LogLevel {
67    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
68    where
69        D: Deserializer<'de>,
70    {
71        deserializer.deserialize_str(LogLevelPresetVisitor)
72    }
73}
74
75/// Creates log level preset from verbosity level
76impl TryFrom<u8> for LogLevel {
77    type Error = Error;
78
79    fn try_from(value: u8) -> Result<Self, <LogLevel as TryFrom<u8>>::Error> {
80        let level = match value {
81            0 => LogLevel::Info,
82            1 => LogLevel::Debug,
83            2 => LogLevel::Trace,
84            3 => LogLevel::Paranoid,
85            verbosity => return Err(Error::InvalidVerbosityLevel(verbosity)),
86        };
87
88        Ok(level)
89    }
90}
91
92impl TryFrom<&LogLevel> for EnvFilter {
93    type Error = Error;
94
95    fn try_from(value: &LogLevel) -> Result<Self, Error> {
96        let env_filter = match value {
97            LogLevel::Silent => EnvFilter::default(),
98            LogLevel::Custom(configuration) => {
99                EnvFilter::try_new(configuration).map_err(Error::InvalidLogSpecification)?
100            }
101            LogLevel::Error => {
102                EnvFilter::try_new("error").expect("should be a valid log specification")
103            }
104            LogLevel::Warn => {
105                EnvFilter::try_new("error,tenderdash_abci=warn,drive_abci=warn,drive=warn,dpp=warn")
106                    .expect("should be a valid log specification")
107            }
108            LogLevel::Info => {
109                EnvFilter::try_new("error,tenderdash_abci=info,drive_abci=info,drive=info,dpp=info")
110                    .expect("should be a valid log specification")
111            }
112            LogLevel::Debug => EnvFilter::try_new(
113                "info,tenderdash_abci=debug,drive_abci=debug,drive=debug,dpp=debug,dapi_grpc=debug,tonic=debug",
114            )
115            .expect("should be a valid log specification"),
116            LogLevel::Trace => EnvFilter::try_new(
117                "debug,tenderdash_abci=trace,drive_abci=trace,drive=trace,drive_grovedb_operations=off,dpp=trace",
118            )
119            .expect("should be a valid log specification"),
120            LogLevel::Paranoid => {
121                EnvFilter::try_new("trace").expect("should be a valid log specification")
122            }
123        };
124
125        Ok(env_filter)
126    }
127}