001 package cpw.mods.fml.relauncher;
002
003 import java.io.ByteArrayOutputStream;
004 import java.io.File;
005 import java.io.IOException;
006 import java.io.PrintStream;
007 import java.util.concurrent.Executors;
008 import java.util.concurrent.LinkedBlockingQueue;
009 import java.util.logging.ConsoleHandler;
010 import java.util.logging.FileHandler;
011 import java.util.logging.Handler;
012 import java.util.logging.Level;
013 import java.util.logging.LogManager;
014 import java.util.logging.LogRecord;
015 import java.util.logging.Logger;
016
017 public class FMLRelaunchLog
018 {
019
020 private static class ConsoleLogWrapper extends Handler
021 {
022 @Override
023 public void publish(LogRecord record)
024 {
025 boolean currInt = Thread.interrupted();
026 try
027 {
028 ConsoleLogThread.recordQueue.put(record);
029 }
030 catch (InterruptedException e)
031 {
032 e.printStackTrace(errCache);
033 }
034 if (currInt)
035 {
036 Thread.currentThread().interrupt();
037 }
038 }
039
040 @Override
041 public void flush()
042 {
043
044 }
045
046 @Override
047 public void close() throws SecurityException
048 {
049 }
050
051 }
052 private static class ConsoleLogThread implements Runnable
053 {
054 static ConsoleHandler wrappedHandler = new ConsoleHandler();
055 static LinkedBlockingQueue<LogRecord> recordQueue = new LinkedBlockingQueue<LogRecord>();
056 @Override
057 public void run()
058 {
059 do
060 {
061 LogRecord lr;
062 try
063 {
064 lr = recordQueue.take();
065 wrappedHandler.publish(lr);
066 }
067 catch (InterruptedException e)
068 {
069 e.printStackTrace(errCache);
070 Thread.interrupted();
071 // Stupid
072 }
073 }
074 while (true);
075 }
076 }
077 private static class LoggingOutStream extends ByteArrayOutputStream
078 {
079 private Logger log;
080 private StringBuilder currentMessage;
081
082 public LoggingOutStream(Logger log)
083 {
084 this.log = log;
085 this.currentMessage = new StringBuilder();
086 }
087
088 @Override
089 public void flush() throws IOException
090 {
091 String record;
092 synchronized(FMLRelaunchLog.class)
093 {
094 super.flush();
095 record = this.toString();
096 super.reset();
097
098 currentMessage.append(record.replace(FMLLogFormatter.LINE_SEPARATOR, "\n"));
099 if (currentMessage.lastIndexOf("\n")>=0)
100 {
101 // Are we longer than just the line separator?
102 if (currentMessage.length()>1)
103 {
104 // Trim the line separator
105 currentMessage.setLength(currentMessage.length()-1);
106 log.log(Level.INFO, currentMessage.toString());
107 }
108 currentMessage.setLength(0);
109 }
110 }
111 }
112 }
113 /**
114 * Our special logger for logging issues to. We copy various assets from the
115 * Minecraft logger to acheive a similar appearance.
116 */
117 public static FMLRelaunchLog log = new FMLRelaunchLog();
118
119 static File minecraftHome;
120 private static boolean configured;
121
122 private static Thread consoleLogThread;
123
124 private static PrintStream errCache;
125 private Logger myLog;
126
127 private FMLRelaunchLog()
128 {
129 }
130 /**
131 * Configure the FML logger
132 */
133 private static void configureLogging()
134 {
135 LogManager.getLogManager().reset();
136 Logger globalLogger = Logger.getLogger(Logger.GLOBAL_LOGGER_NAME);
137 globalLogger.setLevel(Level.OFF);
138
139 log.myLog = Logger.getLogger("ForgeModLoader");
140
141 Logger stdOut = Logger.getLogger("STDOUT");
142 stdOut.setParent(log.myLog);
143 Logger stdErr = Logger.getLogger("STDERR");
144 stdErr.setParent(log.myLog);
145 FMLLogFormatter formatter = new FMLLogFormatter();
146
147 // Console handler captures the normal stderr before it gets replaced
148 log.myLog.setUseParentHandlers(false);
149 log.myLog.addHandler(new ConsoleLogWrapper());
150 consoleLogThread = new Thread(new ConsoleLogThread());
151 consoleLogThread.start();
152 ConsoleLogThread.wrappedHandler.setLevel(Level.parse(System.getProperty("fml.log.level","INFO")));
153 ConsoleLogThread.wrappedHandler.setFormatter(formatter);
154 log.myLog.setLevel(Level.ALL);
155 try
156 {
157 File logPath = new File(minecraftHome, FMLRelauncher.logFileNamePattern);
158 FileHandler fileHandler = new FileHandler(logPath.getPath(), 0, 3);
159 fileHandler.setFormatter(formatter);
160 fileHandler.setLevel(Level.ALL);
161 log.myLog.addHandler(fileHandler);
162 }
163 catch (Exception e)
164 {
165 }
166
167 // Set system out to a log stream
168 errCache = System.err;
169
170 System.setOut(new PrintStream(new LoggingOutStream(stdOut), true));
171 System.setErr(new PrintStream(new LoggingOutStream(stdErr), true));
172
173 // Reset global logging to shut up other logging sources (thanks guava!)
174 configured = true;
175 }
176
177 public static void log(Level level, String format, Object... data)
178 {
179 if (!configured)
180 {
181 configureLogging();
182 }
183 log.myLog.log(level, String.format(format, data));
184 }
185
186 public static void log(Level level, Throwable ex, String format, Object... data)
187 {
188 if (!configured)
189 {
190 configureLogging();
191 }
192 log.myLog.log(level, String.format(format, data), ex);
193 }
194
195 public static void severe(String format, Object... data)
196 {
197 log(Level.SEVERE, format, data);
198 }
199
200 public static void warning(String format, Object... data)
201 {
202 log(Level.WARNING, format, data);
203 }
204
205 public static void info(String format, Object... data)
206 {
207 log(Level.INFO, format, data);
208 }
209
210 public static void fine(String format, Object... data)
211 {
212 log(Level.FINE, format, data);
213 }
214
215 public static void finer(String format, Object... data)
216 {
217 log(Level.FINER, format, data);
218 }
219
220 public static void finest(String format, Object... data)
221 {
222 log(Level.FINEST, format, data);
223 }
224 public Logger getLogger()
225 {
226 return myLog;
227 }
228 }