Skip to main content

elfo_logger/
config.rs

1//! Configuration for the logger.
2//!
3//! Note: all types here are exported only for documentation purposes
4//! and are not subject to stable guarantees. However, the config
5//! structure (usually encoded in TOML) follows stable guarantees.
6
7use std::path::PathBuf;
8
9use fxhash::FxHashMap;
10use serde::{Deserialize, Deserializer};
11use tracing::metadata::LevelFilter;
12
13use bytesize::ByteSize;
14
15/// Logger configuration.
16///
17/// It's exported only for documentation purposes and cannot be created or
18/// received outside the dumper.
19#[derive(Debug, Deserialize)]
20pub struct Config {
21    /// Sink for the log output.
22    /// By default logs are written to stdout.
23    #[serde(default)]
24    pub sink: Sink,
25    /// Path to the log file, applicable only for `Sink::File`.
26    pub path: Option<PathBuf>,
27    /// Log format.
28    #[serde(default)]
29    pub format: Format,
30
31    /// Size limit for each written log-line, in bytes.
32    /// If size exceeds the limit, it will be truncated in the following order:
33    ///
34    /// 1. Message with custom fields
35    /// 2. Meta-info (level, timestamp, ...)
36    /// 3. Meta-fields (location, module)
37    #[serde(default = "default_max_line_size")]
38    pub max_line_size: ByteSize,
39
40    /// Override log levels for specific targets.
41    /// Useful to suppress noisy logs from dependencies.
42    #[serde(default)]
43    pub targets: FxHashMap<String, LoggingTargetConfig>,
44}
45
46/// Configuration for a specific logging target.
47#[derive(Debug, Deserialize)]
48pub struct LoggingTargetConfig {
49    /// Maximum log level for the target.
50    #[serde(deserialize_with = "deserialize_level_filter")]
51    pub max_level: LevelFilter,
52}
53
54/// Sink for the log output.
55/// By default logs are written to stdout.
56#[derive(Debug, Default, PartialEq, Deserialize)]
57pub enum Sink {
58    /// Write logs to a file, specified by `path`.
59    File,
60    /// Write logs to stdout.
61    #[default]
62    Stdout,
63    // TODO: stdout + stderr
64}
65
66/// Log format.
67#[derive(Debug, Deserialize, Default)]
68pub struct Format {
69    /// Include location info in the log output.
70    #[serde(default)]
71    pub with_location: bool,
72    /// Include module info in the log output.
73    #[serde(default)]
74    pub with_module: bool,
75    /// Specify when to use colored output.
76    /// By default, colors are enabled only for interactive terminals.
77    #[serde(default)]
78    pub colorization: Colorization,
79}
80
81/// When to use colored output.
82#[derive(Debug, Deserialize, Default)]
83pub enum Colorization {
84    /// Use colors only if the output is a terminal.
85    #[default]
86    Auto,
87    /// Never use colors.
88    Never,
89    /// Use colors unconditionally.
90    Always,
91}
92
93fn default_max_line_size() -> ByteSize {
94    ByteSize(u64::MAX)
95}
96
97// TODO: deduplicate with core
98fn deserialize_level_filter<'de, D>(deserializer: D) -> Result<LevelFilter, D::Error>
99where
100    D: Deserializer<'de>,
101{
102    use PrettyLevelFilter::*;
103
104    #[derive(Deserialize)]
105    pub(crate) enum PrettyLevelFilter {
106        Trace,
107        Debug,
108        Info,
109        Warn,
110        Error,
111        Off,
112    }
113
114    let pretty = PrettyLevelFilter::deserialize(deserializer)?;
115
116    Ok(match pretty {
117        Trace => LevelFilter::TRACE,
118        Debug => LevelFilter::DEBUG,
119        Info => LevelFilter::INFO,
120        Warn => LevelFilter::WARN,
121        Error => LevelFilter::ERROR,
122        Off => LevelFilter::OFF,
123    })
124}