Skip to content

Commit 81024d5

Browse files
mmlogger - replace log level string with enum.
This choice is because I want the code to have a strong set of ordering of the levels, and I don't want the logger to be "loosy-goosy". This removes the "TIMING" level, and new uses INFO.
1 parent 2c4150c commit 81024d5

File tree

2 files changed

+193
-238
lines changed

2 files changed

+193
-238
lines changed

lib/rust/mmlogger/src/lib.rs

Lines changed: 68 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,27 @@ use std::time::SystemTime;
3333
// Log level filter
3434
// ====================================================================
3535

36+
/// Log severity level, ordered from least to most severe.
37+
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
38+
pub enum LogLevel {
39+
Debug = 0,
40+
Info = 1,
41+
// TODO: Add Progress between Info and Warn.
42+
Warn = 2,
43+
Error = 3,
44+
}
45+
46+
impl LogLevel {
47+
fn as_str(self) -> &'static str {
48+
match self {
49+
LogLevel::Debug => "DEBUG",
50+
LogLevel::Info => "INFO",
51+
LogLevel::Warn => "WARN",
52+
LogLevel::Error => "ERROR",
53+
}
54+
}
55+
}
56+
3657
/// Bitmask of allowed log levels for a stream.
3758
///
3859
/// Combine levels with `|`:
@@ -52,13 +73,12 @@ impl LevelFilter {
5273
pub const ERROR: LevelFilter = LevelFilter(0b1000);
5374
pub const ALL: LevelFilter = LevelFilter(0b1111);
5475

55-
pub fn allows(self, level: &str) -> bool {
76+
pub fn allows(self, level: LogLevel) -> bool {
5677
let bit: u8 = match level {
57-
"DEBUG" => 0b0001,
58-
"INFO" => 0b0010,
59-
"WARN" => 0b0100,
60-
"ERROR" => 0b1000,
61-
_ => 0,
78+
LogLevel::Debug => 0b0001,
79+
LogLevel::Info => 0b0010,
80+
LogLevel::Warn => 0b0100,
81+
LogLevel::Error => 0b1000,
6282
};
6383
self.0 & bit != 0
6484
}
@@ -147,23 +167,23 @@ fn format_unix_timestamp(secs: u64, buf: &mut [u8; 19]) {
147167
fn write_formatted<W: Write>(
148168
writer: &mut W,
149169
format: &LogFormat,
150-
level: &str,
170+
level: LogLevel,
151171
msg: &str,
152172
) {
153173
match format {
154174
LogFormat::Plain => match level {
155-
"WARN" => {
175+
LogLevel::Warn => {
156176
let _ = writeln!(writer, "Warning: {}", msg);
157177
}
158-
"ERROR" => {
178+
LogLevel::Error => {
159179
let _ = writeln!(writer, "Error: {}", msg);
160180
}
161181
_ => {
162182
let _ = writeln!(writer, "{}", msg);
163183
}
164184
},
165185
LogFormat::LevelPrefix => {
166-
let _ = writeln!(writer, "[{}] {}", level, msg);
186+
let _ = writeln!(writer, "[{}] {}", level.as_str(), msg);
167187
}
168188
LogFormat::Timestamp => {
169189
let secs = SystemTime::now()
@@ -173,7 +193,7 @@ fn write_formatted<W: Write>(
173193
let mut buf = [0u8; 19];
174194
format_unix_timestamp(secs, &mut buf);
175195
let ts = std::str::from_utf8(&buf).unwrap_or("0000-00-00 00:00:00");
176-
let _ = writeln!(writer, "[{}] [{}] {}", ts, level, msg);
196+
let _ = writeln!(writer, "[{}] [{}] {}", ts, level.as_str(), msg);
177197
}
178198
}
179199
}
@@ -184,31 +204,11 @@ fn write_formatted<W: Write>(
184204

185205
/// Trait for structured logging with zero-cost when disabled.
186206
pub trait Logger {
187-
// TODO: Get rid of this general method and force people to either
188-
// create a new level, or reuse an existing one. We need to have a
189-
// trade-off between flexibility and performance and simplicity,
190-
// and I think the `log` method is simply too flexible and adds
191-
// the cost of a string rather than a well defined enum that we
192-
// can exhaustively match and ensure all cases are covered.
193-
fn log(&self, level: &str, msg: &str);
194-
195-
fn info(&self, msg: &str) {
196-
self.log("INFO", msg);
197-
}
198-
207+
fn debug(&self, msg: &str);
208+
fn info(&self, msg: &str);
199209
// TODO: Add "progress" method between info and warn.
200-
201-
fn warn(&self, msg: &str) {
202-
self.log("WARN", msg);
203-
}
204-
205-
fn error(&self, msg: &str) {
206-
self.log("ERROR", msg);
207-
}
208-
209-
fn debug(&self, msg: &str) {
210-
self.log("DEBUG", msg);
211-
}
210+
fn warn(&self, msg: &str);
211+
fn error(&self, msg: &str);
212212
}
213213

214214
// ====================================================================
@@ -254,7 +254,7 @@ impl<W1: Write, W2: Write> DualStreamLogger<W1, W2> {
254254
}
255255

256256
/// Write a log message directly (used by the channel writer thread).
257-
pub fn write_log(&mut self, level: &str, msg: &str) {
257+
pub fn write_log(&mut self, level: LogLevel, msg: &str) {
258258
if self.levels1.allows(level) {
259259
write_formatted(&mut self.writer1, &self.format1, level, msg);
260260
}
@@ -274,7 +274,13 @@ pub struct NoOpLogger;
274274

275275
impl Logger for NoOpLogger {
276276
#[inline(always)]
277-
fn log(&self, _level: &str, _msg: &str) {}
277+
fn debug(&self, _msg: &str) {}
278+
#[inline(always)]
279+
fn info(&self, _msg: &str) {}
280+
#[inline(always)]
281+
fn warn(&self, _msg: &str) {}
282+
#[inline(always)]
283+
fn error(&self, _msg: &str) {}
278284
}
279285

280286
// ====================================================================
@@ -283,7 +289,7 @@ impl Logger for NoOpLogger {
283289

284290
/// A log message sent through the channel.
285291
struct LogMessage {
286-
level: String,
292+
level: LogLevel,
287293
msg: String,
288294
}
289295

@@ -297,9 +303,30 @@ pub struct ChannelLogger {
297303
}
298304

299305
impl Logger for ChannelLogger {
300-
fn log(&self, level: &str, msg: &str) {
306+
fn debug(&self, msg: &str) {
307+
let _ = self.sender.send(LogMessage {
308+
level: LogLevel::Debug,
309+
msg: msg.to_owned(),
310+
});
311+
}
312+
313+
fn info(&self, msg: &str) {
314+
let _ = self.sender.send(LogMessage {
315+
level: LogLevel::Info,
316+
msg: msg.to_owned(),
317+
});
318+
}
319+
320+
fn warn(&self, msg: &str) {
321+
let _ = self.sender.send(LogMessage {
322+
level: LogLevel::Warn,
323+
msg: msg.to_owned(),
324+
});
325+
}
326+
327+
fn error(&self, msg: &str) {
301328
let _ = self.sender.send(LogMessage {
302-
level: level.to_owned(),
329+
level: LogLevel::Error,
303330
msg: msg.to_owned(),
304331
});
305332
}
@@ -358,7 +385,7 @@ where
358385
writer1, format1, levels1, writer2, format2, levels2,
359386
);
360387
while let Ok(msg) = receiver.recv() {
361-
backend.write_log(&msg.level, &msg.msg);
388+
backend.write_log(msg.level, &msg.msg);
362389
}
363390
});
364391

0 commit comments

Comments
 (0)