Better shared crash handling
This commit is contained in:
@@ -1,91 +0,0 @@
|
||||
package io.anuke.mindustry.server;
|
||||
|
||||
import io.anuke.arc.Core;
|
||||
import io.anuke.arc.util.Log;
|
||||
import io.anuke.arc.util.OS;
|
||||
import io.anuke.arc.util.serialization.JsonValue;
|
||||
import io.anuke.arc.util.serialization.JsonValue.ValueType;
|
||||
import io.anuke.arc.util.serialization.JsonWriter.OutputType;
|
||||
import io.anuke.mindustry.Vars;
|
||||
import io.anuke.mindustry.game.Version;
|
||||
import io.anuke.mindustry.net.Net;
|
||||
|
||||
import java.io.PrintWriter;
|
||||
import java.io.StringWriter;
|
||||
import java.nio.file.*;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
|
||||
public class CrashHandler{
|
||||
|
||||
public static void handle(Throwable e){
|
||||
e.printStackTrace();
|
||||
|
||||
//don't create crash logs for me (anuke), as it's expected
|
||||
//also don't create logs for custom builds
|
||||
if(System.getProperty("user.name").equals("anuke") || Version.build == -1) return;
|
||||
|
||||
//if getting the crash report property failed, OR if it set to false... don't send it
|
||||
try{
|
||||
if(!Core.settings.getBool("crashreport")) return;
|
||||
}catch(Throwable ignored){
|
||||
return;
|
||||
}
|
||||
|
||||
//attempt to close connections, if applicable
|
||||
try{
|
||||
Net.dispose();
|
||||
}catch(Throwable p){
|
||||
p.printStackTrace();
|
||||
}
|
||||
|
||||
JsonValue value = new JsonValue(ValueType.object);
|
||||
|
||||
//add all relevant info, ignoring exceptions
|
||||
ex(() -> value.addChild("versionType", new JsonValue(Version.type)));
|
||||
ex(() -> value.addChild("versionNumber", new JsonValue(Version.number)));
|
||||
ex(() -> value.addChild("versionModifier", new JsonValue(Version.modifier)));
|
||||
ex(() -> value.addChild("build", new JsonValue(Version.build)));
|
||||
ex(() -> value.addChild("state", new JsonValue(Vars.state.getState().name())));
|
||||
ex(() -> value.addChild("players", new JsonValue(Vars.playerGroup.size())));
|
||||
ex(() -> value.addChild("os", new JsonValue(System.getProperty("os.name"))));
|
||||
ex(() -> value.addChild("trace", new JsonValue(parseException(e))));
|
||||
|
||||
try{
|
||||
Path path = Paths.get(OS.getAppDataDirectoryString(Vars.appName), "crashes",
|
||||
"crash-report-" + DateTimeFormatter.ofPattern("MM-dd-yyyy-HH:mm:ss").format(LocalDateTime.now()) + ".txt");
|
||||
Files.createDirectories(Paths.get(OS.getAppDataDirectoryString(Vars.appName), "crashes"));
|
||||
Files.write(path, parseException(e).getBytes());
|
||||
|
||||
Log.info("Saved crash report at {0}", path.toAbsolutePath().toString());
|
||||
}catch(Throwable t){
|
||||
Log.err("Failure saving crash report: ");
|
||||
t.printStackTrace();
|
||||
}
|
||||
|
||||
Log.info("&lcSending crash report.");
|
||||
//post to crash report URL
|
||||
Net.http(Vars.crashReportURL, "POST", value.toJson(OutputType.json), r -> System.exit(1), t -> System.exit(1));
|
||||
|
||||
//sleep forever
|
||||
try{
|
||||
Thread.sleep(Long.MAX_VALUE);
|
||||
}catch(InterruptedException ignored){
|
||||
}
|
||||
}
|
||||
|
||||
private static String parseException(Throwable e){
|
||||
StringWriter sw = new StringWriter();
|
||||
PrintWriter pw = new PrintWriter(sw);
|
||||
e.printStackTrace(pw);
|
||||
return sw.toString();
|
||||
}
|
||||
|
||||
private static void ex(Runnable r){
|
||||
try{
|
||||
r.run();
|
||||
}catch(Throwable t){
|
||||
t.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -4,6 +4,7 @@ package io.anuke.mindustry.server;
|
||||
import io.anuke.arc.ApplicationListener;
|
||||
import io.anuke.arc.backends.headless.HeadlessApplication;
|
||||
import io.anuke.arc.backends.headless.HeadlessApplicationConfiguration;
|
||||
import io.anuke.mindustry.net.CrashSender;
|
||||
import io.anuke.mindustry.net.Net;
|
||||
import io.anuke.mindustry.net.ArcNetClient;
|
||||
import io.anuke.mindustry.net.ArcNetServer;
|
||||
@@ -23,21 +24,13 @@ public class ServerLauncher extends HeadlessApplication{
|
||||
HeadlessApplicationConfiguration config = new HeadlessApplicationConfiguration();
|
||||
new ServerLauncher(new MindustryServer(args), config);
|
||||
}catch(Throwable t){
|
||||
CrashHandler.handle(t);
|
||||
CrashSender.send(t, f -> {});
|
||||
}
|
||||
|
||||
//find and handle uncaught exceptions in libGDX thread
|
||||
for(Thread thread : Thread.getAllStackTraces().keySet()){
|
||||
if(thread.getName().equals("HeadlessApplication")){
|
||||
thread.setUncaughtExceptionHandler((t, throwable) -> {
|
||||
try{
|
||||
CrashHandler.handle(throwable);
|
||||
System.exit(-1);
|
||||
}catch(Throwable crashCrash){
|
||||
crashCrash.printStackTrace();
|
||||
System.exit(-1);
|
||||
}
|
||||
});
|
||||
thread.setUncaughtExceptionHandler((t, throwable) -> CrashSender.send(throwable, f -> {}));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user