Skip to content
Open
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -929,7 +929,9 @@ public void onLog(String log, boolean isErrorStream) {
if (forbiddenAccessToken != null)
log = log.replace(forbiddenAccessToken, "<access token>");

Log4jLevel level = isErrorStream && !log.startsWith("[authlib-injector]") ? Log4jLevel.ERROR : null;
Log4jLevel level = log.startsWith("[authlib-injector]")
? Log4jLevel.guessLevel(log)
: Log4jLevel.guessLevel(log, isErrorStream);
if (showLogs) {
if (level == null)
level = Lang.requireNonNullElse(Log4jLevel.guessLevel(log), Log4jLevel.INFO);
Comment thread
Wulian233 marked this conversation as resolved.
Comment thread
Wulian233 marked this conversation as resolved.
Expand Down
95 changes: 45 additions & 50 deletions HMCLCore/src/main/java/org/jackhuang/hmcl/util/Log4jLevel.java
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@

import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.logging.Level;

/**
*
Expand Down Expand Up @@ -50,60 +51,33 @@ public boolean lessOrEqual(Log4jLevel level) {
public static final Pattern MINECRAFT_LOGGER = Pattern.compile("\\[(?<timestamp>[0-9:]+)] \\[[^/]+/(?<level>[^]]+)]");
public static final Pattern MINECRAFT_LOGGER_CATEGORY = Pattern.compile("\\[(?<timestamp>[0-9:]+)] \\[[^/]+/(?<level>[^]]+)] \\[(?<category>[^]]+)]");
public static final String JAVA_SYMBOL = "([a-zA-Z_$][a-zA-Z\\d_$]*\\.)+[a-zA-Z_$][a-zA-Z\\d_$]*";
private static final String WRAPPED_PRINT_STREAM = "[java.lang.Throwable$WrappedPrintStream:println";

public static Log4jLevel guessLevel(String line) {
Log4jLevel level = null;
Matcher m = MINECRAFT_LOGGER.matcher(line);
if (m.find()) {
// New style logs from log4j
String levelStr = m.group("level");
if (null != levelStr)
switch (levelStr) {
case "INFO":
level = INFO;
break;
case "WARN":
level = WARN;
break;
case "ERROR":
level = ERROR;
break;
case "FATAL":
level = FATAL;
break;
case "TRACE":
level = TRACE;
break;
case "DEBUG":
level = DEBUG;
break;
default:
break;
}
level = parseLevel(m.group("level"));
Matcher m2 = MINECRAFT_LOGGER_CATEGORY.matcher(line);
if (m2.find()) {
String level2Str = m2.group("category");
if (null != level2Str)
switch (level2Str) {
case "STDOUT":
level = INFO;
break;
case "STDERR":
level = ERROR;
break;
}
}

if (line.contains("STDERR]") || line.contains("[STDERR/]")) {
level = ERROR;
level = switch (level2Str) {
case "STDOUT" -> INFO;
case "STDERR" -> guessStderrLevel(line, level);
default -> level;
};
} else if (line.contains("STDERR]") || line.contains("[STDERR/]")) {
level = guessStderrLevel(line, level);
}
} else {
if (line.contains("[INFO]") || line.contains("[CONFIG]") || line.contains("[FINE]")
|| line.contains("[FINER]") || line.contains("[FINEST]"))
if (containsLevelMarker(line, Level.INFO) || containsLevelMarker(line, Level.CONFIG)
|| containsLevelMarker(line, Level.FINE) || containsLevelMarker(line, Level.FINER)
|| containsLevelMarker(line, Level.FINEST))
level = INFO;
if (line.contains("[SEVERE]") || line.contains("[STDERR]"))
if (containsLevelMarker(line, Level.SEVERE))
level = ERROR;
if (line.contains("[WARNING]"))
if (containsLevelMarker(line, Level.WARNING))
level = WARN;
if (line.contains("[DEBUG]"))
level = DEBUG;
Expand All @@ -120,17 +94,38 @@ public static Log4jLevel guessLevel(String line) {
return level;
}

public static boolean isError(Log4jLevel a) {
return a != null && a.lessOrEqual(Log4jLevel.ERROR);
public static Log4jLevel guessLevel(String line, boolean isErrorStream) {
Log4jLevel level = guessLevel(line);
return level != null || !isErrorStream ? level : ERROR;
Comment on lines +112 to +114

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Declare nullable results in the new classifier API

This overload returns null whenever an unrecognized stdout line is supplied, but its return type and nullable local are unannotated; the added parseLevel return and guessStderrLevel fallback similarly have nullable contracts. Add @NotNullByDefault to the enum and explicitly annotate every nullable declaration so callers and nullability tooling receive the actual contract.

AGENTS.md reference: AGENTS.md:L7-L9

Useful? React with 👍 / 👎.

}

private static Log4jLevel parseLevel(String level) {
Comment thread
Wulian233 marked this conversation as resolved.
return switch (level) {
case "FATAL" -> FATAL;
case "ERROR" -> ERROR;
case "WARN" -> WARN;
case "INFO" -> INFO;
case "DEBUG" -> DEBUG;
case "TRACE" -> TRACE;
case "ALL" -> ALL;
default -> null;
};
}

public static Log4jLevel mergeLevel(Log4jLevel a, Log4jLevel b) {
if (a == null)
return b;
else if (b == null)
return a;
else
return a.level < b.level ? a : b;
private static Log4jLevel guessStderrLevel(String line, Log4jLevel fallback) {
if (line.contains(WRAPPED_PRINT_STREAM) && fallback != null) {
return fallback;
}
return ERROR;
}

private static boolean containsLevelMarker(String line, Level level) {
return line.contains("[" + level.getName() + "]")
Comment thread
Wulian233 marked this conversation as resolved.
Outdated
|| line.contains("[" + level.getLocalizedName() + "]");
}

public static boolean isError(Log4jLevel a) {
return a != null && a.lessOrEqual(Log4jLevel.ERROR);
}

public static boolean guessLogLineError(String log) {
Expand Down