Compare commits

...
2 Commits
2 changed files with 16 additions and 3 deletions
+7 -1
View File
@@ -166,7 +166,13 @@ pub fn rotate(dir: &Path) -> std::io::Result<(PathBuf, File)> {
/// One formatted log line: `<timestamp> <LEVEL> [<thread>] <target>: <message>\n`.
pub fn format_line(ts: &str, level: log::Level, thread: &str, target: &str, message: &str) -> String {
let message = message.strip_suffix('\n').unwrap_or(message);
format!("{ts} {level:<5} [{thread}] {target}: {message}\n")
// Control characters are written escaped: a message quoting a session file (a plugin id, a
// path) must not start a line of its own in the log or steer the terminal.
let mut escaped = String::with_capacity(message.len());
for c in message.chars() {
if c.is_control() { escaped.extend(c.escape_default()) } else { escaped.push(c) }
}
format!("{ts} {level:<5} [{thread}] {target}: {escaped}\n")
}
/// Where formatted lines go besides standard error: kept in memory until a file is attached,
+9 -2
View File
@@ -158,8 +158,15 @@ fn a_line_carries_time_level_thread_target_and_message() {
format_line("2026-10-08T07:59:17.728Z", log::Level::Warn, "main", "soundcraft_mix", "eq_7band: the plugin did not accept its stored state"),
"2026-10-08T07:59:17.728Z WARN [main] soundcraft_mix: eq_7band: the plugin did not accept its stored state\n"
);
// A multi-line message keeps its lines; the record still ends in exactly one newline.
assert!(format_line("t", log::Level::Error, "w", "x", "a\nb\n").ends_with("x: a\nb\n"));
// A message with breaks of its own stays one record; the record still ends in exactly one newline.
assert!(
format_line("t", log::Level::Error, "w", "x", "a\nb\n").ends_with("x: a\\nb\n"),
"a break inside the message is escaped, the final one dropped"
);
assert!(
format_line("t", log::Level::Error, "w", "x", "plugin \u{1b}[2J\r\n2026 INFO forged")
.ends_with("x: plugin \\u{1b}[2J\\r\\n2026 INFO forged\n")
);
}
#[test]