More crash report tweaks. Put a button to open the generated crash report on the error screen, tweak formatting of crash report, and add the enhanced stack trace data (transformers et al)

Signed-off-by: cpw <cpw+github@weeksfamily.ca>
This commit is contained in:
cpw 2020-09-08 20:05:45 -04:00
parent 15733a18e4
commit 43391c009c
No known key found for this signature in database
GPG key ID: 8EB3DF749553B1B7
5 changed files with 60 additions and 12 deletions

View file

@ -8,7 +8,24 @@
} }
public String func_71501_a() { public String func_71501_a() {
@@ -121,23 +122,13 @@ @@ -87,14 +88,8 @@
if (this.field_85060_g != null && this.field_85060_g.length > 0) {
p_71506_1_.append("-- Head --\n");
p_71506_1_.append("Thread: ").append(Thread.currentThread().getName()).append("\n");
- p_71506_1_.append("Stacktrace:\n");
-
- for(StackTraceElement stacktraceelement : this.field_85060_g) {
- p_71506_1_.append("\t").append("at ").append((Object)stacktraceelement);
- p_71506_1_.append("\n");
- }
-
- p_71506_1_.append("\n");
+ p_71506_1_.append("Stacktrace:");
+ p_71506_1_.append(net.minecraftforge.fml.CrashReportExtender.generateEnhancedStackTrace(this.field_85060_g));
}
for(CrashReportCategory crashreportcategory : this.field_71512_c) {
@@ -121,23 +116,13 @@
throwable.setStackTrace(this.field_71511_b.getStackTrace()); throwable.setStackTrace(this.field_71511_b.getStackTrace());
} }

View file

@ -13,7 +13,20 @@
return this.field_85075_d.length; return this.field_85075_d.length;
} }
} }
@@ -158,6 +160,10 @@ @@ -145,11 +147,7 @@
if (this.field_85075_d != null && this.field_85075_d.length > 0) {
p_85072_1_.append("\nStacktrace:");
-
- for(StackTraceElement stacktraceelement : this.field_85075_d) {
- p_85072_1_.append("\n\tat ");
- p_85072_1_.append((Object)stacktraceelement);
- }
+ p_85072_1_.append(net.minecraftforge.fml.CrashReportExtender.generateEnhancedStackTrace(this.field_85075_d));
}
}
@@ -158,6 +156,10 @@
return this.field_85075_d; return this.field_85075_d;
} }

View file

