Package hirondelle.web4j.webmaster

Source Code of hirondelle.web4j.webmaster.LoggingConfigImpl$TimeSensitiveFormatter

package hirondelle.web4j.webmaster;

import static hirondelle.web4j.util.Consts.FILE_SEPARATOR;
import static hirondelle.web4j.util.Consts.NOT_FOUND;
import hirondelle.web4j.BuildImpl;
import hirondelle.web4j.model.AppException;
import hirondelle.web4j.readconfig.InitParam;
import hirondelle.web4j.util.TimeSource;
import hirondelle.web4j.util.Util;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.TimeZone;
import hirondelle.web4j.model.DateTime;
import java.util.List;
import java.util.StringTokenizer;
import java.util.logging.FileHandler;
import java.util.logging.Handler;
import java.util.logging.Level;
import java.util.logging.LogRecord;
import java.util.logging.Logger;
import java.util.logging.SimpleFormatter;

import javax.servlet.ServletConfig;

/**
Default implementation of {@link LoggingConfig}, to set up simple logging.
<P>This implementation uses JDK logging, and appends logging output to a single file,
with no size limit on the file. It uses two settings in <tt>web.xml</tt> :
<ul>
<li><tt>LoggingDirectory</tt> - the absolute directory which will hold the logging
output file. This class will always use a file name using the system date/time, as
returned by {@link DateTime#now(TimeZone)} using the <tt>DefaultUserTimeZone</tt> setting in
<tt>web.xml</tt>, in the form <tt>2007_12_31_59_59.txt</tt>. If the directory does not exist, WEB4J will
attempt to create it upon startup. If set to the special value of <tt>'NONE'</tt>, then
this class will not configure JDK logging in any way.
<li><tt>LoggingLevels</tt> - a comma-separated list of logger names and their corresponding
levels. To verify operation, this class will emit test logging entries for each of these loggers,
at the stated logging levels.
</ul>
*/
public final class LoggingConfigImpl implements LoggingConfig {

  /** See class comment.   */
  public void setup(ServletConfig aConfig) throws AppException {
    fLogger.config("Fetching logging settings from web.xml");
    fetchSettings(aConfig);
    if( isTurnedOff() ) {
      logStdOut("Default logging config is turned off, since directory is set to " + Util.quote(NONE));
    }
    else {
      logStdOut("Setting up logging config...");
      validateDirectorySetting();
      parseLoggers();
      createFileHandler();
      attachLoggersToFileHandler();
      tryTestMessages();
      fLogger.config("Logging to directory : " + Util.quote(fLoggingDir.getValue()));
      DateTime now = DateTime.now(getTimeZone());
      fLogger.config("Current date-time: " + now.format("YYYY-MM-DD hh:mm:ss.fffffffff") + " (uses your TimeSource implementation and the DefaultUserTimeZone setting in web.xml)");
      fLogger.config("Raw value of System.currentTimeMillis(): " + System.currentTimeMillis());
      showLoggerLevels();
    }
  }

  // PRIVATE //
  private static final int NO_SIZE_LIMIT = 0;
  private static final int MAX_BYTES = NO_SIZE_LIMIT;
  private static final int NUM_FILES = 1;
  private static final boolean APPEND_TO_EXISTING = true;
  private static final String NONE = "NONE";
  private static final String SEPARATOR = "=";
  private InitParam fLoggingDir = new InitParam("LoggingDirectory", NONE);
  private InitParam fLoggingLevels = new InitParam("LoggingLevels", "hirondelle.web4j.level=CONFIG");
  private InitParam fDefaultTimeZone = new InitParam("DefaultUserTimeZone", "GMT");
 
  /** List of loggers. Each Logger stores its own Level as part of its state.  */
  private final List<Logger> fLoggers = new ArrayList<Logger>();
  private FileHandler fHandler;
  private static final Logger fLogger = Util.getLogger(LoggingConfigImpl.class);
 
  private void fetchSettings(ServletConfig aConfig){
    //InitParam objects are immutable
    fLoggingDir = fLoggingDir.fetch(aConfig);
    fLoggingLevels = fLoggingLevels.fetch(aConfig);
    fDefaultTimeZone = fDefaultTimeZone.fetch(aConfig);
    logStdOut("Logging directory from web.xml : " + Util.quote(fLoggingDir.getValue()));
    logStdOut("Logging levels from web.xml : " + Util.quote(fLoggingLevels.getValue()));
  }
 
  private boolean isTurnedOff(){
    return NONE.equalsIgnoreCase(fLoggingDir.getValue());
  }
 
