Unlucky Launcher v0.0.1-alpha
CI / fmt (rustfmt --check) (push) Canceled after 0s
CI / clippy (ubuntu-latest) (push) Canceled after 0s
CI / clippy (windows-latest) (push) Canceled after 0s
CI / test (ubuntu-latest) (push) Canceled after 0s
CI / test (windows-latest) (push) Canceled after 0s
CI / build release (ubuntu-latest) (push) Canceled after 0s
CI / build release (windows-latest) (push) Canceled after 0s
Guards / core 零 UI 守门 (push) Canceled after 0s
Guards / 文件行数 ≤400 守门 (push) Canceled after 0s
Guards / 依赖许可与来源(cargo-deny) (push) Canceled after 0s
CI / fmt (rustfmt --check) (push) Canceled after 0s
CI / clippy (ubuntu-latest) (push) Canceled after 0s
CI / clippy (windows-latest) (push) Canceled after 0s
CI / test (ubuntu-latest) (push) Canceled after 0s
CI / test (windows-latest) (push) Canceled after 0s
CI / build release (ubuntu-latest) (push) Canceled after 0s
CI / build release (windows-latest) (push) Canceled after 0s
Guards / core 零 UI 守门 (push) Canceled after 0s
Guards / 文件行数 ≤400 守门 (push) Canceled after 0s
Guards / 依赖许可与来源(cargo-deny) (push) Canceled after 0s
Rust 原生单文件 Minecraft 启动器:CLI 完整可用(install/launch/accounts/java/diagnose/agent), MCP server 接入外部 Agent 工具,GUI 开发中。
This commit is contained in:
commit
bc41dfcf7d
517 files changed
+92844
No files matched your search
@@ -0,0 +1,114 @@
|
||||
//! 日志级别猜测与“关键行”判定。
|
||||
//!
|
||||
//! 平移自 `analyse/02` §6.4(`Log4jLevel.guessLevel`):先认 log4j 注入的
|
||||
//! `[HH:mm:ss] [thread/LEVEL]` 格式,再退到 JUL 的 `[INFO]` 形态;`stderr` 一律当
|
||||
//! ERROR(`[authlib-injector]` 例外)。
|
||||
//!
|
||||
//! 目的有两个:给事件流打 `level`,以及让环形缓冲能“关键行永久保留”
|
||||
//! (`analyse/02` §7.10-3:2000 行截断会把根因行挤掉)。
|
||||
|
||||
/// 日志级别(认知顺序:Error 最严重)。
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
|
||||
pub enum Level {
|
||||
/// 错误。
|
||||
Error,
|
||||
/// 警告。
|
||||
Warn,
|
||||
/// 信息。
|
||||
Info,
|
||||
/// 调试。
|
||||
Debug,
|
||||
/// 无法判断。
|
||||
Unknown,
|
||||
}
|
||||
|
||||
impl Level {
|
||||
/// 事件流里用的字符串形式。
|
||||
pub fn as_str(self) -> &'static str {
|
||||
match self {
|
||||
Self::Error => "error",
|
||||
Self::Warn => "warn",
|
||||
Self::Info => "info",
|
||||
Self::Debug => "debug",
|
||||
Self::Unknown => "unknown",
|
||||
}
|
||||
}
|
||||
|
||||
/// 是否错误级(退出分析筛行用)。
|
||||
pub fn is_error(self) -> bool {
|
||||
self == Self::Error
|
||||
}
|
||||
}
|
||||
|
||||
/// 猜测一行日志的级别。
|
||||
pub fn guess(is_stderr: bool, line: &str) -> Level {
|
||||
let trimmed = line.trim_start();
|
||||
if is_stderr {
|
||||
// authlib-injector 往 stderr 打的都是正常信息(`analyse/02` §6.4)。
|
||||
if trimmed.starts_with("[authlib-injector]") {
|
||||
return Level::Info;
|
||||
}
|
||||
return Level::Error;
|
||||
}
|
||||
if let Some(level) = log4j_level(trimmed) {
|
||||
return level;
|
||||
}
|
||||
jul_level(trimmed).unwrap_or(Level::Unknown)
|
||||
}
|
||||
|
||||
/// 是否“关键行”:命中这些特征的行不随环形淘汰(`Exception|Error|Caused by|OutOfMemory`)。
|
||||
pub fn is_key_line(line: &str) -> bool {
|
||||
let lower = line.to_ascii_lowercase();
|
||||
lower.contains("exception")
|
||||
|| lower.contains("error")
|
||||
|| lower.contains("caused by")
|
||||
|| lower.contains("outofmemory")
|
||||
|| lower.contains("fatal")
|
||||
}
|
||||
|
||||
/// 从 `[12:34:56] [Render thread/INFO]: ...` 里取级别。
|
||||
///
|
||||
/// 逐段扫描方括号内容,取第一段形如 `<线程名>/<LEVEL>` 的级别,最多看 3 段。
|
||||
fn log4j_level(line: &str) -> Option<Level> {
|
||||
let mut rest = line;
|
||||
for _ in 0..3 {
|
||||
let open = rest.find('[')?;
|
||||
let tail = &rest[open + 1..];
|
||||
let close = tail.find(']')?;
|
||||
let segment = &tail[..close];
|
||||
if let Some(slash) = segment.rfind('/') {
|
||||
if let Some(level) = level_from_name(&segment[slash + 1..]) {
|
||||
return Some(level);
|
||||
}
|
||||
}
|
||||
rest = &tail[close + 1..];
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
fn level_from_name(name: &str) -> Option<Level> {
|
||||
match name.trim() {
|
||||
"ERROR" | "FATAL" => Some(Level::Error),
|
||||
"WARN" | "WARNING" => Some(Level::Warn),
|
||||
"INFO" | "NOTICE" => Some(Level::Info),
|
||||
"DEBUG" | "TRACE" | "FINE" | "FINER" | "FINEST" => Some(Level::Debug),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
/// JUL/裸标记形态:`[INFO]`、`[SEVERE]`、`[WARNING]`。
|
||||
fn jul_level(line: &str) -> Option<Level> {
|
||||
const MARKERS: &[(&str, Level)] = &[
|
||||
("[SEVERE]", Level::Error),
|
||||
("[ERROR]", Level::Error),
|
||||
("[WARNING]", Level::Warn),
|
||||
("[WARN]", Level::Warn),
|
||||
("[INFO]", Level::Info),
|
||||
("[DEBUG]", Level::Debug),
|
||||
("[FINE]", Level::Debug),
|
||||
];
|
||||
MARKERS
|
||||
.iter()
|
||||
.find(|(marker, _)| line.starts_with(marker))
|
||||
.map(|(_, level)| *level)
|
||||
}
|
||||
Reference in new issue
Block a user