@ -20,6 +20,7 @@
package net.minecraftforge.fml; package net.minecraftforge.fml;
import cpw.mods.modlauncher.log.TransformingThrowablePatternConverter; import cpw.mods.modlauncher.log.TransformingThrowablePatternConverter;
import joptsimple.internal.Strings;
import net.minecraft.crash.CrashReport; import net.minecraft.crash.CrashReport;
import net.minecraft.crash.CrashReportCategory; import net.minecraft.crash.CrashReportCategory;
import net.minecraftforge.fml.common.ICrashCallable; import net.minecraftforge.fml.common.ICrashCallable;
@ -67,13 +68,23 @@ public class CrashReportExtender
public static void addCrashReportHeader(StringBuilder stringbuilder, CrashReport crashReport) public static void addCrashReportHeader(StringBuilder stringbuilder, CrashReport crashReport)
{ {
} }
public static String generateEnhancedStackTrace(final Throwable throwable) { public static String generateEnhancedStackTrace(final Throwable throwable) {
return TransformingThrowablePatternConverter.generateEnhancedStackTrace(throwable); return generateEnhancedStackTrace(throwable, true);
}
public static String generateEnhancedStackTrace(final StackTraceElement[] stacktrace) {
final Throwable t = new Throwable();
t.setStackTrace(stacktrace);
return generateEnhancedStackTrace(t, false);
}
public static String generateEnhancedStackTrace(final Throwable throwable, boolean header) {
final String s = TransformingThrowablePatternConverter.generateEnhancedStackTrace(throwable);
return header ? s : s.substring(s.indexOf(Strings.LINE_SEPARATOR));
} }
public static void dumpModLoadingCrashReport(final Logger logger, final LoadingFailedException error, final File topLevelDir) { public static File dumpModLoadingCrashReport(final Logger logger, final LoadingFailedException error, final File topLevelDir) {
final CrashReport crashReport = CrashReport.makeCrashReport(new Exception("Mod Loading has failed"), "Mod loading error has occurred"); final CrashReport crashReport = CrashReport.makeCrashReport(new Exception("Mod Loading has failed"), "Mod loading error has occurred");
error.getErrors().forEach(mle -> { error.getErrors().forEach(mle -> {
final Optional<IModInfo> modInfo = Optional.ofNullable(mle.getModInfo()); final Optional<IModInfo> modInfo = Optional.ofNullable(mle.getModInfo());
@ -81,16 +92,16 @@ public class CrashReportExtender
Throwable cause = mle.getCause(); Throwable cause = mle.getCause();
int depth = 0; int depth = 0;
while (cause != null && cause.getCause() != null && cause.getCause()!=cause) { while (cause != null && cause.getCause() != null && cause.getCause()!=cause) {
category.addDetail("Caused by "+(depth++), cause +"\n\t\t"+ Arrays.stream(cause.getStackTrace()).map(Objects::toString).collect(Collectors.joining("\n\t\t"))); category.addDetail("Caused by "+(depth++), cause + generateEnhancedStackTrace(cause.getStackTrace()).replaceAll(Strings.LINE_SEPARATOR+"\t", "\n\t\t"));
cause = cause.getCause(); cause = cause.getCause();
} }
if (cause != null) if (cause != null)
category.applyStackTrace(cause); category.applyStackTrace(cause);
category.addDetail("Mod File", () -> modInfo.map(IModInfo::getOwningFile).map(t->((ModFileInfo)t).getFile().getFileName()).orElse("NO FILE INFO")); category.addDetail("Mod File", () -> modInfo.map(IModInfo::getOwningFile).map(t->((ModFileInfo)t).getFile().getFileName()).orElse("NO FILE INFO"));
category.addDetail("Failure message", () -> mle.getCleanMessage().replace("\n", "\n\t\t")); category.addDetail("Failure message", () -> mle.getCleanMessage().replace("\n", "\n\t\t"));
category.addDetail("Exception message", Objects.toString(cause, "MISSING EXCEPTION MESSAGE"));
category.addDetail("Mod Version", () -> modInfo.map(IModInfo::getVersion).map(Object::toString).orElse("NO MOD INFO AVAILABLE")); category.addDetail("Mod Version", () -> modInfo.map(IModInfo::getVersion).map(Object::toString).orElse("NO MOD INFO AVAILABLE"));
category.addDetail("Mod Issue URL", () -> modInfo.map(IModInfo::getOwningFile).map(ModFileInfo.class::cast).flatMap(mfi->mfi.getConfigElement("issueTrackerURL")).orElse("NOT PROVIDED").toString()); category.addDetail("Mod Issue URL", () -> modInfo.map(IModInfo::getOwningFile).map(ModFileInfo.class::cast).flatMap(mfi->mfi.<String>getConfigElement("issueTrackerURL")).orElse("NOT PROVIDED"));
category.addDetail("Exception message", Objects.toString(cause, "MISSING EXCEPTION MESSAGE"));
}); });
final File file1 = new File(topLevelDir, "crash-reports"); final File file1 = new File(topLevelDir, "crash-reports");
final File file2 = new File(file1, "crash-" + (new SimpleDateFormat("yyyy-MM-dd_HH.mm.ss")).format(new Date()) + "-fml.txt"); final File file2 = new File(file1, "crash-" + (new SimpleDateFormat("yyyy-MM-dd_HH.mm.ss")).format(new Date()) + "-fml.txt");
@ -100,5 +111,6 @@ public class CrashReportExtender
logger.fatal("Failed to save crash report"); logger.fatal("Failed to save crash report");
} }
System.out.print(crashReport.getCompleteReport()); System.out.print(crashReport.getCompleteReport());
return file2;
} }
} }

View file

