nullnet_liblogging/
lib.rs

1#![doc = include_str!("../README.md")]
2
3use std::iter::{IntoIterator, Iterator};
4use std::str::FromStr;
5
6use log::LevelFilter;
7
8use crate::console_logger::ConsoleLogger;
9pub use crate::datastore::config::{DatastoreConfig, ServerKind};
10use crate::datastore_logger::DatastoreLogger;
11use crate::syslog_logger::SyslogLogger;
12
13mod console_logger;
14mod datastore;
15mod datastore_logger;
16mod syslog_logger;
17
18static DEFAULT_ALLOWED_TARGETS: std::sync::LazyLock<Vec<String>> = std::sync::LazyLock::new(|| {
19    vec!["nullnet", "appguard", "wallguard"]
20        .into_iter()
21        .map(str::to_lowercase)
22        .collect()
23});
24
25/// Logger implementation that logs to console, syslog, and Datastore
26pub struct Logger {
27    console: ConsoleLogger,
28    syslog: SyslogLogger,
29    datastore: DatastoreLogger,
30    allowed_targets: Vec<String>,
31}
32
33impl Logger {
34    /// Initializes the logger with the given configuration
35    ///
36    /// # Arguments
37    /// * `logger_config` - The logger configuration
38    pub fn init(logger_config: LoggerConfig) {
39        let LoggerConfig {
40            console,
41            syslog,
42            datastore,
43            allowed_targets,
44        } = logger_config;
45
46        let env_log_level = std::env::var("LOG_LEVEL").unwrap_or("trace".to_string());
47        let level_filter = LevelFilter::from_str(&env_log_level).unwrap_or(LevelFilter::Trace);
48        if level_filter.to_level().is_some() {
49            let allowed_targets = allowed_targets.into_iter().map(str::to_lowercase).collect();
50            log::set_boxed_logger(Box::new(Logger {
51                console: ConsoleLogger::new(console),
52                syslog: SyslogLogger::new(syslog),
53                datastore: DatastoreLogger::new(datastore),
54                allowed_targets,
55            }))
56            .unwrap_or_default();
57        }
58        log::set_max_level(level_filter);
59    }
60}
61
62impl log::Log for Logger {
63    fn enabled(&self, metadata: &log::Metadata) -> bool {
64        !metadata.target().starts_with("nullnet_liblogging")
65            && (self.syslog.enabled(metadata)
66                || self.console.enabled(metadata)
67                || self.datastore.enabled(metadata))
68    }
69
70    fn log(&self, record: &log::Record) {
71        if self.enabled(record.metadata()) {
72            let target = record.target().to_lowercase();
73            if DEFAULT_ALLOWED_TARGETS
74                .iter()
75                .any(|s| target.starts_with(s))
76                || self.allowed_targets.iter().any(|s| target.starts_with(s))
77            {
78                self.syslog.log(record);
79                self.console.log(record);
80                self.datastore.log(record);
81            }
82        }
83    }
84
85    fn flush(&self) {
86        self.syslog.flush();
87        self.console.flush();
88        self.datastore.flush();
89    }
90}
91
92/// Logger configuration
93pub struct LoggerConfig {
94    console: bool,
95    syslog: bool,
96    datastore: Option<DatastoreConfig>,
97    allowed_targets: Vec<&'static str>,
98}
99
100impl LoggerConfig {
101    /// Creates a new logger configuration
102    ///
103    /// # Arguments
104    /// * `console` - Whether to log to console
105    /// * `syslog` - Whether to log to syslog
106    /// * `datastore` - Datastore configuration (use `None` to disable logging to Datastore)
107    /// * `allowed_targets` - The list of allowed targets.<br>
108    ///   By default, only logs from `nullnet*`, `appguard*`, and `wallguard*` will be emitted.<br>
109    ///   Use this parameter to specify additional targets
110    ///   (e.g., specifying "serde" will emit logs for all targets whose name is in the form `serde*`).
111    #[must_use]
112    pub fn new(
113        console: bool,
114        syslog: bool,
115        datastore: Option<DatastoreConfig>,
116        allowed_targets: Vec<&'static str>,
117    ) -> Self {
118        Self {
119            console,
120            syslog,
121            datastore,
122            allowed_targets,
123        }
124    }
125}