feat: crash report analyzer more rules.

This commit is contained in:
huanghongxun
2021-09-21 06:43:52 +08:00
parent 798327eabb
commit ebeec04f83
21 changed files with 2784 additions and 52 deletions

View File

@@ -1,10 +1,12 @@
package org.jackhuang.hmcl.game;
import org.jackhuang.hmcl.util.Log4jLevel;
import org.jackhuang.hmcl.util.Pair;
import org.jackhuang.hmcl.util.io.FileUtils;
import org.jetbrains.annotations.Nullable;
import java.util.ArrayList;
import java.util.List;
import java.io.IOException;
import java.nio.file.InvalidPathException;
import java.nio.file.Paths;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
@@ -21,11 +23,13 @@ public class CrashReportAnalyzer {
// Maybe software rendering? Suggest user for using a graphics card.
OPENGL_NOT_SUPPORTED(Pattern.compile("The driver does not appear to support OpenGL")),
GRAPHICS_DRIVER(Pattern.compile("(Pixel format not accelerated|Couldn't set pixel format|net\\.minecraftforge\\.fml.client\\.SplashProgress|org\\.lwjgl\\.LWJGLException)")),
GRAPHICS_DRIVER(Pattern.compile("(Pixel format not accelerated|Couldn't set pixel format|net\\.minecraftforge\\.fml.client\\.SplashProgress|org\\.lwjgl\\.LWJGLException|EXCEPTION_ACCESS_VIOLATION(.|\\n|\\r)+# C {2}\\[(ig|atio|nvoglv))")),
// Out of memory
OUT_OF_MEMORY(Pattern.compile("java\\.lang\\.OutOfMemoryError")),
OUT_OF_MEMORY(Pattern.compile("(java\\.lang\\.OutOfMemoryError|The system is out of physical RAM or swap space)")),
// Too high resolution
RESOLUTION_TOO_HIGH(Pattern.compile("Maybe try a (lower resolution|lowerresolution) (resourcepack|texturepack)\\?")),
// game can only run on Java 8. Version of uesr's JVM is too high.
JDK_9(Pattern.compile("java\\.lang\\.ClassCastException: java\\.base/jdk")),
JDK_9(Pattern.compile("java\\.lang\\.ClassCastException: (java\\.base/jdk|class jdk)")),
// user modifies minecraft primary jar without changing hash file
FILE_CHANGED(Pattern.compile("java\\.lang\\.SecurityException: SHA1 digest error for (?<file>.*)"), "file"),
// mod loader/coremod injection fault, prompt user to reinstall game.
@@ -35,12 +39,24 @@ public class CrashReportAnalyzer {
// coremod wants to access class without "setAccessible"
ILLEGAL_ACCESS_ERROR(Pattern.compile("java\\.lang\\.IllegalAccessError: tried to access class (.*?) from class (?<class>.*?)"), "class"),
// Some mods duplicated
DUPLICATED_MOD(Pattern.compile("DuplicateModsFoundException")),
MOD_RESOLUTION(Pattern.compile("ModResolutionException: Duplicate")),
DUPLICATED_MOD(Pattern.compile("Found a duplicate mod (?<name>.*) at (?<path>.*)"), "name", "path"),
MOD_RESOLUTION(Pattern.compile("ModResolutionException: (?<reason>(.*)[\\n\\r]*( - (.*)[\\n\\r]*)+)"), "reason"),
// Some mods require a file not existing, asking user to manually delete it
FILE_ALREADY_EXISTS(Pattern.compile("java\\.nio\\.file\\.FileAlreadyExistsException: (?<file>.*)"), "file"),
// Forge found some mod crashed in game loading
LOADING_CRASHED(Pattern.compile("LoaderExceptionModCrash: Caught exception from (?<name>.*?) \\((?<id>.*)\\)"), "name", "id");
LOADING_CRASHED_FORGE(Pattern.compile("LoaderExceptionModCrash: Caught exception from (?<name>.*?) \\((?<id>.*)\\)"), "name", "id"),
BOOTSTRAP_FAILED(Pattern.compile("Failed to create mod instance. ModID: (?<id>.*?),"), "id"),
// Fabric found some mod crashed in game loading
LOADING_CRASHED_FABRIC(Pattern.compile("Could not execute entrypoint stage '(.*?)' due to errors, provided by '(?<id>.*)'!"), "id"),
// Manually triggerd debug crash
DEBUG_CRASH(Pattern.compile("Manually triggered debug crash")),
CONFIG(Pattern.compile("Failed loading config file (?<file>.*?) of type SERVER for modid (?<id>.*)"), "id", "file"),
// Fabric gives some warnings
FABRIC_WARNINGS(Pattern.compile("Warnings were found!(.*?)[\\n\\r]+(?<reason>[^\\[]+)\\["), "reason"),
// Game crashed when ticking entity
ENTITY(Pattern.compile("Entity Type: (?<type>.*)[\\w\\W\\n\\r]*?Entity's Exact location: (?<location>.*)"), "type", "location"),
// Game crashed when tesselating block model
BLOCK(Pattern.compile("Block: (?<type>.*)[\\w\\W\\n\\r]*?Block location: (?<location>.*)"), "type", "location");
private final Pattern pattern;
private final String[] groupNames;
@@ -83,19 +99,65 @@ public class CrashReportAnalyzer {
}
}
public static List<Result> anaylze(List<Pair<String, Log4jLevel>> logs) {
public static List<Result> anaylze(String log) {
List<Result> results = new ArrayList<>();
for (Pair<String, Log4jLevel> log : logs) {
for (Rule rule : Rule.values()) {
Matcher matcher = rule.pattern.matcher(log.getKey());
if (matcher.find()) {
results.add(new Result(rule, log.getKey(), matcher));
}
for (Rule rule : Rule.values()) {
Matcher matcher = rule.pattern.matcher(log);
if (matcher.find()) {
results.add(new Result(rule, log, matcher));
}
}
return results;
}
private static final Pattern CRASH_REPORT_LOCATION_PATTERN = Pattern.compile("#@!@# Game crashed! Crash report saved to: #@!@# (?<location>.*)");
@Nullable
public static String findCrashReport(String log) throws IOException, InvalidPathException {
Matcher matcher = CRASH_REPORT_LOCATION_PATTERN.matcher(log);
if (matcher.find()) {
return FileUtils.readText(Paths.get(matcher.group("location")));
} else {
return null;
}
}
private static final Pattern CRASH_REPORT_STACK_TRACE_PATTERN = Pattern.compile("Description: (.*?)[\\n\\r]+(?<stacktrace>[\\w\\W\\n\\r]+)A detailed walkthrough of the error");
private static final Pattern STACK_TRACE_LINE_PATTERN = Pattern.compile("at (?<method>.*?)\\((.*?)\\)");
private static final Set<String> PACKAGE_KEYWORD_BLACK_LIST = new HashSet<>(Arrays.asList(
"net", "minecraft", "item", "block", "player", "tileentity", "events", "common", "client", "entity", "mojang", "main", "gui", "world", "server", "dedicated", // minecraft
"renderer", "chunk", "model", "loading", "color", "pipeline", "inventory", "launcher", "physics", "particle", "gen", "registry", "worldgen", "texture", "biomes", "biome",
"monster", "passive", "ai", "integrated", "tile", "state", "play", "structure", "nbt", "pathfinding", "chunk", "audio", "entities", "items", "renderers",
"storage",
"java", "lang", "util", "nio", "io", "sun", "reflect", "zip", "jdk", "nashorn", "scripts", "runtime", "internal", // java
"mods", "mod", "impl", "org", "com", "cn", "cc", "jp", // title
"core", "config", "registries", "lib", "ruby", "mc", "codec", "channel", "embedded", "netty", "network", "handler", "feature", // misc
"file", "machine", "shader", "general", "helper", "init", "library", "api", "integration", "engine", "preload", "preinit",
"hellominecraft", "jackhuang", // hmcl
"fml", "minecraftforge", "forge", "cpw", "modlauncher", "launchwrapper", "objectweb", "asm", "event", "eventhandler", "handshake", "kcauldron", // forge
"fabricmc", "loader", "game", "knot", "launch", "mixin" // fabric
));
public static Set<String> findKeywordsFromCrashReport(String crashReport) throws IOException, InvalidPathException {
Matcher matcher = CRASH_REPORT_STACK_TRACE_PATTERN.matcher(crashReport);
Set<String> result = new HashSet<>();
if (matcher.find()) {
for (String line : matcher.group("stacktrace").split("\\n")) {
Matcher lineMatcher = STACK_TRACE_LINE_PATTERN.matcher(line);
if (lineMatcher.find()) {
String[] method = lineMatcher.group("method").split("\\.");
for (int i = 0; i < method.length - 2; i++) {
if (PACKAGE_KEYWORD_BLACK_LIST.contains(method[i])) {
continue;
}
result.add(method[i]);
}
}
}
}
return result;
}
public static final int getJavaVersionFromMajorVersion(int majorVersion) {
if (majorVersion >= 46) {
return majorVersion - 44;