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