flogging/logger/
level.rs

1//
2// File Name:    level.rs
3// Project Name: flogging
4//
5// Copyright (C) 2025 Bradley Willcott
6//
7// SPDX-License-Identifier: GPL-3.0-or-later
8//
9// This library (crate) is free software: you can redistribute it and/or modify
10// it under the terms of the GNU General Public License as published by
11// the Free Software Foundation, either version 3 of the License, or
12// (at your option) any later version.
13//
14// This library (crate) is distributed in the hope that it will be useful,
15// but WITHOUT ANY WARRANTY; without even the implied warranty of
16// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17// GNU General Public License for more details.
18//
19// You should have received a copy of the GNU General Public License
20// along with this library (crate).  If not, see <https://www.gnu.org/licenses/>.
21//
22
23//!
24//! # Log Entry Level
25//!
26//! This module provides the enum containing the possible log entry levels.
27//! The order in which they are listed within the enum, enables logging at that level
28//! and at all higher levels.
29//!
30//! The levels in descending order are:
31//!
32//! - SEVERE (highest level)
33//! - WARNING
34//! - INFO
35//! - CONFIG
36//! - FINE
37//! - FINER
38//! - FINEST (lowest level)
39//!
40//! In addition there is a level **OFF** that can be used to turn off logging.
41
42use std::{fmt, str::FromStr};
43use strum::{EnumIter, IntoEnumIterator};
44
45///
46/// Log entry level setting.
47///
48/// Default level: INFO.
49///
50// #[allow(unused)]
51#[derive(Debug, Clone, Default, PartialEq, PartialOrd, EnumIter)]
52pub enum Level {
53    ///
54    /// ALL is a special level that can be used to turn on logging
55    /// for all levels.
56    ///
57    ALL,
58
59    ///
60    /// FINEST indicates a highly detailed tracing message.
61    ///
62    FINEST,
63
64    ///
65    /// FINER indicates a fairly detailed tracing message.
66    /// Suggest logging calls for entering, returning,
67    /// or `Error`s, such as returned via `Result`, are traced at
68    /// this level.
69    ///
70    FINER,
71
72    ///
73    /// FINE is a message level providing tracing information.
74    ///
75    /// All of FINE, FINER, and FINEST are intended for relatively
76    /// detailed tracing. The exact meaning of the three levels will
77    /// vary between subsystems, but in general, FINEST should be
78    /// used for the most voluminous detailed output, FINER for somewhat
79    /// less detailed output, and FINE for the lowest volume (and most
80    /// important) messages.
81    ///
82    /// In general the FINE level should be used for information that
83    /// will be broadly interesting to developers who do not have a
84    /// specialized interest in the specific subsystem.
85    ///
86    /// FINE messages might include things like minor (recoverable)
87    /// failures. Issues indicating potential performance problems are
88    /// also worth logging as FINE.
89    ///
90    FINE,
91
92    ///
93    /// CONFIG is a message level for static configuration messages.
94    ///
95    /// CONFIG messages are intended to provide a variety of static
96    /// configuration information, to assist in debugging problems
97    /// that may be associated with particular configurations.
98    ///
99    /// For example, a CONFIG message might include the CPU type, the
100    /// graphics depth, the GUI look-and-feel, etc.
101    ///
102    CONFIG,
103
104    ///
105    /// INFO is a message level for informational messages.
106    ///
107    /// Typically INFO messages will be written to the console or its
108    /// equivalent. So the INFO level should only be used for reasonably
109    /// significant messages that will make sense to end users and system
110    /// administrators.
111    ///
112    /// \[default level]
113    ///
114    #[default]
115    INFO,
116
117    ///
118    /// WARNING is a message level indicating a potential problem.
119    ///
120    /// In general WARNING messages should describe events that will be
121    /// of interest to end users or system managers, or which indicate
122    /// potential problems.
123    ///
124    WARNING,
125
126    ///
127    /// SEVERE is a message level indicating a serious failure.
128    ///
129    /// In general SEVERE messages should describe events that are of
130    /// considerable importance and which will prevent normal program
131    /// execution. They should be reasonably intelligible to end users
132    /// and to system administrators.
133    ///
134    SEVERE,
135
136    ///
137    /// OFF is a special level that can be used to turn off logging.
138    ///
139    OFF,
140}
141
142impl Level {
143    ///
144    /// Converts a level to its string version.
145    ///
146    pub const fn as_str(&self) -> &'static str {
147        match self {
148            Level::ALL => "ALL",
149            Level::FINEST => "FINEST",
150            Level::FINER => "FINER",
151            Level::FINE => "FINE",
152            Level::CONFIG => "CONFIG",
153            Level::INFO => "INFO",
154            Level::WARNING => "WARNING",
155            Level::SEVERE => "SEVERE",
156            Level::OFF => "OFF",
157        }
158    }
159}
160
161impl fmt::Display for Level {
162    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
163        self.as_str().fmt(f)
164    }
165}
166
167#[allow(dead_code)]
168#[derive(Debug)]
169pub struct LevelError {
170    msg: String,
171}
172
173impl FromStr for Level {
174    type Err = LevelError;
175
176    fn from_str(s: &str) -> Result<Self, Self::Err> {
177        match s {
178            "ALL" => Ok(Level::ALL),
179            "FINEST" => Ok(Level::FINEST),
180            "FINER" => Ok(Level::FINER),
181            "FINE" => Ok(Level::FINE),
182            "CONFIG" => Ok(Level::CONFIG),
183            "INFO" => Ok(Level::INFO),
184            "WARNING" => Ok(Level::WARNING),
185            "SEVERE" => Ok(Level::SEVERE),
186            "OFF" => Ok(Level::OFF),
187            _ => Err(LevelError {
188                msg: format!("Unknown Level: {s}"),
189            }),
190        }
191    }
192}
193
194#[cfg(test)]
195mod tests {
196    use super::*;
197
198    #[test]
199    fn compare_levels() {
200        let log_level = Level::default();
201        let b = Level::FINE;
202
203        println!("\n|{log_level}|\n");
204
205        assert!(b < log_level);
206    }
207
208    #[test]
209    fn check_conversions() {
210        for level in Level::iter() {
211            let lstr = level.as_str();
212            let l = Level::from_str(lstr).unwrap();
213            assert_eq!(level, l);
214        }
215
216        assert!(Level::from_str("DEBUG").is_err());
217    }
218}