Ignoring IOExceptions in log4j handler

This commit is contained in:
huangyuhui 2018-02-08 00:04:02 +08:00
parent 98b43945ed
commit 6823291eb0
5 changed files with 60 additions and 33 deletions

View File

@ -40,6 +40,7 @@ import org.jackhuang.hmcl.util.*;
import java.io.*;
import java.util.*;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.atomic.AtomicInteger;
public final class LauncherHelper {
@ -282,6 +283,7 @@ public final class LauncherHelper {
private boolean lwjgl;
private LogWindow logWindow;
private final LinkedList<Pair<String, Log4jLevel>> logs;
private final CountDownLatch latch = new CountDownLatch(1);
public HMCLProcessListener(AuthInfo authInfo, VersionSetting setting) {
this.setting = setting;
@ -307,11 +309,12 @@ public final class LauncherHelper {
Platform.runLater(() -> {
logWindow = new LogWindow();
logWindow.show();
latch.countDown();
});
}
@Override
public void onLog(String log, Log4jLevel level) {
public synchronized void onLog(String log, Log4jLevel level) {
String newLog = log;
for (Map.Entry<String, String> entry : forbiddenTokens.entrySet())
newLog = newLog.replace(entry.getKey(), entry.getValue());
@ -321,13 +324,19 @@ public final class LauncherHelper {
else
System.out.print(log);
Platform.runLater(() -> {
logs.add(new Pair<>(log, level));
if (logs.size() > Settings.INSTANCE.getLogLines())
logs.removeFirst();
if (logWindow != null)
logWindow.logLine(log, level);
});
logs.add(new Pair<>(log, level));
if (logs.size() > Settings.INSTANCE.getLogLines())
logs.removeFirst();
if (setting.isShowLogs()) {
Lang.invoke(() -> {
latch.await();
logWindow.waitForLoaded();
});
Platform.runLater(() -> logWindow.logLine(log, level));
}
if (!lwjgl && log.contains("LWJGL Version: ")) {
lwjgl = true;

View File

@ -116,9 +116,9 @@ public final class LogWindow extends Stage {
}
public void logLine(String line, Log4jLevel level) {
Element div = impl.engine.getDocument().createElement("div");
Element div = impl.document.createElement("div");
// a <pre> element to prevent multiple spaces and tabs being removed.
Element pre = impl.engine.getDocument().createElement("pre");
Element pre = impl.document.createElement("pre");
pre.setTextContent(line);
div.appendChild(pre);
impl.body.appendChild(div);
@ -143,6 +143,10 @@ public final class LogWindow extends Stage {
}
}
public void waitForLoaded() throws InterruptedException {
latch.await();
}
public class LogWindowImpl extends StackPane {
@FXML

View File

@ -36,6 +36,7 @@ public class CrashReporter implements Thread.UncaughtExceptionHandler {
private static final HashMap<String, String> SOURCE = new HashMap<String, String>() {
{
put("javafx.fxml.LoadException", Main.i18n("crash.NoClassDefFound"));
put("UnsatisfiedLinkError", Main.i18n("crash.user_fault"));
put("java.lang.NoClassDefFoundError", Main.i18n("crash.NoClassDefFound"));
put("java.lang.VerifyError", Main.i18n("crash.NoClassDefFound"));
@ -68,10 +69,14 @@ public class CrashReporter implements Thread.UncaughtExceptionHandler {
@Override
public void uncaughtException(Thread t, Throwable e) {
String s = StringUtils.getStackTrace(e);
if (!s.contains("org.jackhuang"))
String stackTrace = StringUtils.getStackTrace(e);
if (!stackTrace.contains("org.jackhuang"))
return;
if (THROWABLE_SET.contains(stackTrace))
return;
THROWABLE_SET.add(stackTrace);
try {
StringBuilder builder = new StringBuilder();
builder.append("---- Hello Minecraft! Crash Report ----\n");
@ -79,7 +84,7 @@ public class CrashReporter implements Thread.UncaughtExceptionHandler {
builder.append(" Time: ").append(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date())).append("\n");
builder.append(" Thread: ").append(t.toString()).append("\n");
builder.append("\n Content: \n ");
builder.append(s).append("\n\n");
builder.append(stackTrace).append("\n\n");
builder.append("-- System Details --\n");
builder.append(" Operating System: ").append(System.getProperty("os.name")).append(' ').append(OperatingSystem.SYSTEM_VERSION).append("\n");
builder.append(" Java Version: ").append(System.getProperty("java.version")).append(", ").append(System.getProperty("java.vendor")).append("\n");
@ -91,7 +96,7 @@ public class CrashReporter implements Thread.UncaughtExceptionHandler {
if (checkThrowable(e) && !text.contains("OpenJDK")) {
Platform.runLater(() -> new CrashWindow(text).show());
if (!Main.UPDATE_CHECKER.isOutOfDate())
reportToServer(text, s);
reportToServer(text);
}
} catch (Throwable ex) {
Logging.LOG.log(Level.SEVERE, "Unable to caught exception", ex);
@ -101,10 +106,7 @@ public class CrashReporter implements Thread.UncaughtExceptionHandler {
private static final HashSet<String> THROWABLE_SET = new HashSet<>();
private void reportToServer(final String text, String stacktrace) {
if (THROWABLE_SET.contains(stacktrace) || stacktrace.contains("Font") || stacktrace.contains("InternalError"))
return;
THROWABLE_SET.add(stacktrace);
private void reportToServer(final String text) {
Thread t = new Thread(() -> {
HashMap<String, String> map = new HashMap<>();
map.put("crash_report", text);

View File

@ -18,10 +18,7 @@
package org.jackhuang.hmcl.launch;
import org.jackhuang.hmcl.task.Schedulers;
import org.jackhuang.hmcl.util.Constants;
import org.jackhuang.hmcl.util.Lang;
import org.jackhuang.hmcl.util.Log4jLevel;
import org.jackhuang.hmcl.util.OperatingSystem;
import org.jackhuang.hmcl.util.*;
import org.xml.sax.Attributes;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
@ -34,10 +31,15 @@ import java.io.InterruptedIOException;
import java.io.PipedInputStream;
import java.io.PipedOutputStream;
import java.util.Date;
import java.util.LinkedList;
import java.util.List;
import java.util.Optional;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.function.BiConsumer;
import java.util.logging.Level;
import java.util.stream.Collectors;
/**
* This class is to parse log4j classic XML layout logging,
@ -54,6 +56,7 @@ final class Log4jHandler extends Thread {
private final PipedOutputStream outputStream = new PipedOutputStream();
private final PipedInputStream inputStream = Lang.invoke(() -> new PipedInputStream(outputStream));
private final AtomicBoolean interrupted = new AtomicBoolean(false);
private final List<String> logs = new LinkedList<>();
public Log4jHandler(BiConsumer<String, Log4jLevel> callback) {
this.callback = callback;
@ -73,7 +76,7 @@ final class Log4jHandler extends Thread {
// Game has been interrupted.
interrupted.set(true);
} catch (SAXException | IOException e) {
Lang.throwable(e);
Logging.LOG.log(Level.WARNING, "An error occurred when reading console lines", e);
}
}
@ -83,7 +86,7 @@ final class Log4jHandler extends Thread {
Lang.invoke(() -> Schedulers.newThread().schedule(() -> {
if (!interrupted.get()) {
Lang.invoke(() -> newLine("</output>").get());
newLine("</output>").get();
outputStream.close();
join();
}
@ -92,13 +95,22 @@ final class Log4jHandler extends Thread {
public Future<?> newLine(String log) {
return Schedulers.computation().schedule(() -> {
byte[] bytes = (log + OperatingSystem.LINE_SEPARATOR)
.replace("log4j:Event", "log4j_Event")
.replace("log4j:Message", "log4j_Message")
.replace("log4j:Throwable", "log4j_Throwable")
.getBytes();
outputStream.write(bytes);
outputStream.flush();
try {
String line = (log + OperatingSystem.LINE_SEPARATOR)
.replace("<![CDATA[", "")
.replace("]]>", "")
.replace("log4j:Event", "log4j_Event")
.replace("<log4j:Message>", "<log4j_Message><![CDATA[")
.replace("</log4j:Message>", "]]></log4j_Message>")
.replace("log4j:Throwable", "log4j_Throwable");
logs.add(line);
byte[] bytes = line.getBytes(Charsets.UTF_8);
outputStream.write(bytes);
outputStream.flush();
} catch (IOException e) {
// Ignoring IOException, including read end dead.
Logging.LOG.log(Level.WARNING, "An error occurred when writing console lines", e);
}
});
}

View File

@ -60,7 +60,7 @@ public final class Lang {
return function.apply(t);
} catch (Exception e) {
throwable(e);
return null; // won't get to here.
throw new Error(); // won't get to here.
}
}
@ -88,7 +88,7 @@ public final class Lang {
return supplier.get();
} catch (Exception e) {
throwable(e);
return null; // won't get to here.
throw new Error(); // won't get to here.
}
}