feat: Implement new log format specification
This commit is contained in:
parent
da758206b4
commit
a8ed131b3b
1 changed files with 59 additions and 20 deletions
|
|
@ -2,20 +2,13 @@ use env_logger::fmt::Formatter;
|
|||
use log::Record;
|
||||
use std::io::Write;
|
||||
|
||||
// ANSI color codes
|
||||
const RED: &str = "\x1b[31m";
|
||||
const YELLOW: &str = "\x1b[33m";
|
||||
const GREEN: &str = "\x1b[32m";
|
||||
const CYAN: &str = "\x1b[36m";
|
||||
const RESET: &str = "\x1b[0m";
|
||||
|
||||
pub fn compact_format(buf: &mut Formatter, record: &Record) -> std::io::Result<()> {
|
||||
let (level, color) = match record.level() {
|
||||
log::Level::Error => ("E", RED),
|
||||
log::Level::Warn => ("W", YELLOW),
|
||||
log::Level::Info => ("I", GREEN),
|
||||
log::Level::Debug => ("D", CYAN),
|
||||
log::Level::Trace => ("T", ""),
|
||||
let level_char = match record.level() {
|
||||
log::Level::Error => 'E',
|
||||
log::Level::Warn => 'I', // Mapping Warn to Info per I/T/E spec
|
||||
log::Level::Info => 'I',
|
||||
log::Level::Debug => 'T', // Mapping Debug to Trace per I/T/E spec
|
||||
log::Level::Trace => 'T',
|
||||
};
|
||||
|
||||
let now = chrono::Local::now();
|
||||
|
|
@ -28,10 +21,58 @@ pub fn compact_format(buf: &mut Formatter, record: &Record) -> std::io::Result<(
|
|||
target
|
||||
};
|
||||
|
||||
if color.is_empty() {
|
||||
writeln!(buf, "{} {} {}:{}", timestamp, level, module, record.args())
|
||||
// Format: "YYYYMMDDHHMMSS.mmm L module:"
|
||||
// Length: 18 + 1 + 1 + 1 + module.len() + 1 = 22 + module.len()
|
||||
let prefix = format!("{} {} {}:", timestamp, level_char, module);
|
||||
|
||||
// Max width 80
|
||||
// If prefix + message fits, print it.
|
||||
// Else, wrap.
|
||||
// Indent for wrapping is 21 spaces (18 timestamp + 1 space + 1 level + 1 space)
|
||||
// Actually, based on spec:
|
||||
// Position: 123456789012345678901234567890...
|
||||
// Format: YYYYMMDDHHMMSS.mmm L module:Message
|
||||
// 1 18 20 22
|
||||
// So indent is 21 spaces.
|
||||
|
||||
let message = record.args().to_string();
|
||||
let indent = " "; // 21 spaces
|
||||
|
||||
if prefix.len() + message.len() <= 80 {
|
||||
writeln!(buf, "{}{}", prefix, message)
|
||||
} else {
|
||||
writeln!(buf, "{} {}{}{} {}:{}", timestamp, color, level, RESET, module, record.args())
|
||||
let available_first_line = if prefix.len() < 80 {
|
||||
80 - prefix.len()
|
||||
} else {
|
||||
0
|
||||
};
|
||||
let available_other_lines = 80 - 21; // 59 chars
|
||||
|
||||
let mut current_pos = 0;
|
||||
let chars: Vec<char> = message.chars().collect();
|
||||
let total_chars = chars.len();
|
||||
|
||||
// First line
|
||||
write!(buf, "{}", prefix)?;
|
||||
|
||||
// If prefix is already >= 80, we force a newline immediately?
|
||||
// Or we just print a bit and wrap?
|
||||
// Let's assume typical usage where module name isn't huge.
|
||||
|
||||
let take = std::cmp::min(available_first_line, total_chars);
|
||||
let first_chunk: String = chars[0..take].iter().collect();
|
||||
writeln!(buf, "{}", first_chunk)?;
|
||||
current_pos += take;
|
||||
|
||||
while current_pos < total_chars {
|
||||
write!(buf, "{}", indent)?;
|
||||
let remaining = total_chars - current_pos;
|
||||
let take = std::cmp::min(remaining, available_other_lines);
|
||||
let chunk: String = chars[current_pos..current_pos + take].iter().collect();
|
||||
writeln!(buf, "{}", chunk)?;
|
||||
current_pos += take;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -42,8 +83,6 @@ pub fn init_compact_logger(default_filter: &str) {
|
|||
}
|
||||
|
||||
pub fn init_compact_logger_with_style(default_filter: &str) {
|
||||
env_logger::Builder::from_env(env_logger::Env::default().default_filter_or(default_filter))
|
||||
.format(compact_format)
|
||||
.write_style(env_logger::WriteStyle::Always)
|
||||
.init();
|
||||
// Style ignored to strictly follow text format spec
|
||||
init_compact_logger(default_filter);
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue