小红书导出失败日志按字符数截断

- commands.rs 的 log_failure 落盘前经 bounded_for_log 截到 512 字符,CommandFailed 的 4KB 脚本输出不再整段写进 AppData 日志与去重表

- 新增 bounded_for_log 的短文本与中文边界用例
This commit is contained in:
2026-10-06 18:51:02 +08:00
parent eee12b2809
commit 9722b42692
@@ -151,8 +151,15 @@ fn report<T, E: std::fmt::Debug>(command: &'static str, project_path: &str, resu
}
}
/// 一条失败日志最多记多少个字符。
///
/// `CommandFailed` 的 `Debug` 里带着最多 4,000 字符的脚本输出尾部,原样落进 AppData 日志会把一次
/// 失败撑成好几 KB,去重表也跟着留一份长字符串。日志只需要认得出「哪个变体、哪条命令失败」,
/// 完整现场已经结构化回给前端了。
const MAX_LOGGED_FAILURE_CHARS: usize = 512;
fn log_failure(command: &'static str, project_path: &str, error: &impl std::fmt::Debug) {
let message = format!("{error:?}");
let message = bounded_for_log(&format!("{error:?}"), MAX_LOGGED_FAILURE_CHARS);
if let Ok(mut last) = LAST_FAILURE.lock() {
if last.get(command).is_some_and(|seen| *seen == message) {
return;
@@ -162,6 +169,15 @@ fn log_failure(command: &'static str, project_path: &str, error: &impl std::fmt:
app_log!("export.{command}.failed project={project_path}: {message}");
}
/// 按**字符**(不是字节)截断日志文本,避免切坏 UTF-8;发生截断时补一个省略号说明。
fn bounded_for_log(message: &str, max_chars: usize) -> String {
if message.chars().count() <= max_chars {
return message.to_string();
}
let head: String = message.chars().take(max_chars).collect();
format!("{head}…")
}
fn clear_failure(command: &'static str) {
if let Ok(mut last) = LAST_FAILURE.lock() {
last.remove(command);
@@ -176,7 +192,7 @@ fn short(hash: &str) -> &str {
#[cfg(test)]
mod tests {
use super::short;
use super::{bounded_for_log, short};
#[test]
fn short_keeps_first_eight_characters() {
@@ -184,4 +200,11 @@ mod tests {
assert_eq!(short("0123"), "0123");
assert_eq!(short(""), "");
}
#[test]
fn bounded_for_log_keeps_short_text_and_truncates_on_char_boundaries() {
assert_eq!(bounded_for_log("构建失败", 8), "构建失败");
// 按字符截断:4 个中文字符不会被切坏,末尾补省略号。
assert_eq!(bounded_for_log("一二三四五六", 4), "一二三四…");
}
}