  private void validateDirectorySetting() {
    if( ! fLoggingDir.getValue().endsWith(FILE_SEPARATOR) ){
      String message = "*** PROBLEM *** LoggingDirectory setting in web.xml does not end in with a directory separator : " + Util.quote(fLoggingDir.getValue());
      logStdOut(message);
      throw new IllegalArgumentException(message);
    }
    if( ! targetDirectoryExists() ){
      String message = "LoggingDirectory setting in web.xml does not refer to an existing, writable directory. Will attempt to create directory : " + Util.quote(fLoggingDir.getValue());
      logStdOut(message);
      File directory = new File(fLoggingDir.getValue());
      boolean success = directory.mkdirs();
      if (success) {
        logStdOut("Directory created successfully");
      }
      else {
        logStdOut("*** PROBLEM *** : Unable to create LoggingDirectory specified in web.xml! Permissions problem? Directory already exists, but not writable?");
      }
    }
  }
 
  private void parseLoggers(){
    StringTokenizer parser = new StringTokenizer(fLoggingLevels.getValue(), ",");
    while ( parser.hasMoreElements() ){
      String rawItem = (String)parser.nextElement();
      int separator = rawItem.indexOf(SEPARATOR);
      String logger = rawItem.substring(0, separator).trim();
      String level = rawItem.substring(separator + 1).trim();
      addLogger(removeSuffix(logger), level);
    }
  }
 
  private String removeSuffix(String aLogger){
    int suffix = aLogger.indexOf(".level");
    if ( suffix == NOT_FOUND ) {
      throw new IllegalArgumentException("*** PROBLEM *** LoggingLevels setting in web.xml does not end with '.level'");
    }
    return aLogger.substring(0, suffix);
  }
 
  private void addLogger(String aLogger, String aLevel){
    if( ! Util.textHasContent(aLogger) ){
      throw new IllegalArgumentException("Logger name specified in web.xml has no content.");
    }
    Logger logger = Logger.getLogger(aLogger); //creates Logger if does not yet exist
    logger.setLevel(Level.parse(aLevel));
    fLogger.config("Adding Logger " + Util.quote(logger.getName() ) + " with level " + Util.quote(logger.getLevel()) );
    fLoggers.add(logger);
  }
 
  private void createFileHandler() throws AppException {
    try {
      fHandler = new FileHandler(getFileName(), MAX_BYTES, NUM_FILES, APPEND_TO_EXISTING);
      fHandler.setLevel(Level.FINEST);
      fHandler.setFormatter(new TimeSensitiveFormatter());
    }
    catch (IOException ex){
      throw new AppException("Cannot create FileHandler: " + ex.toString() , ex);
    }
  }
 
  private void attachLoggersToFileHandler(){
    for (Logger logger: fLoggers){
      if( hasNoFileHandler(logger) ){
        logger.addHandler(fHandler);
      }
    }
  }
 
  private boolean hasNoFileHandler(Logger aLogger){
    boolean result = true;
    Handler[] handlers = aLogger.getHandlers();
    fLogger.config("Logger " + aLogger.getName() + " has this many existing handlers: " + handlers.length);
    for (int idx = 0; idx < handlers.length; ++idx){
      if ( FileHandler.class.isAssignableFrom(handlers[idx].getClass()) ){
        fLogger.config("FileHandler already exists for Logger " + Util.quote(aLogger.getName()) + ". Will not add a new one.");
        result = false;
        break;
      }
    }
    return result;
  }
 
  /** Log a test message at each logger's configured level. */
  private void tryTestMessages(){
    logStdOut("Sending test messages to configured loggers. Please confirm output to above log file.");
    for(Logger logger: fLoggers){
      logger.log(logger.getLevel(), "This is a test message for Logger " + Util.quote(logger.getName()));
    }
  }

  /**
   Return the complete name of the logging file.
   Example file name : <tt>C:\log\fish_and_chips\2007_12_31_23_59.txt</tt>
  */
  private String getFileName(){
    String result = null;
    DateTime now = DateTime.now(getTimeZone());
    result = fLoggingDir.getValue() + now.format("YYYY|_|MM|_|DD|_|hh|_|mm");
    result = result + ".txt";
    logStdOut("Logging file name : " + Util.quote(result));
    return result;
  }
 
  private boolean targetDirectoryExists(){
    File directory = new File(fLoggingDir.getValue());
    return directory.exists() && directory.isDirectory() && directory.canWrite();
  }
 
  private void logStdOut(Object aObject){
    String message = String.valueOf(aObject);
    System.out.println(message);
  }
 
  private void showLoggerLevels() {
    for(Logger logger : fLoggers){
      fLogger.config("Logger " + logger.getName() + " has level " + logger.getLevel());
    }
  }
 
  private static final class TimeSensitiveFormatter extends SimpleFormatter {
    @Override public String format(LogRecord aLogRecord) {
      aLogRecord.setMillis(fTimeSource.currentTimeMillis());
      return super.format(aLogRecord);
    }
    private TimeSource fTimeSource = BuildImpl.forTimeSource();
  }
 
  private TimeZone getTimeZone(){
    return TimeZone.getTimeZone(fDefaultTimeZone.getValue());
  }
}
TOP

Related Classes of hirondelle.web4j.webmaster.LoggingConfigImpl$TimeSensitiveFormatter

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.