1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
use std::cmp::Ordering;
use std::fmt::{Display, Formatter};
use std::str::FromStr;
use serde::Serialize;
/// Represents the log levels.
#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize)]
pub enum Level {
/// System is unusable, requires immediate attention
Emergency,
/// Immediate action must be taken, critical alert
Alert,
/// Critical conditions, serious failures
Critical,
/// Error conditions, runtime errors
Error,
/// Warning conditions, potential issues
Warning,
/// Normal but significant events, noteworthy conditions
Notice,
/// Informational messages, general system events
Info,
/// Debug-level messages, detailed diagnostic information
Debug,
/// User-defined custom log level, allows arbitrary string values
/// with an optional numeric severity for ordering.
Custom(String, Option<i8>),
}
impl Level {
/// Returns the standardized name of this log level in lowercase.
///
/// - `Level::Emergency` - **emergency** (System is unusable, requires immediate attention)
/// - `Level::Alert` - **alert** (Immediate action must be taken, critical alert)
/// - `Level::Critical` - **critical** (Critical conditions, serious failures)
/// - `Level::Error` - **error** (Error conditions, runtime errors)
/// - `Level::Warning` - **warning** (Warning conditions, potential issues)
/// - `Level::Notice` - **notice** (Normal but significant events, noteworthy conditions)
/// - `Level::Info` - **info** (Informational messages, general system events)
/// - `Level::Debug` - **debug** (Debug-level messages, detailed diagnostic information)
///
/// Custom levels are converted to lowercase strings.
pub fn name(&self) -> String {
match self {
Level::Emergency => "emergency".into(),
Level::Alert => "alert".into(),
Level::Critical => "critical".into(),
Level::Error => "error".into(),
Level::Warning => "warning".into(),
Level::Notice => "notice".into(),
Level::Info => "info".into(),
Level::Debug => "debug".into(),
Level::Custom(s, _) => s.to_lowercase(),
}
}
/// Returns the numeric severity value for this log level.
///
/// - `Emergency` - **0** System is unusable, requires immediate attention.
/// - `Alert` - **1** Immediate action must be taken, critical alert.
/// - `Critical` - **2** Critical conditions, serious failures.
/// - `Error` - **3** Error conditions, runtime errors.
/// - `Warning` - **4** Warning conditions, potential issues.
/// - `Notice` - **5** Normal but significant events, noteworthy conditions.
/// - `Info` - **6** Informational messages, general system events.
/// - `Debug` - **7** Debug-level messages, detailed diagnostic information.
///
/// Custom levels return their defined severity if provided,
/// otherwise `-1` because they do not have a defined numeric mapping.
pub fn severity(&self) -> i8 {
match self {
Level::Debug => 7,
Level::Info => 6,
Level::Notice => 5,
Level::Warning => 4,
Level::Error => 3,
Level::Critical => 2,
Level::Alert => 1,
Level::Emergency => 0,
Level::Custom(_, Some(v)) => *v,
Level::Custom(_, None) => -1,
}
}
/// Returns true if this level is more severe than `other`.
///
/// **Parameters**
/// - `other`: The `Level` to compare against.
///
/// **Returns**
/// - `true` if this level is more severe than `other`
pub fn above(&self, other: &Self) -> bool {
self.severity() < other.severity()
}
/// Returns true if this level is less severe than `other`.
///
/// **Parameters**
/// - `other`: The `Level` to compare against.
///
/// **Returns**
/// - `true` if this level is less severe than `other`
pub fn below(&self, other: &Self) -> bool {
self.severity() > other.severity()
}
/// Constructs a `Level` from a string name (case-insensitive).
///
/// Each name corresponds to a standard log level:
/// - `"debug"` - `Debug`
/// - `"info"` - `Info`
/// - `"notice"` - `Notice`
/// - `"warning"` - `Warning`
/// - `"error"` - `Error`
/// - `"critical"` - `Critical`
/// - `"alert"` - `Alert`
/// - `"emergency"` - `Emergency`
///
/// Any other string will be mapped to a `Custom` level
/// with no predefined severity (`None`).
pub fn from_name(name: &str) -> Self {
match name.to_lowercase().as_str() {
"debug" => Level::Debug,
"info" => Level::Info,
"notice" => Level::Notice,
"warning" => Level::Warning,
"error" => Level::Error,
"critical" => Level::Critical,
"alert" => Level::Alert,
"emergency" => Level::Emergency,
other => Level::Custom(other.to_string(), None),
}
}
/// Constructs a `Level` from its numeric severity value.
///
/// - `0` - **Emergency** (System is unusable, requires immediate attention)
/// - `1` - **Alert** (Immediate action must be taken, critical alert)
/// - `2` - **Critical** (Critical conditions, serious failures)
/// - `3` - **Error** (Error conditions, runtime errors)
/// - `4` - **Warning** (Warning conditions, potential issues)
/// - `5` - **Notice** (Normal but significant events, noteworthy conditions)
/// - `6` - **Info** (Informational messages, general system events)
/// - `7` - **Debug** (Debug-level messages, detailed diagnostic information)
///
/// Any other numeric value will be mapped to a `Custom` level
/// with the numeric severity preserved.
pub fn from_severity(severity: i8) -> Self {
match severity {
0 => Level::Emergency,
1 => Level::Alert,
2 => Level::Critical,
3 => Level::Error,
4 => Level::Warning,
5 => Level::Notice,
6 => Level::Info,
7 => Level::Debug,
other => Level::Custom(other.to_string(), Some(other)),
}
}
}
impl Display for Level {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
f.write_str(self.name().as_ref())
}
}
impl FromStr for Level {
type Err = ();
fn from_str(s: &str) -> Result<Self, Self::Err> {
Ok(Self::from_name(s))
}
}
impl PartialOrd for Level {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
Some(self.cmp(other))
}
}
impl Ord for Level {
fn cmp(&self, other: &Self) -> Ordering {
self.severity().cmp(&other.severity()).reverse()
}
}