From 74367360401a9e7fd5392527a23f80aac15b9bc8 Mon Sep 17 00:00:00 2001 From: huangyuhui Date: Sun, 26 Feb 2017 20:21:35 +0800 Subject: [PATCH] Modify logging system --- .../main/java/org/jackhuang/hmcl/Main.java | 10 +-- .../jackhuang/hmcl/ui/LaunchingUIDaemon.java | 37 +++++----- .../java/org/jackhuang/hmcl/ui/LogWindow.form | 6 +- .../java/org/jackhuang/hmcl/ui/LogWindow.java | 48 +++++-------- .../hmcl/ui/LogWindowOutputStream.java | 1 - .../hmcl/core/launch/GameLauncher.java | 2 +- .../org/jackhuang/hmcl/util/log/Level.java | 5 +- .../jackhuang/hmcl/util/sys/JavaProcess.java | 3 - .../hmcl/util/sys/ProcessMonitor.java | 67 +++++++++++-------- .../hmcl/util/sys/ProcessThread.java | 9 +-- 10 files changed, 83 insertions(+), 105 deletions(-) diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/Main.java b/HMCL/src/main/java/org/jackhuang/hmcl/Main.java index 61b0853b3..262918303 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/Main.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/Main.java @@ -53,13 +53,12 @@ import org.jackhuang.hmcl.util.log.layout.DefaultLayout; import org.jackhuang.hmcl.util.ui.MyRepaintManager; import org.jackhuang.hmcl.util.upgrade.IUpgrader; import org.jackhuang.hmcl.laf.BeautyEyeLNFHelper; -import org.jackhuang.hmcl.util.sys.JavaProcess; /** * * @author huangyuhui */ -public final class Main implements Runnable { +public final class Main { private static final X509TrustManager XTM = new X509TrustManager() { @Override @@ -192,7 +191,6 @@ public final class Main implements Runnable { } LogWindow.INSTANCE.clean(); - LogWindow.INSTANCE.setTerminateGame(new Main()::run); Settings.UPDATE_CHECKER.upgrade.register(IUpgrader.NOW_UPGRADER); Settings.UPDATE_CHECKER.process(false).reg(t -> Main.invokeUpdate()).execute(); @@ -214,12 +212,6 @@ public final class Main implements Runnable { } } - @Override - public void run() { - for (Process p : JavaProcess.processes) - p.destroy(); - } - public static void invokeUpdate() { MainFrame.INSTANCE.invokeUpdate(); } diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/LaunchingUIDaemon.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/LaunchingUIDaemon.java index 6f73d5d35..78ae7d26d 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/LaunchingUIDaemon.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/LaunchingUIDaemon.java @@ -20,6 +20,7 @@ package org.jackhuang.hmcl.ui; import java.io.File; import java.io.IOException; import javax.swing.JOptionPane; +import javax.swing.SwingUtilities; import org.jackhuang.hmcl.api.HMCLApi; import org.jackhuang.hmcl.api.event.process.JVMLaunchFailedEvent; import org.jackhuang.hmcl.api.event.process.JavaProcessExitedAbnormallyEvent; @@ -40,7 +41,6 @@ import org.jackhuang.hmcl.api.HMCLog; import org.jackhuang.hmcl.util.DefaultPlugin; import org.jackhuang.hmcl.util.sys.FileUtils; import org.jackhuang.hmcl.util.sys.ProcessMonitor; -import org.jackhuang.hmcl.util.net.WebFrame; /** * @@ -89,29 +89,22 @@ public class LaunchingUIDaemon { break; } } - if (!LogWindow.INSTANCE.isVisible()) { - String msg = C.i18n("launch.exited_abnormally") + " exit code: " + exitCode; - if (errorText != null) - msg += ", advice: " + MinecraftCrashAdvicer.getAdvice(FileUtils.readQuietly(new File(errorText))); - WebFrame f = new WebFrame(logs); - f.setModal(true); - f.setTitle(msg); - f.setVisible(true); - } - checkExit((LauncherVisibility) ((ProcessMonitor) event.getSource()).getTag()); + String msg = C.i18n("launch.exited_abnormally") + " exit code: " + exitCode; + if (errorText != null) + msg += ", advice: " + MinecraftCrashAdvicer.getAdvice(FileUtils.readQuietly(new File(errorText))); + HMCLog.err(msg); + SwingUtilities.invokeLater(() -> LogWindow.INSTANCE.setVisible(true)); + noExitThisTime = true; }); HMCLApi.EVENT_BUS.channel(JVMLaunchFailedEvent.class).register(event -> { int exitCode = event.getValue().getExitCode(); HMCLog.err("Cannot create jvm, exit code: " + exitCode); - if (!LogWindow.INSTANCE.isVisible()) { - WebFrame f = new WebFrame(event.getValue().getStdOutLines().toArray(new String[0])); - f.setModal(true); - f.setTitle(C.i18n("launch.cannot_create_jvm") + " exit code: " + exitCode); - f.setVisible(true); - } - checkExit((LauncherVisibility) ((ProcessMonitor) event.getSource()).getTag()); + SwingUtilities.invokeLater(() -> LogWindow.INSTANCE.setVisible(true)); + noExitThisTime = true; }); } + + boolean noExitThisTime = false; void runGame(Profile profile) { MainFrame.INSTANCE.showMessage(C.i18n("ui.message.launching")); @@ -168,12 +161,14 @@ public class LaunchingUIDaemon { } }; - private static void checkExit(LauncherVisibility v) { - if (v != LauncherVisibility.KEEP && !LogWindow.INSTANCE.isVisible()) { + private void checkExit(LauncherVisibility v) { + if (v != LauncherVisibility.KEEP && !LogWindow.INSTANCE.isVisible() && !noExitThisTime) { HMCLog.log("Launcher will exit now."); System.exit(0); - } else + } else { HMCLog.log("Launcher will not exit now."); + noExitThisTime = false; + } } private static final Consumer LAUNCH_SCRIPT_FINISHER = event -> { diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/LogWindow.form b/HMCL/src/main/java/org/jackhuang/hmcl/ui/LogWindow.form index 9c98ebd8c..2d954fb7d 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/LogWindow.form +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/LogWindow.form @@ -32,7 +32,7 @@ - + @@ -62,7 +62,7 @@ - + @@ -161,7 +161,7 @@ - + diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/LogWindow.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/LogWindow.java index 41997cce5..6a6b9bdee 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/LogWindow.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/LogWindow.java @@ -18,6 +18,7 @@ package org.jackhuang.hmcl.ui; import java.io.PrintStream; +import javax.swing.JScrollBar; import javax.swing.SwingUtilities; import javax.swing.text.Document; import javax.swing.text.SimpleAttributeSet; @@ -28,6 +29,7 @@ import org.jackhuang.hmcl.util.log.Level; import org.jackhuang.hmcl.api.func.NonFunction; import org.jackhuang.hmcl.util.DoubleOutputStream; import org.jackhuang.hmcl.util.Utils; +import org.jackhuang.hmcl.util.sys.ProcessMonitor; import org.jackhuang.hmcl.util.ui.SwingUtils; /** @@ -36,9 +38,7 @@ import org.jackhuang.hmcl.util.ui.SwingUtils; */ public class LogWindow extends javax.swing.JFrame { - boolean movingEnd; NonFunction listener; - Runnable terminateGameListener; /** * Creates new form LogWindow @@ -46,8 +46,6 @@ public class LogWindow extends javax.swing.JFrame { public LogWindow() { initComponents(); - movingEnd = true; - DoubleOutputStream out = new DoubleOutputStream(new LogWindowOutputStream(this, Level.INFO), System.out); System.setOut(new PrintStream(out)); DoubleOutputStream err = new DoubleOutputStream(new LogWindowOutputStream(this, Level.ERROR), System.err); @@ -79,7 +77,7 @@ public class LogWindow extends javax.swing.JFrame { btnMCF = new javax.swing.JButton(); btnTerminateGame = new javax.swing.JButton(); btnGitHub = new javax.swing.JButton(); - jScrollPane2 = new javax.swing.JScrollPane(); + pnlLog = new javax.swing.JScrollPane(); txtLog = new javax.swing.JTextPane(); setDefaultCloseOperation(javax.swing.WindowConstants.DISPOSE_ON_CLOSE); @@ -148,7 +146,7 @@ public class LogWindow extends javax.swing.JFrame { } }); - jScrollPane2.setViewportView(txtLog); + pnlLog.setViewportView(txtLog); javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane()); getContentPane().setLayout(layout); @@ -157,7 +155,7 @@ public class LogWindow extends javax.swing.JFrame { .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup() .addContainerGap() .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING) - .addComponent(jScrollPane2) + .addComponent(pnlLog) .addGroup(layout.createSequentialGroup() .addComponent(btnTieBa) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) @@ -183,7 +181,7 @@ public class LogWindow extends javax.swing.JFrame { .addContainerGap() .addComponent(lblCrash) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(jScrollPane2, javax.swing.GroupLayout.DEFAULT_SIZE, 356, Short.MAX_VALUE) + .addComponent(pnlLog, javax.swing.GroupLayout.DEFAULT_SIZE, 356, Short.MAX_VALUE) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) .addComponent(btnClear) @@ -201,8 +199,8 @@ public class LogWindow extends javax.swing.JFrame { }// //GEN-END:initComponents private void btnCloseActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnCloseActionPerformed - if (listener != null && listener.apply() && terminateGameListener != null) - terminateGameListener.run(); + if (listener != null && listener.apply()) + terminateGames(); SwingUtils.exitIfNoWindow(this, true); }//GEN-LAST:event_btnCloseActionPerformed @@ -227,8 +225,7 @@ public class LogWindow extends javax.swing.JFrame { }//GEN-LAST:event_btnMCFActionPerformed private void btnTerminateGameActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnTerminateGameActionPerformed - if (terminateGameListener != null) - terminateGameListener.run(); + terminateGames(); }//GEN-LAST:event_btnTerminateGameActionPerformed private void btnGitHubActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnGitHubActionPerformed @@ -236,11 +233,15 @@ public class LogWindow extends javax.swing.JFrame { }//GEN-LAST:event_btnGitHubActionPerformed private void formWindowClosing(java.awt.event.WindowEvent evt) {//GEN-FIRST:event_formWindowClosing - if (listener != null && listener.apply() && terminateGameListener != null) - terminateGameListener.run(); + if (listener != null && listener.apply()) + terminateGames(); SwingUtils.exitIfNoWindow(this); }//GEN-LAST:event_formWindowClosing + void terminateGames() { + ProcessMonitor.stopAll(); + } + public void log(final String status, final Level c) { SwingUtilities.invokeLater(() -> { String newStatus = status.replace("\t", " "); @@ -252,11 +253,6 @@ public class LogWindow extends javax.swing.JFrame { } catch (Exception ex) { HMCLog.err("Failed to insert \"" + newStatus + "\" to " + d.getLength(), ex); } - - if (movingEnd) { - int position = d.getLength(); - txtLog.setCaretPosition(position); - } }); } @@ -264,22 +260,10 @@ public class LogWindow extends javax.swing.JFrame { this.listener = exit; } - public void setTerminateGame(Runnable l) { - this.terminateGameListener = l; - } - public void clean() { txtLog.setText(""); } - public boolean getMovingEnd() { - return movingEnd; - } - - public void setMovingEnd(boolean b) { - movingEnd = b; - } - @Override public void setVisible(boolean b) { lblCrash.setVisible(false); @@ -316,8 +300,8 @@ public class LogWindow extends javax.swing.JFrame { private javax.swing.JButton btnMCF; private javax.swing.JButton btnTerminateGame; private javax.swing.JButton btnTieBa; - private javax.swing.JScrollPane jScrollPane2; private javax.swing.JLabel lblCrash; + private javax.swing.JScrollPane pnlLog; private javax.swing.JTextPane txtLog; // End of variables declaration//GEN-END:variables } diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/LogWindowOutputStream.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/LogWindowOutputStream.java index 6eb6b3e94..6b9c789fd 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/LogWindowOutputStream.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/LogWindowOutputStream.java @@ -20,7 +20,6 @@ package org.jackhuang.hmcl.ui; import java.io.OutputStream; import java.util.Objects; import javax.swing.SwingUtilities; -import org.jackhuang.hmcl.util.code.Charsets; import org.jackhuang.hmcl.util.log.Level; /** diff --git a/HMCLCore/src/main/java/org/jackhuang/hmcl/core/launch/GameLauncher.java b/HMCLCore/src/main/java/org/jackhuang/hmcl/core/launch/GameLauncher.java index f2a1a1734..800c86fde 100644 --- a/HMCLCore/src/main/java/org/jackhuang/hmcl/core/launch/GameLauncher.java +++ b/HMCLCore/src/main/java/org/jackhuang/hmcl/core/launch/GameLauncher.java @@ -167,7 +167,7 @@ public abstract class GameLauncher { ProcessBuilder builder = new ProcessBuilder(str); if (options.getLaunchVersion() == null || service.baseDirectory() == null) throw new Error("Fucking bug!"); - builder.redirectErrorStream(true).directory(service.version().getRunDirectory(options.getLaunchVersion())) + builder.directory(service.version().getRunDirectory(options.getLaunchVersion())) .environment().put("APPDATA", service.baseDirectory().getAbsolutePath()); JavaProcess jp = new JavaProcess(str, builder.start()); HMCLog.log("Have started the process"); diff --git a/HMCLCore/src/main/java/org/jackhuang/hmcl/util/log/Level.java b/HMCLCore/src/main/java/org/jackhuang/hmcl/util/log/Level.java index ee9738078..4a7a985e8 100644 --- a/HMCLCore/src/main/java/org/jackhuang/hmcl/util/log/Level.java +++ b/HMCLCore/src/main/java/org/jackhuang/hmcl/util/log/Level.java @@ -50,7 +50,8 @@ public enum Level { public static final Pattern MINECRAFT_LOGGER = Pattern.compile("\\[(?[0-9:]+)\\] \\[[^/]+/(?[^\\]]+)\\]"); public static final String JAVA_SYMBOL = "([a-zA-Z_$][a-zA-Z\\d_$]*\\.)+[a-zA-Z_$][a-zA-Z\\d_$]*"; - public static Level guessLevel(String line, Level level) { + public static Level guessLevel(String line, Level preLevel) { + Level level = preLevel; Matcher m = MINECRAFT_LOGGER.matcher(line); if (m.find()) { // New style logs from log4j @@ -98,7 +99,7 @@ public enum Level { || line.matches("([a-zA-Z_$][a-zA-Z\\d_$]*\\.)+[a-zA-Z_$]?[a-zA-Z\\d_$]*(Exception|Error|Throwable)") || line.matches("... \\d+ more$")) return ERROR; - return level; + return preLevel.level < level.level ? preLevel : level; } } diff --git a/HMCLCore/src/main/java/org/jackhuang/hmcl/util/sys/JavaProcess.java b/HMCLCore/src/main/java/org/jackhuang/hmcl/util/sys/JavaProcess.java index 27a5d9461..fa91a1f1d 100644 --- a/HMCLCore/src/main/java/org/jackhuang/hmcl/util/sys/JavaProcess.java +++ b/HMCLCore/src/main/java/org/jackhuang/hmcl/util/sys/JavaProcess.java @@ -20,7 +20,6 @@ package org.jackhuang.hmcl.util.sys; import org.jackhuang.hmcl.api.IProcess; import java.util.ArrayList; import java.util.Arrays; -import java.util.HashSet; import java.util.List; /** @@ -28,7 +27,6 @@ import java.util.List; * @author huangyuhui */ public class JavaProcess implements IProcess { - public static HashSet processes = new HashSet<>(); private final List commands; private final Process process; @@ -37,7 +35,6 @@ public class JavaProcess implements IProcess { public JavaProcess(List commands, Process process) { this.commands = commands; this.process = process; - processes.add(process); } public JavaProcess(String[] commands, Process process) { diff --git a/HMCLCore/src/main/java/org/jackhuang/hmcl/util/sys/ProcessMonitor.java b/HMCLCore/src/main/java/org/jackhuang/hmcl/util/sys/ProcessMonitor.java index 1eb78e29d..55626d4b4 100644 --- a/HMCLCore/src/main/java/org/jackhuang/hmcl/util/sys/ProcessMonitor.java +++ b/HMCLCore/src/main/java/org/jackhuang/hmcl/util/sys/ProcessMonitor.java @@ -19,7 +19,6 @@ package org.jackhuang.hmcl.util.sys; import java.util.Arrays; import java.util.HashSet; -import org.jackhuang.hmcl.util.CollectionUtils; import org.jackhuang.hmcl.api.HMCLApi; import org.jackhuang.hmcl.api.event.process.JVMLaunchFailedEvent; import org.jackhuang.hmcl.api.event.process.JavaProcessExitedAbnormallyEvent; @@ -36,7 +35,9 @@ import org.jackhuang.hmcl.api.IProcess; */ public class ProcessMonitor { - private final HashSet al = new HashSet<>(); + public static final HashSet MONITORS = new HashSet<>(); + + ProcessThread inputThread, errorThread; private final IProcess p; public ProcessMonitor(IProcess p) { @@ -46,7 +47,7 @@ public class ProcessMonitor { public IProcess getProcess() { return p; } - + private Object tag; public Object getTag() { @@ -56,36 +57,44 @@ public class ProcessMonitor { public void setTag(Object tag) { this.tag = tag; } - + public void start() { + MONITORS.add(this); HMCLApi.EVENT_BUS.fireChannel(new JavaProcessStartingEvent(this, p)); - ProcessThread a = new ProcessThread(p); - a.stopEvent.register(event -> { - HMCLog.log("Process exit code: " + p.getExitCode()); - if (p.getExitCode() != 0 || StrUtils.containsOne(p.getStdOutLines(), - Arrays.asList("Unable to launch"), - x -> Level.guessLevel(x, Level.INFO).lessOrEqual(Level.ERROR))) - HMCLApi.EVENT_BUS.fireChannel(new JavaProcessExitedAbnormallyEvent(ProcessMonitor.this, p)); - if (p.getExitCode() != 0 && StrUtils.containsOne(p.getStdOutLines(), - Arrays.asList("Could not create the Java Virtual Machine.", - "Error occurred during initialization of VM", - "A fatal exception has occurred. Program will exit.", - "Unable to launch"), - x -> Level.guessLevel(x, Level.INFO).lessOrEqual(Level.ERROR))) - HMCLApi.EVENT_BUS.fireChannel(new JVMLaunchFailedEvent(ProcessMonitor.this, p)); - processThreadStopped((ProcessThread) event.getSource(), false); - }); - a.start(); - al.add(a); + inputThread = new ProcessThread(p, false); + errorThread = new ProcessThread(p, true); + inputThread.stopEvent.register(this::threadStopped); + inputThread.stopEvent.register(event -> processThreadStopped((ProcessThread) event.getSource())); + errorThread.stopEvent.register(this::threadStopped); + inputThread.start(); } - void processThreadStopped(ProcessThread t1, boolean forceTermintate) { - CollectionUtils.removeIf(al, t -> t == t1 || !t.isAlive()); - if (al.isEmpty() || forceTermintate) { - for (Thread a : al) - a.interrupt(); - al.clear(); - HMCLApi.EVENT_BUS.fireChannel(new JavaProcessStoppedEvent(this, p)); + private void threadStopped() { + HMCLog.log("Process exit code: " + p.getExitCode()); + if (p.getExitCode() != 0 || StrUtils.containsOne(p.getStdOutLines(), + Arrays.asList("Unable to launch"), + x -> Level.guessLevel(x, Level.INFO).lessOrEqual(Level.ERROR))) + HMCLApi.EVENT_BUS.fireChannel(new JavaProcessExitedAbnormallyEvent(ProcessMonitor.this, p)); + if (p.getExitCode() != 0 && StrUtils.containsOne(p.getStdOutLines(), + Arrays.asList("Could not create the Java Virtual Machine.", + "Error occurred during initialization of VM", + "A fatal exception has occurred. Program will exit.", + "Unable to launch"), + x -> Level.guessLevel(x, Level.INFO).lessOrEqual(Level.ERROR))) + HMCLApi.EVENT_BUS.fireChannel(new JVMLaunchFailedEvent(ProcessMonitor.this, p)); + } + + private void processThreadStopped(ProcessThread t1) { + MONITORS.remove(this); + errorThread.interrupt(); + HMCLApi.EVENT_BUS.fireChannel(new JavaProcessStoppedEvent(this, p)); + } + + public static void stopAll() { + for (ProcessMonitor monitor : MONITORS) { + monitor.getProcess().getRawProcess().destroy(); + monitor.inputThread.interrupt(); + monitor.errorThread.interrupt(); } } } diff --git a/HMCLCore/src/main/java/org/jackhuang/hmcl/util/sys/ProcessThread.java b/HMCLCore/src/main/java/org/jackhuang/hmcl/util/sys/ProcessThread.java index 0283402b5..04df2767a 100644 --- a/HMCLCore/src/main/java/org/jackhuang/hmcl/util/sys/ProcessThread.java +++ b/HMCLCore/src/main/java/org/jackhuang/hmcl/util/sys/ProcessThread.java @@ -34,12 +34,14 @@ import org.jackhuang.hmcl.api.IProcess; public class ProcessThread extends Thread { IProcess p; - + boolean readError; public final EventHandler> printlnEvent = new EventHandler<>(); public final EventHandler> stopEvent = new EventHandler<>(); - public ProcessThread(IProcess process) { + public ProcessThread(IProcess process, boolean readError) { p = process; + this.readError = readError; + setDaemon(readError); } public IProcess getProcess() { @@ -51,7 +53,7 @@ public class ProcessThread extends Thread { setName("ProcessMonitor"); BufferedReader br = null; try { - InputStream in = p.getRawProcess().getInputStream(); + InputStream in = readError ? p.getRawProcess().getErrorStream() : p.getRawProcess().getInputStream(); br = new BufferedReader(new InputStreamReader(in, Charsets.toCharset())); String line; @@ -66,7 +68,6 @@ public class ProcessThread extends Thread { System.out.println("MC: " + line); p.getStdOutLines().add(line); } - JavaProcess.processes.remove(p.getRawProcess()); stopEvent.fire(new SimpleEvent<>(this, p)); } catch (IOException e) { HMCLog.err("An error occured when reading process stdout/stderr.", e);