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