signstar_common/logging.rs
1//! Logging utilities.
2
3use log::{LevelFilter, SetLoggerError, set_max_level};
4use simplelog::{ColorChoice, TermLogger, TerminalMode};
5use systemd_journal_logger::{JournalLog, connected_to_journal};
6
7/// Logging setup error.
8#[derive(Debug, thiserror::Error)]
9pub enum Error {
10 /// The process is not connected to the systemd journal.
11 #[error("The process is not connected to the system journal")]
12 JournalNotConnected,
13
14 /// Journal initialization error.
15 #[error("Journal initialization error: {0}")]
16 Journal(std::io::Error),
17
18 /// Logger initialization error.
19 #[error("Logger initialization error: {0}")]
20 Logger(#[from] SetLoggerError),
21}
22
23/// Sets up a global terminal logger based on a maximum logging level filter.
24///
25/// # Errors
26///
27/// Returns an error, if [`TermLogger::init`] fails.
28pub fn setup_terminal_logging(max_level: impl Into<LevelFilter>) -> Result<(), crate::Error> {
29 TermLogger::init(
30 max_level.into(),
31 Default::default(),
32 TerminalMode::Stderr,
33 ColorChoice::Auto,
34 )
35 .map_err(|error| Error::Logger(error).into())
36}
37
38/// Sets up a global systemd journal logger based on a maximum logging level filter.
39///
40/// # Errors
41///
42/// Returns an error, if globally installing a [`JournalLog`] fails.
43pub fn setup_systemd_journal_logging(
44 max_level: impl Into<LevelFilter>,
45) -> Result<(), crate::Error> {
46 JournalLog::new()
47 .map_err(Error::Journal)?
48 .with_extra_fields(vec![("VERSION", env!("CARGO_PKG_VERSION"))])
49 .install()
50 .map_err(Error::Logger)?;
51
52 set_max_level(max_level.into());
53
54 Ok(())
55}
56
57/// Sets up a global systemd journal logger based on a maximum logging level filter, when connected
58/// to the journal.
59///
60/// # Note
61///
62/// Only sets up logging, if the current process is connected to the journal (see `JOURNAL_STREAM`
63/// in [systemd.exec(5)]). This is particularly useful e.g. in [systemd.service(5)] files in which
64/// the executed command is connected to the journal with the help of the `StandardOutput` and
65/// `StandardError` [logging and standard input/output settings].
66///
67/// # Errors
68///
69/// Returns an error, if
70///
71/// - the process is not connected to the systemd journal
72/// - globally installing a [`JournalLog`] fails
73///
74/// [systemd.exec(5)]: https://man.archlinux.org/man/systemd.exec.5
75/// [systemd.service(5)]: https://man.archlinux.org/man/systemd.service.5
76/// [logging and standard input/output settings]: https://man.archlinux.org/man/systemd.exec.5#LOGGING_AND_STANDARD_INPUT/OUTPUT
77pub fn setup_systemd_journal_logging_when_connected(
78 max_level: impl Into<LevelFilter>,
79) -> Result<(), crate::Error> {
80 if !connected_to_journal() {
81 return Err(Error::JournalNotConnected.into());
82 }
83
84 JournalLog::new()
85 .map_err(Error::Journal)?
86 .with_extra_fields(vec![("VERSION", env!("CARGO_PKG_VERSION"))])
87 .install()
88 .map_err(Error::Logger)?;
89
90 set_max_level(max_level.into());
91
92 Ok(())
93}