ostd/log/level.rs
1// SPDX-License-Identifier: MPL-2.0
2
3//! Log level and level filter types.
4
5use core::fmt;
6
7/// Kernel log level, matching the severity levels described in `syslog(2)`.
8///
9/// # Ordering
10///
11/// Levels are ordered by severity: `Emerg < Alert < ... < Debug`.
12/// `a < b` means `a` is more severe than `b`.
13///
14/// Higher severity is assigned lower numeric value.
15/// For example,
16/// `Level::Emerg` has the smallest value of 0 and means the highest severity.
17/// On the end of the spectrum,
18/// `Level::Debug` has the largest value of 7 and means the lowest severity.
19///
20/// # Mapping from Linux's logging levels
21///
22/// The numeric values of `Level::Xxx` are assigned to those of their Linux counterparts.
23///
24/// ```text
25/// LOGLEVEL_EMERG 0 /* system is unusable */
26/// LOGLEVEL_ALERT 1 /* action must be taken immediately */
27/// LOGLEVEL_CRIT 2 /* critical conditions */
28/// LOGLEVEL_ERR 3 /* error conditions */
29/// LOGLEVEL_WARNING 4 /* warning conditions */
30/// LOGLEVEL_NOTICE 5 /* normal but significant condition */
31/// LOGLEVEL_INFO 6 /* informational */
32/// LOGLEVEL_DEBUG 7 /* debug-level messages */
33/// ```
34///
35/// # Mapping from the `log` crate
36///
37/// | `log::Level` | `ostd::log::Level` | Notes |
38/// |--------------|--------------------| ------|
39/// | Error | Error (3) | |
40/// | Warn | Warning (4) | |
41/// | Info | Info (6) | |
42/// | Debug | Debug (7) | |
43/// | Trace | Debug (7) | Bridge only; no `trace!` macro in OSTD |
44#[repr(u8)]
45#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
46pub enum Level {
47 /// System is unusable.
48 Emerg = 0,
49 /// Action must be taken immediately.
50 Alert = 1,
51 /// Critical conditions.
52 Crit = 2,
53 /// Error conditions.
54 Error = 3,
55 /// Warning conditions.
56 Warning = 4,
57 /// Normal but significant condition.
58 Notice = 5,
59 /// Informational.
60 Info = 6,
61 /// Debug-level messages.
62 Debug = 7,
63}
64
65impl Level {
66 /// Creates a `Level` from a numeric value (0--7).
67 ///
68 /// Values > 7 are clamped to `Debug`.
69 pub const fn from_u8(val: u8) -> Self {
70 match val {
71 0 => Self::Emerg,
72 1 => Self::Alert,
73 2 => Self::Crit,
74 3 => Self::Error,
75 4 => Self::Warning,
76 5 => Self::Notice,
77 6 => Self::Info,
78 _ => Self::Debug,
79 }
80 }
81}
82
83impl fmt::Display for Level {
84 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
85 f.pad(match self {
86 Level::Emerg => "EMERG",
87 Level::Alert => "ALERT",
88 Level::Crit => "CRIT",
89 Level::Error => "ERROR",
90 Level::Warning => "WARN",
91 Level::Notice => "NOTICE",
92 Level::Info => "INFO",
93 Level::Debug => "DEBUG",
94 })
95 }
96}
97
98/// A filter for log levels.
99///
100/// `LevelFilter::from_level(level)` includes that level and all more-severe levels.
101/// `LevelFilter::Off` disables all logging.
102///
103/// The filtering rule: a level passes when `(filter as u8) > (level as u8)`.
104///
105/// ```text
106/// LevelFilter::Off(0) -> nothing passes
107/// LevelFilter::Error(4) -> Emerg(0), Alert(1), Crit(2), Error(3)
108/// LevelFilter::Debug(8) -> everything
109/// ```
110#[repr(u8)]
111#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
112pub enum LevelFilter {
113 /// All logging disabled.
114 Off = 0,
115 /// Enable Emerg only.
116 Emerg = 1,
117 /// Enable Emerg and Alert.
118 Alert = 2,
119 /// Enable Emerg through Crit.
120 Crit = 3,
121 /// Enable Emerg through Error.
122 Error = 4,
123 /// Enable Emerg through Warning.
124 Warning = 5,
125 /// Enable Emerg through Notice.
126 Notice = 6,
127 /// Enable Emerg through Info.
128 Info = 7,
129 /// Enable all levels.
130 Debug = 8,
131}
132
133impl LevelFilter {
134 /// Returns `true` if `level` passes this filter.
135 #[inline]
136 pub const fn is_enabled(self, level: Level) -> bool {
137 (self as u8) > (level as u8)
138 }
139
140 /// Constructs a filter that enables `level` and all more-severe levels.
141 pub const fn from_level(level: Level) -> Self {
142 match level {
143 Level::Emerg => Self::Emerg,
144 Level::Alert => Self::Alert,
145 Level::Crit => Self::Crit,
146 Level::Error => Self::Error,
147 Level::Warning => Self::Warning,
148 Level::Notice => Self::Notice,
149 Level::Info => Self::Info,
150 Level::Debug => Self::Debug,
151 }
152 }
153
154 /// Creates a `LevelFilter` from a numeric value (0--8).
155 ///
156 /// Values > 8 are clamped to `Debug`.
157 pub const fn from_u8(val: u8) -> Self {
158 match val {
159 0 => Self::Off,
160 1 => Self::Emerg,
161 2 => Self::Alert,
162 3 => Self::Crit,
163 4 => Self::Error,
164 5 => Self::Warning,
165 6 => Self::Notice,
166 7 => Self::Info,
167 _ => Self::Debug,
168 }
169 }
170}
171
172#[cfg(ktest)]
173mod test {
174 use super::*;
175 use crate::prelude::*;
176
177 #[ktest]
178 fn level_ordering() {
179 assert!(Level::Emerg < Level::Alert);
180 assert!(Level::Alert < Level::Crit);
181 assert!(Level::Crit < Level::Error);
182 assert!(Level::Error < Level::Warning);
183 assert!(Level::Warning < Level::Notice);
184 assert!(Level::Notice < Level::Info);
185 assert!(Level::Info < Level::Debug);
186 }
187
188 #[ktest]
189 fn level_filter_enabled() {
190 assert!(!LevelFilter::Off.is_enabled(Level::Emerg));
191 assert!(LevelFilter::Emerg.is_enabled(Level::Emerg));
192 assert!(!LevelFilter::Emerg.is_enabled(Level::Alert));
193 assert!(LevelFilter::Error.is_enabled(Level::Error));
194 assert!(LevelFilter::Error.is_enabled(Level::Crit));
195 assert!(!LevelFilter::Error.is_enabled(Level::Warning));
196 assert!(LevelFilter::Debug.is_enabled(Level::Debug));
197 }
198
199 #[ktest]
200 fn level_from_u8_clamping() {
201 assert_eq!(Level::from_u8(0), Level::Emerg);
202 assert_eq!(Level::from_u8(7), Level::Debug);
203 assert_eq!(Level::from_u8(255), Level::Debug);
204 }
205
206 #[ktest]
207 fn level_filter_from_level() {
208 assert_eq!(LevelFilter::from_level(Level::Error), LevelFilter::Error);
209 assert_eq!(LevelFilter::from_level(Level::Debug), LevelFilter::Debug);
210 }
211}