/******************************************************************************* * Copyright 2012 Pradeep Nambiar, Pexus LLC * * Source File: src/org/perf/log/app/logger/DefaultSampleAppLoggerImpl.java * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. ******************************************************************************/ package org.perf.log.app.logger; import java.io.File; import java.io.IOException; import java.text.MessageFormat; import java.text.SimpleDateFormat; import java.util.Properties; import java.util.logging.*; import org.perf.log.context.PerfLogContextHelper; import org.perf.log.logger.PerfLogMessageFormatter; import org.perf.log.utils.JvmCloneGetterFactory; import org.perf.log.utils.PropertyFileLoader; public class AppLoggerImpl implements org.perf.log.app.logger.Logger { // Create a java.util.logggin.Logger // This can be used to leverage J2EE container log level control e.g. in // WebSphere private java.util.logging.Logger javaUtilLogger = null; private String loggerName; private static boolean propertiesInited = false; private static String logDestination = "console"; private static String logFileRootDir = null; private static int logFileNumToKeep = 2; private static String logFileName = "appLogFile"; private static int logFileMaxSize = 2097152; // 2MB private static String logFileInitialLevel = "info"; private static boolean useAsynchronousLogging=false; private static final String PROP_LOG_DESTINATION = "logDestination"; private static final String PROP_LOGFILE_ROOT_DIR = "logFileRootDir"; private static final String PROP_LOGFILE_MAX_SIZE = "logFileMaxSize"; private static final String PROP_LOGFILE_NUM_TO_KEEP = "logFileNumToKeep"; private static final String PROP_LOGFILE_NAME = "logFileName"; private static final String PROP_LOGFILE_INITIAL_LEVEL = "logFileInitialLevel"; private static final String PROP_USE_ASYNCHRONOUS_LOGGING = "useAsynchronousLogging"; private static ConsoleHandler consoleHandler = null; private static FileHandler fileHandler = null; private static CommonJAsyncThreadLogger asyncLogger = null; //private static boolean javaUtilLoggerInited = false; private Level getInitialJDKLoggerLevel() { // valid initial level values : warn trace info error debug off String levelStr = getLogFileInitialLevel(); if (levelStr.equalsIgnoreCase("info")) return Level.INFO; else if (levelStr.equalsIgnoreCase("warn")) return Level.WARNING; else if (levelStr.equalsIgnoreCase("debug")) return Level.FINEST; else if (levelStr.equalsIgnoreCase("trace")) return Level.FINER; else if (levelStr.equalsIgnoreCase("error")) return Level.SEVERE; else if (levelStr.equalsIgnoreCase("off")) return Level.OFF; else return Level.INFO; } private ConsoleHandler getConsoleHandler() { if(consoleHandler == null ) { consoleHandler = new java.util.logging.ConsoleHandler(); consoleHandler.setFormatter(new AppLogMessageFormatter( new MessageFormat("{0}\n"))); } return consoleHandler; } private FileHandler getFileHandler() { if (fileHandler == null) { String fullLogFileName = getLogFileName(); String logRootForThisJVM = getLogRootDirForThisJVM(); File f = new File(logRootForThisJVM); if (!f.exists()) { f.mkdirs(); } if (getLogFileName() != null) { fullLogFileName = fullLogFileName.trim(); if (!fullLogFileName.endsWith(".log")) { fullLogFileName = fullLogFileName.concat("%g%u.log"); } else { fullLogFileName = fullLogFileName.substring(0, fullLogFileName.indexOf(".log")); fullLogFileName = fullLogFileName.concat("%g%u.log"); } } fullLogFileName = logRootForThisJVM + "/" + fullLogFileName; try { fileHandler = new FileHandler(fullLogFileName, getLogFileMaxSize(), getLogFileNumToKeep(), true); fileHandler.setFormatter(new PerfLogMessageFormatter( new MessageFormat("{0}\n"))); } catch (IOException ioException) { System.out .println("IO Exception during initializing app log file:" + fullLogFileName + ", will use console handler" + ioException.getMessage()); return null; } System.out.println(AppLoggerImpl.class.getName()+":Application Log File opened for logging:"+fullLogFileName); } return fileHandler; } private synchronized void initJavaUtilLogger(String loggerName) { initProperties(); javaUtilLogger = java.util.logging.Logger.getLogger(loggerName); // This is a sample implementation. Get the initial level from // values initialized from properties file // If running in WebSphere Environment, the levels can also be // changed // from WAS console if required // Navigate to Troubleshooting -> Logs and Traces -> <server> // and // Change Log Level Details // and look for org.perf.log.logger.LoggerImpl javaUtilLogger.setLevel(getInitialJDKLoggerLevel()); if (getLogDestination().equalsIgnoreCase("console")) { ConsoleHandler consoleHandler = getConsoleHandler(); javaUtilLogger.addHandler(consoleHandler); } else { FileHandler fileHandler = getFileHandler(); if (fileHandler == null) { ConsoleHandler consoleHandler = getConsoleHandler(); javaUtilLogger.addHandler(consoleHandler); } else { javaUtilLogger.addHandler(fileHandler); } } javaUtilLogger.setUseParentHandlers(false); } public AppLoggerImpl(String loggerName) { super(); initJavaUtilLogger(loggerName); this.loggerName = loggerName; } @Override public void debug(String msg) { log(Level.FINEST, "DEBUG", msg, null); } @Override public void debug(String msg, Throwable t) { log(Level.FINEST, "DEBUG", msg, t); } @Override public void error(String msg) { log(Level.SEVERE, "ERROR", msg, null); } @Override public void error(String msg, Throwable t) { log(Level.SEVERE, "ERROR", msg, t); } @Override public void info(String msg) { log(Level.INFO, "INFO", msg, null); } @Override public void info(String msg, Throwable t) { log(Level.INFO, "INFO", msg, t); } @Override public void trace(String msg) { log(Level.FINE, "TRACE", msg, null); } @Override public void trace(String msg, Throwable t) { log(Level.FINE, "TRACE", msg, t); } @Override public void warn(String msg) { log(Level.WARNING, "WARNING", msg, null); } @Override public void warn(String msg, Throwable t) { log(Level.WARNING, "WARNING", msg, t); } /** * This is our internal implementation for logging regular * (non-parameterized) log messages. * * @param level * @param message * @param t */ private void log(Level javaUtilLoggerLevel, String appLoggerLevelStr, String message, Throwable t) { StringBuffer buf = new StringBuffer(); SimpleDateFormat sdf = new SimpleDateFormat("MM/dd/yy HH:mm:ss:SSS z"); String formattedTransactionDate = null; formattedTransactionDate = "[" + sdf.format(new java.util.Date()) + "]"; buf.append(formattedTransactionDate); buf.append(" "); buf.append(appLoggerLevelStr); buf.append(" "); buf.append(loggerName); buf.append(" - "); buf.append(PerfLogContextHelper.getBaseAndInfoContextString()); buf.append(message); if (javaUtilLogger.isLoggable(javaUtilLoggerLevel)) { if(isUseAsynchronousLogging()) { AppLogData appLogData = new AppLogData(); appLogData.setJavaUtilLogger(javaUtilLogger); appLogData.setJavaUtilLoggerLevel(javaUtilLoggerLevel); appLogData.setLogData(buf.toString()); appLogData.setThrowable(t); asyncLogger.log(appLogData); } else { if (t != null) { javaUtilLogger.log(javaUtilLoggerLevel, buf.toString(), t); } else javaUtilLogger.log(javaUtilLoggerLevel, buf.toString()); } } else { // Cache the trace data in the debug context // This would be useful for diagnosis when the context data // is dumped when there is error or response time exceeds a defined // threshold PerfLogContextHelper.addToDebugContext("trace", buf.toString()); } // Dump the context data when there is an error // and throwable is not null if (javaUtilLogger.isLoggable(javaUtilLoggerLevel) && javaUtilLoggerLevel == Level.SEVERE && t!=null) { PerfLogContextHelper.dumpPerfLogContext(javaUtilLogger); } } public String getLoggerName() { return loggerName; } @Override public void setLoggerName(String loggerName) { this.loggerName = loggerName; } @Override public void setLevel(Level level) { if (javaUtilLogger != null) javaUtilLogger.setLevel(level); } private synchronized static void initProperties() { if (!propertiesInited) { try { String propVal; ClassLoader ctxClassLoader = Thread.currentThread().getContextClassLoader(); Properties props = PropertyFileLoader.load( "perfLogAppLogger.properties", "perfLogAppLogerDefault.properties", ctxClassLoader, AppLoggerImpl.class.getClass().getClassLoader(), AppLoggerImpl.class.getName()); if (props != null) { propVal = props.getProperty(PROP_LOG_DESTINATION); if (propVal != null) setLogDestination(propVal); propVal = props.getProperty(PROP_LOGFILE_ROOT_DIR); if (propVal != null) setLogFileRootDir(propVal); propVal = props.getProperty(PROP_LOGFILE_NAME); if (propVal != null) setLogFileName(propVal); propVal = props.getProperty(PROP_LOGFILE_NUM_TO_KEEP); if (propVal != null) setLogFileNumToKeep(new Integer(propVal).intValue()); propVal = props.getProperty(PROP_LOGFILE_MAX_SIZE); if (propVal != null) setLogFileMaxSize(new Integer(propVal).intValue()); propVal = props.getProperty(PROP_LOGFILE_INITIAL_LEVEL); if (propVal != null) setLogFileInitialLevel(propVal); propVal = props.getProperty(PROP_USE_ASYNCHRONOUS_LOGGING); if(propVal!=null) setUseAsynchronousLogging(new Boolean(propVal).booleanValue()); if(isUseAsynchronousLogging()) { // create an instance of CommonJAsyncThreadLooger asyncLogger = new CommonJAsyncThreadLogger(); } } else { System.out.println(AppLoggerImpl.class.getName() + ":Error in reading perfLogAppLogger properties files"); } } catch (Exception exception) { System.out.println(AppLoggerImpl.class.getName() + ":Error Loading perfLogAppLogger properties:" + exception.getMessage()); } propertiesInited = true; } } public static String getLogFileRootDir() { return logFileRootDir; } public static String getLogRootDirForThisJVM() { // Get the File Root Dir String logFileRootDirFromProperty = getLogFileRootDir(); String logRootDir = logFileRootDirFromProperty; // append the JVM Clone name to the directory to split individually // create and log to each JVM clone's instance log file String envInstanceName = JvmCloneGetterFactory.getJvmCloneGetterImpl().getName(); if(envInstanceName!=null) { logRootDir = logRootDir+"/"+envInstanceName; } return logRootDir; } public static void setLogFileRootDir(String inLogFileRootDir) { logFileRootDir = inLogFileRootDir; } public static int getLogFileNumToKeep() { return logFileNumToKeep; } public static void setLogFileNumToKeep(int inLogFileNumToKeep) { logFileNumToKeep = inLogFileNumToKeep; } public static String getLogFileName() { return logFileName; } public static void setLogFileName(String inLogFileName) { logFileName = inLogFileName; } public static int getLogFileMaxSize() { return logFileMaxSize; } public static void setLogFileMaxSize(int inLogFileMaxSize) { logFileMaxSize = inLogFileMaxSize; } public static String getLogFileInitialLevel() { return logFileInitialLevel; } public static void setLogFileInitialLevel(String logFileInitialLevel) { AppLoggerImpl.logFileInitialLevel = logFileInitialLevel; } public static String getLogDestination() { return logDestination; } public static void setLogDestination(String logDestination) { AppLoggerImpl.logDestination = logDestination; } @Override public void fine(String msg) { log(Level.FINE, "FINE", msg, null); } @Override public void fine(String msg, Throwable t) { log(Level.FINE, "FINE", msg, t); } @Override public void finest(String msg) { log(Level.FINEST, "FINEST", msg, null); } @Override public void finest(String msg, Throwable t) { log(Level.FINEST, "FINEST", msg, t); } @Override public void severe(String msg) { log(Level.SEVERE, "SEVERE", msg, null); } @Override public void severe(String msg, Throwable t) { log(Level.SEVERE, "SEVERE", msg, t); } public static boolean isUseAsynchronousLogging() { return useAsynchronousLogging; } public static void setUseAsynchronousLogging(boolean inUseAsynchronousLogging) { useAsynchronousLogging = inUseAsynchronousLogging; } }