Added logging highlight.

This commit is contained in:
huanghongxun 2015-11-16 18:41:28 +08:00
parent 990f830300
commit b7aa99550d
9 changed files with 144 additions and 92 deletions

View File

@ -99,7 +99,7 @@ public final class Launcher {
Method minecraftMain; Method minecraftMain;
try { 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) { } catch (ClassNotFoundException | NoSuchMethodException | SecurityException t) {
MessageBox.Show(C.i18n("crash.main_class_not_found")); MessageBox.Show(C.i18n("crash.main_class_not_found"));
println("Minecraft main class not found."); println("Minecraft main class not found.");
@ -118,9 +118,9 @@ public final class Launcher {
final String advice = MinecraftCrashAdvicer.getAdvice(trace); final String advice = MinecraftCrashAdvicer.getAdvice(trace);
MessageBox.Show(C.i18n("crash.minecraft") + ": " + advice); MessageBox.Show(C.i18n("crash.minecraft") + ": " + advice);
LogWindow.instance.log(C.i18n("crash.minecraft")); LogWindow.instance.warning(C.i18n("crash.minecraft"));
LogWindow.instance.log(advice); LogWindow.instance.warning(advice);
LogWindow.instance.log(trace); LogWindow.instance.warning(trace);
LogWindow.instance.setExit(TrueFunction.instance); LogWindow.instance.setExit(TrueFunction.instance);
LogWindow.instance.setVisible(true); LogWindow.instance.setVisible(true);

View File

@ -70,7 +70,7 @@ import org.jackhuang.hellominecraft.utils.system.OS;
*/ */
public final class Main implements Runnable { public final class Main implements Runnable {
private static final X509TrustManager xtm = new X509TrustManager() { private static final X509TrustManager XTM = new X509TrustManager() {
@Override @Override
public void checkClientTrusted(X509Certificate[] chain, String authType) { public void checkClientTrusted(X509Certificate[] chain, String authType) {
} }
@ -84,21 +84,21 @@ public final class Main implements Runnable {
return null; return null;
} }
}; };
private static final HostnameVerifier hnv = (hostname, session) -> true; private static final HostnameVerifier HNV = (hostname, session) -> true;
static { static {
SSLContext sslContext = null; SSLContext sslContext = null;
try { try {
sslContext = SSLContext.getInstance("TLS"); sslContext = SSLContext.getInstance("TLS");
X509TrustManager[] xtmArray = new X509TrustManager[]{xtm}; X509TrustManager[] xtmArray = new X509TrustManager[]{XTM};
sslContext.init(null, xtmArray, new java.security.SecureRandom()); sslContext.init(null, xtmArray, new java.security.SecureRandom());
} catch (GeneralSecurityException gse) { } catch (GeneralSecurityException gse) {
} }
if (sslContext != null) if (sslContext != null)
HttpsURLConnection.setDefaultSSLSocketFactory(sslContext.getSocketFactory()); HttpsURLConnection.setDefaultSSLSocketFactory(sslContext.getSocketFactory());
HttpsURLConnection.setDefaultHostnameVerifier(hnv); HttpsURLConnection.setDefaultHostnameVerifier(HNV);
} }
public static String launcherName = "Hello Minecraft! Launcher"; public static String launcherName = "Hello Minecraft! Launcher";
@ -123,7 +123,7 @@ public final class Main implements Runnable {
return launcherName + ' ' + makeVersion(); return launcherName + ' ' + makeVersion();
} }
public static final Main instance = new Main(); public static final Main INSTANCE = new Main();
public static void main(String[] args) { public static void main(String[] args) {
{ {

View File

@ -144,7 +144,7 @@ public class GameLauncher {
.environment().put("APPDATA", get.getCanonicalGameDir()); .environment().put("APPDATA", get.getCanonicalGameDir());
JavaProcess jp = new JavaProcess(str, builder.start(), PROCESS_MANAGER); JavaProcess jp = new JavaProcess(str, builder.start(), PROCESS_MANAGER);
launchEvent.execute(jp); launchEvent.execute(jp);
} catch (IOException e) { } catch (Exception e) {
failEvent.execute(C.i18n("launch.failed_creating_process") + "\n" + e.getMessage()); failEvent.execute(C.i18n("launch.failed_creating_process") + "\n" + e.getMessage());
HMCLog.err("Failed to launch when creating a new process.", e); HMCLog.err("Failed to launch when creating a new process.", e);
} }

View File

@ -16,33 +16,82 @@
*/ */
package org.jackhuang.hellominecraft.logging; package org.jackhuang.hellominecraft.logging;
import java.awt.Color;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/** /**
* *
* @author huangyuhui * @author huangyuhui
*/ */
public enum Level { public enum Level {
OFF(0), OFF(0, Color.gray),
FATAL(1), FATAL(1, Color.red),
ERROR(2), ERROR(2, Color.red),
WARN(3), WARN(3, Color.orange),
INFO(4), INFO(4, Color.black),
DEBUG(5), DEBUG(5, Color.blue),
TRACE(6), TRACE(6, Color.blue),
ALL(2147483647); ALL(2147483647, Color.black);
public final int level; public final int level;
public final Color COLOR;
private Level(int i) { private Level(int i, Color c) {
level = i; level = i;
COLOR = c;
} }
public boolean lessOrEqual(Level level) { public boolean lessOrEqual(Level level) {
return this.level <= level.level; return this.level <= level.level;
} }
public boolean lessOrEqual(int level) { public boolean lessOrEqual(int level) {
return this.level <= level; return this.level <= level;
}
public static final Pattern MINECRAFT_LOGGER = Pattern.compile("\\[(?<timestamp>[0-9:]+)\\] \\[[^/]+/(?<level>[^\\]]+)\\]");
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;
} }
} }

View File

@ -29,7 +29,7 @@ public class DefaultLayout extends AbstractStringLayout {
@Override @Override
public String toSerializable(LogEvent event) { 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";
} }
} }

View File

@ -18,19 +18,21 @@ package org.jackhuang.hellominecraft.utils;
import java.io.OutputStream; import java.io.OutputStream;
import java.util.Timer; import java.util.Timer;
import java.util.TimerTask;
import javax.swing.SwingUtilities; import javax.swing.SwingUtilities;
import javax.swing.text.JTextComponent; import org.jackhuang.hellominecraft.logging.Level;
import org.jackhuang.hellominecraft.views.LogWindow;
/** /**
* *
* @author huangyuhui * @author huangyuhui
*/ */
public class TextComponentOutputStream extends OutputStream { public class LogWindowOutputStream extends OutputStream {
private static final Timer TIMER = new Timer(); 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 final CacheTask t = new CacheTask();
private class CacheTask extends TimerTask { private class CacheTask extends TimerTask {
private final Object lock = new Object(); private final Object lock = new Object();
@ -53,12 +55,11 @@ public class TextComponentOutputStream extends OutputStream {
cachedString.append(s); cachedString.append(s);
} }
} }
} }*/
public TextComponentOutputStream(JTextComponent paramJTextComponent) { public LogWindowOutputStream(LogWindow logWindow, Level l) {
txt = paramJTextComponent; txt = logWindow;
this.sas = l;
//TIMER.schedule(t, 20);
} }
@Override @Override
@ -72,12 +73,9 @@ public class TextComponentOutputStream extends OutputStream {
} }
private void append(final String newString) { private void append(final String newString) {
//t.cache(newString);
try { try {
SwingUtilities.invokeLater(() -> { SwingUtilities.invokeLater(() -> {
String t = txt.getText() + newString.replace("\t", " "); txt.log(newString, Level.guessLevel(newString, sas));
txt.setText(t);
txt.setCaretPosition(t.length());
}); });
} catch (Throwable e) { } catch (Throwable e) {
e.printStackTrace(); e.printStackTrace();

View File

@ -29,10 +29,10 @@
<Layout> <Layout>
<DimensionLayout dim="0"> <DimensionLayout dim="0">
<Group type="103" groupAlignment="0" attributes="0"> <Group type="103" groupAlignment="0" attributes="0">
<Group type="102" attributes="0"> <Group type="102" alignment="1" attributes="0">
<EmptySpace max="-2" attributes="0"/> <EmptySpace max="-2" attributes="0"/>
<Group type="103" groupAlignment="0" attributes="0"> <Group type="103" groupAlignment="1" attributes="0">
<Component id="jScrollPane1" max="32767" attributes="0"/> <Component id="jScrollPane2" max="32767" attributes="0"/>
<Group type="102" alignment="1" attributes="0"> <Group type="102" alignment="1" attributes="0">
<Component id="btnTieBa" min="-2" max="-2" attributes="0"/> <Component id="btnTieBa" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/> <EmptySpace max="-2" attributes="0"/>
@ -50,7 +50,7 @@
<EmptySpace max="-2" attributes="0"/> <EmptySpace max="-2" attributes="0"/>
<Component id="btnClose" min="-2" max="-2" attributes="0"/> <Component id="btnClose" min="-2" max="-2" attributes="0"/>
</Group> </Group>
<Component id="lblCrash" alignment="0" pref="674" max="32767" attributes="0"/> <Component id="lblCrash" alignment="0" max="32767" attributes="0"/>
</Group> </Group>
<EmptySpace max="-2" attributes="0"/> <EmptySpace max="-2" attributes="0"/>
</Group> </Group>
@ -62,7 +62,7 @@
<EmptySpace max="-2" attributes="0"/> <EmptySpace max="-2" attributes="0"/>
<Component id="lblCrash" min="-2" max="-2" attributes="0"/> <Component id="lblCrash" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/> <EmptySpace max="-2" attributes="0"/>
<Component id="jScrollPane1" pref="375" max="32767" attributes="0"/> <Component id="jScrollPane2" pref="356" max="32767" attributes="0"/>
<EmptySpace max="-2" attributes="0"/> <EmptySpace max="-2" attributes="0"/>
<Group type="103" groupAlignment="3" attributes="0"> <Group type="103" groupAlignment="3" attributes="0">
<Component id="btnClear" alignment="3" min="-2" max="-2" attributes="0"/> <Component id="btnClear" alignment="3" min="-2" max="-2" attributes="0"/>
@ -80,22 +80,6 @@
</DimensionLayout> </DimensionLayout>
</Layout> </Layout>
<SubComponents> <SubComponents>
<Container class="javax.swing.JScrollPane" name="jScrollPane1">
<AuxValues>
<AuxValue name="autoScrollPane" type="java.lang.Boolean" value="true"/>
</AuxValues>
<Layout class="org.netbeans.modules.form.compat2.layouts.support.JScrollPaneSupportLayout"/>
<SubComponents>
<Component class="javax.swing.JTextArea" name="txtLog">
<Properties>
<Property name="editable" type="boolean" value="false"/>
<Property name="columns" type="int" value="20"/>
<Property name="rows" type="int" value="5"/>
</Properties>
</Component>
</SubComponents>
</Container>
<Component class="javax.swing.JButton" name="btnClear"> <Component class="javax.swing.JButton" name="btnClear">
<Properties> <Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor"> <Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
@ -177,5 +161,16 @@
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="btnGitHubActionPerformed"/> <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="btnGitHubActionPerformed"/>
</Events> </Events>
</Component> </Component>
<Container class="javax.swing.JScrollPane" name="jScrollPane2">
<AuxValues>
<AuxValue name="autoScrollPane" type="java.lang.Boolean" value="true"/>
</AuxValues>
<Layout class="org.netbeans.modules.form.compat2.layouts.support.JScrollPaneSupportLayout"/>
<SubComponents>
<Component class="javax.swing.JTextPane" name="txtLog">
</Component>
</SubComponents>
</Container>
</SubComponents> </SubComponents>
</Form> </Form>

View File

@ -16,13 +16,18 @@
*/ */
package org.jackhuang.hellominecraft.views; 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.C;
import org.jackhuang.hellominecraft.HMCLog;
import org.jackhuang.hellominecraft.logging.Level;
import org.jackhuang.hellominecraft.utils.functions.NonFunction; import org.jackhuang.hellominecraft.utils.functions.NonFunction;
import org.jackhuang.hellominecraft.utils.DoubleOutputStream; import org.jackhuang.hellominecraft.utils.DoubleOutputStream;
import org.jackhuang.hellominecraft.utils.LauncherPrintStream; import org.jackhuang.hellominecraft.utils.LauncherPrintStream;
import org.jackhuang.hellominecraft.utils.StrUtils; import org.jackhuang.hellominecraft.utils.LogWindowOutputStream;
import org.jackhuang.hellominecraft.utils.TextComponentOutputStream;
import org.jackhuang.hellominecraft.utils.Utils; import org.jackhuang.hellominecraft.utils.Utils;
/** /**
@ -44,11 +49,10 @@ public class LogWindow extends javax.swing.JFrame {
movingEnd = true; movingEnd = true;
setLocationRelativeTo(null); setLocationRelativeTo(null);
txtLog.setEditable(false);
TextComponentOutputStream tc = new TextComponentOutputStream(txtLog); DoubleOutputStream out = new DoubleOutputStream(new LogWindowOutputStream(this, Level.INFO), System.out);
DoubleOutputStream out = new DoubleOutputStream(tc, System.out);
System.setOut(new LauncherPrintStream(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)); System.setErr(new LauncherPrintStream(err));
} }
@ -63,8 +67,6 @@ public class LogWindow extends javax.swing.JFrame {
// <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
private void initComponents() { private void initComponents() {
jScrollPane1 = new javax.swing.JScrollPane();
txtLog = new javax.swing.JTextArea();
btnClear = new javax.swing.JButton(); btnClear = new javax.swing.JButton();
btnClose = new javax.swing.JButton(); btnClose = new javax.swing.JButton();
btnCopy = 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(); btnMCF = new javax.swing.JButton();
btnTerminateGame = new javax.swing.JButton(); btnTerminateGame = new javax.swing.JButton();
btnGitHub = 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); setDefaultCloseOperation(javax.swing.WindowConstants.DISPOSE_ON_CLOSE);
setTitle(C.I18N.getString("logwindow.title")); // NOI18N 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.setText(C.I18N.getString("ui.button.clear")); // NOI18N
btnClear.addActionListener(new java.awt.event.ActionListener() { btnClear.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) { 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()); javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
getContentPane().setLayout(layout); getContentPane().setLayout(layout);
layout.setHorizontalGroup( layout.setHorizontalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup() .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup()
.addContainerGap() .addContainerGap()
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING)
.addComponent(jScrollPane1) .addComponent(jScrollPane2)
.addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup() .addGroup(layout.createSequentialGroup()
.addComponent(btnTieBa) .addComponent(btnTieBa)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(btnMCBBS) .addComponent(btnMCBBS)
@ -170,7 +171,7 @@ public class LogWindow extends javax.swing.JFrame {
.addComponent(btnClear) .addComponent(btnClear)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(btnClose)) .addComponent(btnClose))
.addComponent(lblCrash, javax.swing.GroupLayout.DEFAULT_SIZE, 674, Short.MAX_VALUE)) .addComponent(lblCrash, javax.swing.GroupLayout.Alignment.LEADING))
.addContainerGap()) .addContainerGap())
); );
layout.setVerticalGroup( layout.setVerticalGroup(
@ -179,7 +180,7 @@ public class LogWindow extends javax.swing.JFrame {
.addContainerGap() .addContainerGap()
.addComponent(lblCrash, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) .addComponent(lblCrash, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .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) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
.addComponent(btnClear) .addComponent(btnClear)
@ -235,19 +236,28 @@ public class LogWindow extends javax.swing.JFrame {
}//GEN-LAST:event_btnGitHubActionPerformed }//GEN-LAST:event_btnGitHubActionPerformed
public void log(String status) { public void log(String status) {
String text = txtLog.getText(); log(status, Level.INFO);
text += status + System.getProperty("line.separator");
txtLog.setText(text);
if (movingEnd) {
int position = text.length();
txtLog.setCaretPosition(position);
}
} }
public void log(String status, Throwable t) { public void warning(String status) {
log(status); log(status, Level.WARN);
log(StrUtils.getStackTrace(t)); }
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 = d.getLength();
txtLog.setCaretPosition(position);
}
} }
public void setExit(NonFunction<Boolean> exit) { public void setExit(NonFunction<Boolean> exit) {
@ -306,8 +316,8 @@ public class LogWindow extends javax.swing.JFrame {
private javax.swing.JButton btnMCF; private javax.swing.JButton btnMCF;
private javax.swing.JButton btnTerminateGame; private javax.swing.JButton btnTerminateGame;
private javax.swing.JButton btnTieBa; private javax.swing.JButton btnTieBa;
private javax.swing.JScrollPane jScrollPane1; private javax.swing.JScrollPane jScrollPane2;
private javax.swing.JLabel lblCrash; private javax.swing.JLabel lblCrash;
private javax.swing.JTextArea txtLog; private javax.swing.JTextPane txtLog;
// End of variables declaration//GEN-END:variables // End of variables declaration//GEN-END:variables
} }

View File

@ -63,10 +63,10 @@ public class Main {
HMCLog.err("There's something wrong when running server holder.", t); HMCLog.err("There's something wrong when running server holder.", t);
LogWindow.instance.clean(); LogWindow.instance.clean();
LogWindow.instance.log("开服器崩溃了QAQ"); LogWindow.instance.warning("开服器崩溃了QAQ");
StringWriter trace = new StringWriter(); StringWriter trace = new StringWriter();
t.printStackTrace(new PrintWriter(trace)); t.printStackTrace(new PrintWriter(trace));
LogWindow.instance.log(trace.toString()); LogWindow.instance.warning(trace.toString());
LogWindow.instance.setVisible(true); LogWindow.instance.setVisible(true);
System.exit(-1); System.exit(-1);