From b7aa99550db24b5c42c44ddd20476b099bc3dda6 Mon Sep 17 00:00:00 2001 From: huanghongxun Date: Mon, 16 Nov 2015 18:41:28 +0800 Subject: [PATCH] Added logging highlight. --- .../hellominecraft/launcher/Launcher.java | 10 +-- .../hellominecraft/launcher/Main.java | 12 +-- .../launcher/launch/GameLauncher.java | 2 +- .../hellominecraft/logging/Level.java | 73 ++++++++++++++++--- .../logging/layout/DefaultLayout.java | 2 +- ...Stream.java => LogWindowOutputStream.java} | 24 +++--- .../hellominecraft/views/LogWindow.form | 37 ++++------ .../hellominecraft/views/LogWindow.java | 72 ++++++++++-------- .../jackhuang/hellominecraft/svrmgr/Main.java | 4 +- 9 files changed, 144 insertions(+), 92 deletions(-) rename HMCLAPI/src/main/java/org/jackhuang/hellominecraft/utils/{TextComponentOutputStream.java => LogWindowOutputStream.java} (82%) diff --git a/HMCL/src/main/java/org/jackhuang/hellominecraft/launcher/Launcher.java b/HMCL/src/main/java/org/jackhuang/hellominecraft/launcher/Launcher.java index 8e64002c6..36045a124 100644 --- a/HMCL/src/main/java/org/jackhuang/hellominecraft/launcher/Launcher.java +++ b/HMCL/src/main/java/org/jackhuang/hellominecraft/launcher/Launcher.java @@ -61,7 +61,7 @@ public final class Launcher { String[] tokenized = StrUtils.tokenize(classPath, File.pathSeparator); int len = tokenized.length; - + if (showInfo) { LogWindow.instance.setTerminateGame(() -> Utils.shutdownForcely(1)); try { @@ -99,7 +99,7 @@ public final class Launcher { Method minecraftMain; try { - minecraftMain = new URLClassLoader(urls, URLClassLoader.getSystemClassLoader().getParent()).loadClass(mainClass).getMethod("main", String[].class); + minecraftMain = new URLClassLoader(urls, URLClassLoader.getSystemClassLoader()).loadClass(mainClass).getMethod("main", String[].class); } catch (ClassNotFoundException | NoSuchMethodException | SecurityException t) { MessageBox.Show(C.i18n("crash.main_class_not_found")); println("Minecraft main class not found."); @@ -118,9 +118,9 @@ public final class Launcher { final String advice = MinecraftCrashAdvicer.getAdvice(trace); MessageBox.Show(C.i18n("crash.minecraft") + ": " + advice); - LogWindow.instance.log(C.i18n("crash.minecraft")); - LogWindow.instance.log(advice); - LogWindow.instance.log(trace); + LogWindow.instance.warning(C.i18n("crash.minecraft")); + LogWindow.instance.warning(advice); + LogWindow.instance.warning(trace); LogWindow.instance.setExit(TrueFunction.instance); LogWindow.instance.setVisible(true); diff --git a/HMCL/src/main/java/org/jackhuang/hellominecraft/launcher/Main.java b/HMCL/src/main/java/org/jackhuang/hellominecraft/launcher/Main.java index 08e60f28e..e77eb6a1c 100644 --- a/HMCL/src/main/java/org/jackhuang/hellominecraft/launcher/Main.java +++ b/HMCL/src/main/java/org/jackhuang/hellominecraft/launcher/Main.java @@ -70,7 +70,7 @@ import org.jackhuang.hellominecraft.utils.system.OS; */ public final class Main implements Runnable { - private static final X509TrustManager xtm = new X509TrustManager() { + private static final X509TrustManager XTM = new X509TrustManager() { @Override public void checkClientTrusted(X509Certificate[] chain, String authType) { } @@ -84,21 +84,21 @@ public final class Main implements Runnable { return null; } }; - private static final HostnameVerifier hnv = (hostname, session) -> true; + private static final HostnameVerifier HNV = (hostname, session) -> true; static { SSLContext sslContext = null; try { sslContext = SSLContext.getInstance("TLS"); - X509TrustManager[] xtmArray = new X509TrustManager[]{xtm}; + X509TrustManager[] xtmArray = new X509TrustManager[]{XTM}; sslContext.init(null, xtmArray, new java.security.SecureRandom()); } catch (GeneralSecurityException gse) { } if (sslContext != null) HttpsURLConnection.setDefaultSSLSocketFactory(sslContext.getSocketFactory()); - HttpsURLConnection.setDefaultHostnameVerifier(hnv); + HttpsURLConnection.setDefaultHostnameVerifier(HNV); } public static String launcherName = "Hello Minecraft! Launcher"; @@ -123,7 +123,7 @@ public final class Main implements Runnable { return launcherName + ' ' + makeVersion(); } - public static final Main instance = new Main(); + public static final Main INSTANCE = new Main(); public static void main(String[] args) { { @@ -174,7 +174,7 @@ public final class Main implements Runnable { LogWindow.instance.clean(); LogWindow.instance.setTerminateGame(GameLauncher.PROCESS_MANAGER::stopAllProcesses); - + try { UIManager.setLookAndFeel(new HelloMinecraftLookAndFeel()); } catch (ParseException | UnsupportedLookAndFeelException ex) { diff --git a/HMCL/src/main/java/org/jackhuang/hellominecraft/launcher/launch/GameLauncher.java b/HMCL/src/main/java/org/jackhuang/hellominecraft/launcher/launch/GameLauncher.java index 2584c32a7..ba6b39d18 100644 --- a/HMCL/src/main/java/org/jackhuang/hellominecraft/launcher/launch/GameLauncher.java +++ b/HMCL/src/main/java/org/jackhuang/hellominecraft/launcher/launch/GameLauncher.java @@ -144,7 +144,7 @@ public class GameLauncher { .environment().put("APPDATA", get.getCanonicalGameDir()); JavaProcess jp = new JavaProcess(str, builder.start(), PROCESS_MANAGER); launchEvent.execute(jp); - } catch (IOException e) { + } catch (Exception e) { failEvent.execute(C.i18n("launch.failed_creating_process") + "\n" + e.getMessage()); HMCLog.err("Failed to launch when creating a new process.", e); } diff --git a/HMCLAPI/src/main/java/org/jackhuang/hellominecraft/logging/Level.java b/HMCLAPI/src/main/java/org/jackhuang/hellominecraft/logging/Level.java index c5e749a1a..848171192 100644 --- a/HMCLAPI/src/main/java/org/jackhuang/hellominecraft/logging/Level.java +++ b/HMCLAPI/src/main/java/org/jackhuang/hellominecraft/logging/Level.java @@ -16,33 +16,82 @@ */ package org.jackhuang.hellominecraft.logging; +import java.awt.Color; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + /** * * @author huangyuhui */ public enum Level { - OFF(0), - FATAL(1), - ERROR(2), - WARN(3), - INFO(4), - DEBUG(5), - TRACE(6), - ALL(2147483647); + OFF(0, Color.gray), + FATAL(1, Color.red), + ERROR(2, Color.red), + WARN(3, Color.orange), + INFO(4, Color.black), + DEBUG(5, Color.blue), + TRACE(6, Color.blue), + ALL(2147483647, Color.black); public final int level; + public final Color COLOR; - private Level(int i) { - level = i; + private Level(int i, Color c) { + level = i; + COLOR = c; } public boolean lessOrEqual(Level level) { - return this.level <= level.level; + return this.level <= level.level; } public boolean lessOrEqual(int level) { - return this.level <= level; + return this.level <= 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) { + Matcher m = MINECRAFT_LOGGER.matcher(line); + if (m.find()) { + // New style logs from log4j + String levelStr = m.group("level"); + if ("INFO".equals(levelStr)) + level = INFO; + else if ("WARN".equals(levelStr)) + level = WARN; + else if ("ERROR".equals(levelStr)) + level = ERROR; + else if ("FATAL".equals(levelStr)) + level = FATAL; + else if ("TRACE".equals(levelStr)) + level = TRACE; + else if ("DEBUG".equals(levelStr)) + level = DEBUG; + } else { + if (line.contains("[INFO]") || line.contains("[CONFIG]") || line.contains("[FINE]") + || line.contains("[FINER]") || line.contains("[FINEST]")) + level = INFO; + if (line.contains("[SEVERE]") || line.contains("[STDERR]")) + level = ERROR; + if (line.contains("[WARNING]")) + level = WARN; + if (line.contains("[DEBUG]")) + level = DEBUG; + } + if (line.contains("overwriting existing")) + return FATAL; + + if (line.contains("Exception in thread") + || line.matches("\\s+at " + JAVA_SYMBOL) + || line.matches("Caused by: " + JAVA_SYMBOL) + || 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; } } diff --git a/HMCLAPI/src/main/java/org/jackhuang/hellominecraft/logging/layout/DefaultLayout.java b/HMCLAPI/src/main/java/org/jackhuang/hellominecraft/logging/layout/DefaultLayout.java index 62901e119..b350a108f 100644 --- a/HMCLAPI/src/main/java/org/jackhuang/hellominecraft/logging/layout/DefaultLayout.java +++ b/HMCLAPI/src/main/java/org/jackhuang/hellominecraft/logging/layout/DefaultLayout.java @@ -29,7 +29,7 @@ public class DefaultLayout extends AbstractStringLayout { @Override public String toSerializable(LogEvent event) { - return "[" + sdf.format(new Date()) + "][" + event.threadName + "/" + event.level.name() + "] " + event.message.getFormattedMessage() + "\n"; + return "[" + sdf.format(new Date()) + "] [" + event.threadName + "/" + event.level.name() + "] " + event.message.getFormattedMessage() + "\n"; } } diff --git a/HMCLAPI/src/main/java/org/jackhuang/hellominecraft/utils/TextComponentOutputStream.java b/HMCLAPI/src/main/java/org/jackhuang/hellominecraft/utils/LogWindowOutputStream.java similarity index 82% rename from HMCLAPI/src/main/java/org/jackhuang/hellominecraft/utils/TextComponentOutputStream.java rename to HMCLAPI/src/main/java/org/jackhuang/hellominecraft/utils/LogWindowOutputStream.java index 26c1f1542..7a55c9a73 100644 --- a/HMCLAPI/src/main/java/org/jackhuang/hellominecraft/utils/TextComponentOutputStream.java +++ b/HMCLAPI/src/main/java/org/jackhuang/hellominecraft/utils/LogWindowOutputStream.java @@ -18,19 +18,21 @@ package org.jackhuang.hellominecraft.utils; import java.io.OutputStream; import java.util.Timer; -import java.util.TimerTask; import javax.swing.SwingUtilities; -import javax.swing.text.JTextComponent; +import org.jackhuang.hellominecraft.logging.Level; +import org.jackhuang.hellominecraft.views.LogWindow; /** * * @author huangyuhui */ -public class TextComponentOutputStream extends OutputStream { +public class LogWindowOutputStream extends OutputStream { private static final Timer TIMER = new Timer(); - private final JTextComponent txt; + private final LogWindow txt; + private final Level sas; + /* private final CacheTask t = new CacheTask(); private class CacheTask extends TimerTask { private final Object lock = new Object(); @@ -53,12 +55,11 @@ public class TextComponentOutputStream extends OutputStream { cachedString.append(s); } } - } + }*/ - public TextComponentOutputStream(JTextComponent paramJTextComponent) { - txt = paramJTextComponent; - - //TIMER.schedule(t, 20); + public LogWindowOutputStream(LogWindow logWindow, Level l) { + txt = logWindow; + this.sas = l; } @Override @@ -72,12 +73,9 @@ public class TextComponentOutputStream extends OutputStream { } private void append(final String newString) { - //t.cache(newString); try { SwingUtilities.invokeLater(() -> { - String t = txt.getText() + newString.replace("\t", " "); - txt.setText(t); - txt.setCaretPosition(t.length()); + txt.log(newString, Level.guessLevel(newString, sas)); }); } catch (Throwable e) { e.printStackTrace(); diff --git a/HMCLAPI/src/main/java/org/jackhuang/hellominecraft/views/LogWindow.form b/HMCLAPI/src/main/java/org/jackhuang/hellominecraft/views/LogWindow.form index 1567b985d..99e2a6305 100644 --- a/HMCLAPI/src/main/java/org/jackhuang/hellominecraft/views/LogWindow.form +++ b/HMCLAPI/src/main/java/org/jackhuang/hellominecraft/views/LogWindow.form @@ -29,10 +29,10 @@ - + - - + + @@ -50,7 +50,7 @@ - + @@ -62,7 +62,7 @@ - + @@ -80,22 +80,6 @@ - - - - - - - - - - - - - - - - @@ -177,5 +161,16 @@ + + + + + + + + + + + diff --git a/HMCLAPI/src/main/java/org/jackhuang/hellominecraft/views/LogWindow.java b/HMCLAPI/src/main/java/org/jackhuang/hellominecraft/views/LogWindow.java index 610bc5a17..c70b2982e 100644 --- a/HMCLAPI/src/main/java/org/jackhuang/hellominecraft/views/LogWindow.java +++ b/HMCLAPI/src/main/java/org/jackhuang/hellominecraft/views/LogWindow.java @@ -16,13 +16,18 @@ */ package org.jackhuang.hellominecraft.views; -import java.util.Timer; +import java.awt.Color; +import javax.swing.text.BadLocationException; +import javax.swing.text.Document; +import javax.swing.text.SimpleAttributeSet; +import javax.swing.text.StyleConstants; import org.jackhuang.hellominecraft.C; +import org.jackhuang.hellominecraft.HMCLog; +import org.jackhuang.hellominecraft.logging.Level; import org.jackhuang.hellominecraft.utils.functions.NonFunction; import org.jackhuang.hellominecraft.utils.DoubleOutputStream; import org.jackhuang.hellominecraft.utils.LauncherPrintStream; -import org.jackhuang.hellominecraft.utils.StrUtils; -import org.jackhuang.hellominecraft.utils.TextComponentOutputStream; +import org.jackhuang.hellominecraft.utils.LogWindowOutputStream; import org.jackhuang.hellominecraft.utils.Utils; /** @@ -44,11 +49,10 @@ public class LogWindow extends javax.swing.JFrame { movingEnd = true; setLocationRelativeTo(null); - - TextComponentOutputStream tc = new TextComponentOutputStream(txtLog); - DoubleOutputStream out = new DoubleOutputStream(tc, System.out); + txtLog.setEditable(false); + DoubleOutputStream out = new DoubleOutputStream(new LogWindowOutputStream(this, Level.INFO), System.out); System.setOut(new LauncherPrintStream(out)); - DoubleOutputStream err = new DoubleOutputStream(tc, System.err); + DoubleOutputStream err = new DoubleOutputStream(new LogWindowOutputStream(this, Level.ERROR), System.err); System.setErr(new LauncherPrintStream(err)); } @@ -63,8 +67,6 @@ public class LogWindow extends javax.swing.JFrame { // //GEN-BEGIN:initComponents private void initComponents() { - jScrollPane1 = new javax.swing.JScrollPane(); - txtLog = new javax.swing.JTextArea(); btnClear = new javax.swing.JButton(); btnClose = new javax.swing.JButton(); btnCopy = new javax.swing.JButton(); @@ -74,6 +76,8 @@ 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(); + txtLog = new javax.swing.JTextPane(); setDefaultCloseOperation(javax.swing.WindowConstants.DISPOSE_ON_CLOSE); setTitle(C.I18N.getString("logwindow.title")); // NOI18N @@ -83,11 +87,6 @@ public class LogWindow extends javax.swing.JFrame { } }); - txtLog.setEditable(false); - txtLog.setColumns(20); - txtLog.setRows(5); - jScrollPane1.setViewportView(txtLog); - btnClear.setText(C.I18N.getString("ui.button.clear")); // NOI18N btnClear.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { @@ -146,15 +145,17 @@ public class LogWindow extends javax.swing.JFrame { } }); + jScrollPane2.setViewportView(txtLog); + javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane()); getContentPane().setLayout(layout); layout.setHorizontalGroup( layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(layout.createSequentialGroup() + .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup() .addContainerGap() - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addComponent(jScrollPane1) - .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup() + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING) + .addComponent(jScrollPane2) + .addGroup(layout.createSequentialGroup() .addComponent(btnTieBa) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addComponent(btnMCBBS) @@ -170,7 +171,7 @@ public class LogWindow extends javax.swing.JFrame { .addComponent(btnClear) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addComponent(btnClose)) - .addComponent(lblCrash, javax.swing.GroupLayout.DEFAULT_SIZE, 674, Short.MAX_VALUE)) + .addComponent(lblCrash, javax.swing.GroupLayout.Alignment.LEADING)) .addContainerGap()) ); layout.setVerticalGroup( @@ -179,7 +180,7 @@ public class LogWindow extends javax.swing.JFrame { .addContainerGap() .addComponent(lblCrash, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(jScrollPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 375, Short.MAX_VALUE) + .addComponent(jScrollPane2, 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) @@ -235,21 +236,30 @@ public class LogWindow extends javax.swing.JFrame { }//GEN-LAST:event_btnGitHubActionPerformed public void log(String status) { - String text = txtLog.getText(); - text += status + System.getProperty("line.separator"); - txtLog.setText(text); + log(status, Level.INFO); + } + + public void warning(String status) { + log(status, Level.WARN); + } + + public void log(String status, Level c) { + status = status.replace("\t", " "); + Document d = txtLog.getStyledDocument(); + SimpleAttributeSet sas = new SimpleAttributeSet(); + StyleConstants.setForeground(sas, c.COLOR); + try { + d.insertString(d.getLength(), status, sas); + } catch (BadLocationException ex) { + HMCLog.err("Failed to insert \"" + status + "\" to " + d.getLength(), ex); + } if (movingEnd) { - int position = text.length(); + int position = d.getLength(); txtLog.setCaretPosition(position); } } - public void log(String status, Throwable t) { - log(status); - log(StrUtils.getStackTrace(t)); - } - public void setExit(NonFunction exit) { this.listener = exit; } @@ -306,8 +316,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 jScrollPane1; + private javax.swing.JScrollPane jScrollPane2; private javax.swing.JLabel lblCrash; - private javax.swing.JTextArea txtLog; + private javax.swing.JTextPane txtLog; // End of variables declaration//GEN-END:variables } diff --git a/HMCSM/src/main/java/org/jackhuang/hellominecraft/svrmgr/Main.java b/HMCSM/src/main/java/org/jackhuang/hellominecraft/svrmgr/Main.java index f4951bb84..494b84be3 100644 --- a/HMCSM/src/main/java/org/jackhuang/hellominecraft/svrmgr/Main.java +++ b/HMCSM/src/main/java/org/jackhuang/hellominecraft/svrmgr/Main.java @@ -63,10 +63,10 @@ public class Main { HMCLog.err("There's something wrong when running server holder.", t); LogWindow.instance.clean(); - LogWindow.instance.log("开服器崩溃了QAQ"); + LogWindow.instance.warning("开服器崩溃了QAQ"); StringWriter trace = new StringWriter(); t.printStackTrace(new PrintWriter(trace)); - LogWindow.instance.log(trace.toString()); + LogWindow.instance.warning(trace.toString()); LogWindow.instance.setVisible(true); System.exit(-1);