001package daikon; 002 003import static java.util.logging.Level.INFO; 004 005import java.util.HashSet; 006import java.util.Set; 007import java.util.logging.ConsoleHandler; 008import java.util.logging.Formatter; 009import java.util.logging.Handler; 010import java.util.logging.Level; 011import java.util.logging.LogRecord; 012import java.util.logging.Logger; 013import java.util.logging.SimpleFormatter; 014 015/** 016 * Standard methods for setting up logging. Allows creation of Console writers using one method. 017 * Logger methods should only be called in a shell class at setup, after which Logger calls should 018 * be used for logging. 019 */ 020public final class LogHelper { 021 private LogHelper() { 022 throw new Error("do not instantiate"); 023 } 024 025 /** 026 * Sets up global logs with a given priority and logging output pattern. Creates one 027 * ConsoleHandler at root to receive default messages, setting priority to INFO. Removes previous 028 * appenders at root. 029 */ 030 public static void setupLogs(Level l, Formatter formatter) { 031 // Send debug and other info messages to System.err 032 Handler app = new ConsoleHandler(); 033 app.setLevel(Level.ALL); 034 app.setFormatter(formatter); 035 036 // Logger.global.removeAllAppenders(); 037 { 038 // Java 5 version 039 @SuppressWarnings("deprecation") 040 Logger global = Logger.global; 041 // Java 6 version (doesn't work in Java 5) 042 // Logger global = Logger.getLogger(Logger.GLOBAL_LOGGER_NAME); 043 Handler[] handlers = global.getHandlers(); 044 for (Handler handler : handlers) { 045 global.removeHandler(handler); 046 } 047 } 048 049 Logger root = Logger.getLogger(""); 050 Handler[] handlers = root.getHandlers(); 051 for (Handler handler : handlers) { 052 root.removeHandler(handler); 053 } 054 root.addHandler(app); 055 root.setLevel(l); 056 allLoggers.add(root); 057 058 // Logger.global.addHandler(app); 059 // Logger.global.setLevel(l); 060 // Logger.global.fine ("Installed logger at level " + l); 061 } 062 063 public static class DaikonLogFormatter extends SimpleFormatter { 064 @Override 065 public synchronized String format(LogRecord record) { 066 // // By default, take up 20 spaces min, and 20 spaces max for logger. 067 // // %c = Logger. %m = message, %n = newline 068 // // Example output: "@ daikon.Daikon: This is a message" 069 // setupLogs (l, "@ %20.20c: %m%n"); 070 071 String loggerName = record.getLoggerName() + ":"; 072 073 // If we aren't generating tracebacks, find the src class/method/line 074 // where the log was called from 075 String src = ""; 076 if (!Debug.dkconfig_showTraceback) { 077 Throwable stack = new Throwable("debug traceback"); 078 stack.fillInStackTrace(); 079 StackTraceElement[] ste_arr = stack.getStackTrace(); 080 for (int ii = ste_arr.length - 1; ii >= 0; ii--) { 081 StackTraceElement ste = ste_arr[ii]; 082 if (ste.getClassName().startsWith("java") 083 || ste.getClassName().contains("daikon.LogHelper") 084 || ste.getMethodName().equals("log") 085 || ste.getClassName().contains("daikon.Debug")) { 086 continue; 087 } 088 src = ste.getFileName() + " " + ste.getLineNumber() + ": "; 089 } 090 } 091 // src = record.getSourceClassName().replaceAll ("\\w*\\.", "") 092 // + "." + record.getSourceMethodName() + ": "; 093 094 return "@ " + loggerName + " " + src + record.getMessage() + Global.lineSep; 095 } 096 } 097 098 /** Default method for setting up global logs. */ 099 public static void setupLogs() { 100 setupLogs(INFO); 101 } 102 103 /** 104 * Sets up global logs with a given priority. Creates one ConsoleHandler. Removes previous 105 * appenders at root. 106 */ 107 public static void setupLogs(Level l) { 108 setupLogs(l, new DaikonLogFormatter()); 109 } 110 111 private static final Set<Logger> allLoggers = new HashSet<>(); 112 113 /** 114 * Changes the logging priority of a sub category. Also caches the logger to avoid 115 * garbage-collection and recreation with the old level. 116 */ 117 public static void setLevel(Logger lg, Level l) { 118 lg.setLevel(l); 119 allLoggers.add(lg); // to prevent garbage-collection and re-initialization 120 } 121 122 /** 123 * Changes the logging priority of a sub category. Also caches the logger to avoid 124 * garbage-collection and recreation with the old level. 125 */ 126 public static void setLevel(String s, Level l) { 127 setLevel(Logger.getLogger(s), l); 128 } 129}