@ -182,16 +182,17 @@ public class ClientModLoader
} }
warnings = Collections.emptyList(); //Clear warnings, as the user does not want to see them warnings = Collections.emptyList(); //Clear warnings, as the user does not want to see them
} }
File dumpedLocation = null;
if (error == null) { if (error == null) {
// We can finally start the forge eventbus up // We can finally start the forge eventbus up
MinecraftForge.EVENT_BUS.start(); MinecraftForge.EVENT_BUS.start();
} else { } else {
// Double check we have the langs loaded for forge // Double check we have the langs loaded for forge
LanguageHook.loadForgeAndMCLangs(); LanguageHook.loadForgeAndMCLangs();
CrashReportExtender.dumpModLoadingCrashReport(LOGGER, error, mc.gameDir); dumpedLocation = CrashReportExtender.dumpModLoadingCrashReport(LOGGER, error, mc.gameDir);
} }
if (error != null || !warnings.isEmpty()) { if (error != null || !warnings.isEmpty()) {
mc.displayGuiScreen(new LoadingErrorScreen(error, warnings)); mc.displayGuiScreen(new LoadingErrorScreen(error, warnings, dumpedLocation));
return true; return true;
} else { } else {
ClientHooks.logMissingTextureErrors(); ClientHooks.logMissingTextureErrors();

View file

@ -41,6 +41,7 @@ import net.minecraftforge.fml.loading.FMLPaths;
import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.Logger;
import java.io.File;
import java.nio.file.Path; import java.nio.file.Path;
import java.nio.file.Paths; import java.nio.file.Paths;
import java.util.Collections; import java.util.Collections;
@ -53,17 +54,19 @@ public class LoadingErrorScreen extends ErrorScreen {
private final Path logFile; private final Path logFile;
private final List<ModLoadingException> modLoadErrors; private final List<ModLoadingException> modLoadErrors;
private final List<ModLoadingWarning> modLoadWarnings; private final List<ModLoadingWarning> modLoadWarnings;
private final Path dumpedLocation;
private LoadingEntryList entryList; private LoadingEntryList entryList;
private ITextComponent errorHeader; private ITextComponent errorHeader;
private ITextComponent warningHeader; private ITextComponent warningHeader;
public LoadingErrorScreen(LoadingFailedException loadingException, List<ModLoadingWarning> warnings) public LoadingErrorScreen(LoadingFailedException loadingException, List<ModLoadingWarning> warnings, final File dumpedLocation)
{ {
super(new StringTextComponent("Loading Error"), null); super(new StringTextComponent("Loading Error"), null);
this.modLoadWarnings = warnings; this.modLoadWarnings = warnings;
this.modLoadErrors = loadingException == null ? Collections.emptyList() : loadingException.getErrors(); this.modLoadErrors = loadingException == null ? Collections.emptyList() : loadingException.getErrors();
this.modsDir = FMLPaths.MODSDIR.get(); this.modsDir = FMLPaths.MODSDIR.get();
this.logFile = FMLPaths.GAMEDIR.get().resolve(Paths.get("logs","latest.log")); this.logFile = FMLPaths.GAMEDIR.get().resolve(Paths.get("logs","latest.log"));
this.dumpedLocation = dumpedLocation.toPath();
} }
@Override @Override
@ -76,7 +79,7 @@ public class LoadingErrorScreen extends ErrorScreen {
this.errorHeader = new StringTextComponent(TextFormatting.RED + ForgeI18n.parseMessage("fml.loadingerrorscreen.errorheader", this.modLoadErrors.size()) + TextFormatting.RESET); this.errorHeader = new StringTextComponent(TextFormatting.RED + ForgeI18n.parseMessage("fml.loadingerrorscreen.errorheader", this.modLoadErrors.size()) + TextFormatting.RESET);
this.warningHeader = new StringTextComponent(TextFormatting.YELLOW + ForgeI18n.parseMessage("fml.loadingerrorscreen.warningheader", this.modLoadErrors.size()) + TextFormatting.RESET); this.warningHeader = new StringTextComponent(TextFormatting.YELLOW + ForgeI18n.parseMessage("fml.loadingerrorscreen.warningheader", this.modLoadErrors.size()) + TextFormatting.RESET);
int yOffset = this.modLoadErrors.isEmpty() ? 46 : 38; int yOffset = 46;
this.func_230480_a_(new ExtendedButton(50, this.field_230709_l_ - yOffset, this.field_230708_k_ / 2 - 55, 20, new StringTextComponent(ForgeI18n.parseMessage("fml.button.open.mods.folder")), b -> Util.getOSType().openFile(modsDir.toFile()))); this.func_230480_a_(new ExtendedButton(50, this.field_230709_l_ - yOffset, this.field_230708_k_ / 2 - 55, 20, new StringTextComponent(ForgeI18n.parseMessage("fml.button.open.mods.folder")), b -> Util.getOSType().openFile(modsDir.toFile())));
this.func_230480_a_(new ExtendedButton(this.field_230708_k_ / 2 + 5, this.field_230709_l_ - yOffset, this.field_230708_k_ / 2 - 55, 20, new StringTextComponent(ForgeI18n.parseMessage("fml.button.open.file", logFile.getFileName())), b -> Util.getOSType().openFile(logFile.toFile()))); this.func_230480_a_(new ExtendedButton(this.field_230708_k_ / 2 + 5, this.field_230709_l_ - yOffset, this.field_230708_k_ / 2 - 55, 20, new StringTextComponent(ForgeI18n.parseMessage("fml.button.open.file", logFile.getFileName())), b -> Util.getOSType().openFile(logFile.toFile())));
if (this.modLoadErrors.isEmpty()) { if (this.modLoadErrors.isEmpty()) {
@ -84,6 +87,8 @@ public class LoadingErrorScreen extends ErrorScreen {
ClientHooks.logMissingTextureErrors(); ClientHooks.logMissingTextureErrors();
this.field_230706_i_.displayGuiScreen(null); this.field_230706_i_.displayGuiScreen(null);
})); }));
} else {
this.func_230480_a_(new ExtendedButton(this.field_230708_k_ / 4, this.field_230709_l_ - 24, this.field_230708_k_ / 2, 20, new StringTextComponent(ForgeI18n.parseMessage("fml.button.open.file", dumpedLocation.getFileName())), b -> Util.getOSType().openFile(dumpedLocation.toFile())));
} }
this.entryList = new LoadingEntryList(this, this.modLoadErrors, this.modLoadWarnings); this.entryList = new LoadingEntryList(this, this.modLoadErrors, this.modLoadWarnings);