001 package org.hackystat.utilities.logger; 002 003 import java.io.File; 004 import java.io.IOException; 005 import java.util.logging.ConsoleHandler; 006 import java.util.logging.FileHandler; 007 import java.util.logging.Handler; 008 import java.util.logging.Level; 009 import java.util.logging.LogManager; 010 import java.util.logging.Logger; 011 012 import org.hackystat.utilities.home.HackystatUserHome; 013 014 015 /** 016 * Supports logging of informational and error messages by a service. 017 * Uses HackystatUserHome.getHome() to determine where to put the logs directory. 018 * @author Philip Johnson 019 */ 020 public final class HackystatLogger { 021 022 023 /** 024 * Create a new Logger for Hackystat. 025 * 026 * @param loggerName The name of the logger to create. 027 * @param subdir If non-null, then logging files are placed in .hackystat/[subdir]/logs. 028 * Otherwise they are placed in .hackystat/logs. 029 * @param hasConsole If true, then a ConsoleHandler is created. 030 */ 031 private HackystatLogger(String loggerName, String subdir, boolean hasConsole) { 032 Logger logger = Logger.getLogger(loggerName); 033 logger.setUseParentHandlers(false); 034 035 // Define a file handler that writes to the ~/.hackystat/logs directory, creating it if nec. 036 String logSubDir = (subdir == null) ? ".hackystat/logs/" : ".hackystat/" + subdir + "/logs/"; 037 File logDir = new File(HackystatUserHome.getHome(), logSubDir); 038 boolean dirsOk = logDir.mkdirs(); 039 if (!dirsOk && !logDir.exists()) { 040 throw new RuntimeException("mkdirs() failed"); 041 } 042 String fileName = logDir + "/" + loggerName + ".%g.%u.log"; 043 FileHandler fileHandler; 044 try { 045 fileHandler = new FileHandler(fileName, 500000, 10, true); 046 fileHandler.setFormatter(new OneLineFormatter()); 047 logger.addHandler(fileHandler); 048 } 049 catch (IOException e) { 050 throw new RuntimeException("Could not open the log file for this Hackystat service.", e); 051 } 052 053 // Define a console handler to also write the message to the console. 054 if (hasConsole) { 055 ConsoleHandler consoleHandler = new ConsoleHandler(); 056 consoleHandler.setFormatter(new OneLineFormatter()); 057 logger.addHandler(consoleHandler); 058 } 059 setLoggingLevel(logger, "INFO"); 060 } 061 062 063 /** 064 * Return the Hackystat Logger named with loggerName, creating it if it does not yet exist. 065 * Hackystat loggers have the following characteristics: 066 * <ul> 067 * <li> Log messages are one line and are prefixed with a time stamp using the OneLineFormatter 068 * class. 069 * <li> The logger creates a Console logger and a File logger. 070 * <li> The File logger is written out to the ~/.hackystat/logs/ directory, creating this if 071 * it is not found. 072 * <li> The File log name is {name}.%u.log. 073 * </ul> 074 * @param loggerName The name of this HackystatLogger. 075 * @return The Logger instance. 076 */ 077 public static Logger getLogger(String loggerName) { 078 return HackystatLogger.getLogger(loggerName, null, true); 079 } 080 081 /** 082 * Return the Hackystat Logger named with loggerName, creating it if it does not yet exist. 083 * Hackystat loggers have the following characteristics: 084 * <ul> 085 * <li> Log messages are one line and are prefixed with a time stamp using the OneLineFormatter 086 * class. 087 * <li> The logger creates a Console logger and a File logger. 088 * <li> The File logger is written out to the ~/.hackystat/[subDir]/logs/ directory, creating 089 * this if it is not found. 090 * <li> The File log name is {name}.%u.log. 091 * </ul> 092 * @param loggerName The name of this HackystatLogger. 093 * @param subDir The .hackystat subdirectory in which the log/ directory should be put. 094 * @return The Logger instance. 095 */ 096 public static Logger getLogger(String loggerName, String subDir) { 097 return getLogger(loggerName, subDir, true); 098 } 099 100 /** 101 * Return the Hackystat Logger named with loggerName, creating it if it does not yet exist. 102 * Hackystat loggers have the following characteristics: 103 * <ul> 104 * <li> Log messages are one line and are prefixed with a time stamp using the OneLineFormatter 105 * class. 106 * <li> The logger creates a File logger. 107 * <li> The File logger is written out to the ~/.hackystat/[subDir]/logs/ directory, creating 108 * this if it is not found. 109 * <li> The File log name is {name}.%g.%u.log. 110 * <li> There is also a ConsoleHandler (if hasConsole is true). 111 * </ul> 112 * @param loggerName The name of this HackystatLogger. 113 * @param subDir The .hackystat subdirectory in which the log/ directory should be put. 114 * @param hasConsole If true, then a ConsoleHandler is created. 115 * @return The Logger instance. 116 */ 117 public static Logger getLogger(String loggerName, String subDir, boolean hasConsole) { 118 Logger logger = LogManager.getLogManager().getLogger(loggerName); 119 if (logger == null) { 120 new HackystatLogger(loggerName, subDir, hasConsole); 121 } 122 return LogManager.getLogManager().getLogger(loggerName); 123 } 124 125 126 /** 127 * Sets the logging level to be used for this Hackystat logger. 128 * If the passed string cannot be parsed into a Level, then INFO is set by default. 129 * @param logger The logger whose level is to be set. 130 * @param level The new Level. 131 */ 132 public static void setLoggingLevel(Logger logger, String level) { 133 Level newLevel = Level.INFO; 134 try { 135 newLevel = Level.parse(level); 136 } 137 catch (Exception e) { 138 logger.info("Couldn't set Logging level to: " + level); 139 } 140 logger.setLevel(newLevel); 141 for (Handler handler : logger.getHandlers()) { 142 handler.setLevel(newLevel); 143 } 144 } 145 } 146