Java tutorial
/* * Copyright 2015 Cisco Systems, Inc. * * 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 com.cisco.oss.foundation.logging; import com.cisco.oss.foundation.flowcontext.FlowContextFactory; import com.cisco.oss.foundation.logging.structured.AbstractFoundationLoggingMarker; import org.apache.commons.lang3.StringUtils; import org.apache.log4j.*; import org.apache.log4j.helpers.Loader; import org.apache.log4j.helpers.OptionConverter; import org.apache.log4j.nt.NTEventLogAppender; import org.apache.log4j.spi.LoggerRepository; import org.apache.log4j.spi.LoggingEvent; import org.apache.log4j.spi.RepositorySelector; import org.jdom2.Document; import org.jdom2.Element; import org.jdom2.input.SAXBuilder; import org.joda.time.DateTime; import org.joda.time.DateTimeZone; import org.joda.time.format.DateTimeFormatter; import org.joda.time.format.DateTimeFormatterBuilder; import org.slf4j.Marker; import org.slf4j.helpers.FormattingTuple; import org.slf4j.helpers.MessageFormatter; import org.slf4j.spi.LocationAwareLogger; import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; import java.net.MalformedURLException; import java.net.URL; import java.text.MessageFormat; import java.util.*; import java.util.logging.ConsoleHandler; import java.util.logging.FileHandler; import java.util.logging.Handler; import java.util.logging.LogRecord; /** * This Logger implementation is used for applying the Foundation Logging standards on * top of log4j. The logger is initialized by the the FoundationLogHierarcy Object. It * is not meant to be used in code by developers. In runtime they will use this * Logger if they specify the following line in thier log4j.properties file: * log4j.loggerFactory=com.cisco.oss.foundation.logging.FoundationLogFactory * * @author Yair Ogen */ class FoundationLogger extends Logger implements LocationAwareLogger { // NOPMD /** * the property key for reloading the log4j properties file. */ private static final String Foundation_FILE_RELOAD_DELAY = "FoundationfileReloadDelay"; /** * default delay value for reloading the log4j properties file. */ private static final int FILE_RELOAD_DELAY = 10000; static Properties log4jConfigProps = null; // NOPMD private static final String DEFAULT_CONFIGURATION_FILE = "log4j.properties"; // NOPMD private static final String DEFAULT_CONFIGURATION_KEY = "log4j.configuration"; // NOPMD private static final String FQCN = FoundationLogger.class.getName(); private static final String PATTERN_KEY = "messagePattern"; public static Map<String, Map<String, Layout>> markerAppendersMap = new HashMap<String, Map<String, Layout>>(); /** * Boolean indicating whether or not NTEventLogAppender is supported. */ private static boolean ntEventLogSupported = true; FoundationLogger(final String name) { super(name); } /** * Initialize that Foundation Logging library. */ static void init() {// NOPMD determineIfNTEventLogIsSupported(); URL resource = null; final String configurationOptionStr = OptionConverter.getSystemProperty(DEFAULT_CONFIGURATION_KEY, null); if (configurationOptionStr != null) { try { resource = new URL(configurationOptionStr); } catch (MalformedURLException ex) { // so, resource is not a URL: // attempt to get the resource from the class path resource = Loader.getResource(configurationOptionStr); } } if (resource == null) { resource = Loader.getResource(DEFAULT_CONFIGURATION_FILE); // NOPMD } if (resource == null) { System.err.println("[FoundationLogger] Can not find resource: " + DEFAULT_CONFIGURATION_FILE); // NOPMD throw new FoundationIOException("Can not find resource: " + DEFAULT_CONFIGURATION_FILE); // NOPMD } // update the log manager to use the Foundation repository. final RepositorySelector foundationRepositorySelector = new FoundationRepositorySelector( FoundationLogFactory.foundationLogHierarchy); LogManager.setRepositorySelector(foundationRepositorySelector, null); // set logger to info so we always want to see these logs even if root // is set to ERROR. final Logger logger = getLogger(FoundationLogger.class); final String logPropFile = resource.getPath(); log4jConfigProps = getLogProperties(resource); // select and configure again so the loggers are created with the right // level after the repository selector was updated. OptionConverter.selectAndConfigure(resource, null, FoundationLogFactory.foundationLogHierarchy); // start watching for property changes setUpPropFileReloading(logger, logPropFile, log4jConfigProps); // add syslog appender or windows event viewer appender // setupOSSystemLog(logger, log4jConfigProps); // parseMarkerPatterns(log4jConfigProps); // parseMarkerPurePattern(log4jConfigProps); // udpateMarkerStructuredLogOverrideMap(logger); AbstractFoundationLoggingMarker.init(); updateSniffingLoggersLevel(logger); setupJULSupport(resource); } private static void setupJULSupport(URL resource) { boolean julSupportEnabled = Boolean.valueOf(log4jConfigProps .getProperty(FoundationLoggerConstants.Foundation_JUL_SUPPORT_ENABLED.toString(), "false")); if (julSupportEnabled) { String appenderRef = log4jConfigProps .getProperty(FoundationLoggerConstants.Foundation_JUL_APPENDER_REF.toString()); if (StringUtils.isBlank(appenderRef)) { Enumeration allAppenders = Logger.getRootLogger().getAllAppenders(); while (allAppenders.hasMoreElements()) { Appender appender = (Appender) allAppenders.nextElement(); if (appender instanceof FileAppender) { appenderRef = appender.getName(); getLogger(FoundationLogger.class) .info("*** Using '" + appenderRef + "' as the Java util logging appender ref ***"); System.err.println( "*** Using '" + appenderRef + "' as the Java util logging appender ref ***"); break; } } } if (StringUtils.isBlank(appenderRef)) { throw new IllegalArgumentException( "Java util support was enabled but couldn't find a matching appender under the '" + FoundationLoggerConstants.Foundation_JUL_APPENDER_REF.toString() + "' key."); } Handler handler = null; Appender appender = Logger.getRootLogger().getAppender(appenderRef); if (appender == null) { Enumeration allAppenders = Logger.getRootLogger().getAllAppenders(); while (allAppenders.hasMoreElements()) { Appender tempAppender = (Appender) allAppenders.nextElement(); if (tempAppender instanceof AsyncAppender) { AsyncAppender asyncAppender = (AsyncAppender) tempAppender; Enumeration asyncAppenderAllAppenders = asyncAppender.getAllAppenders(); while (asyncAppenderAllAppenders.hasMoreElements()) { Appender asyncTempAppender = (Appender) asyncAppenderAllAppenders.nextElement(); if (appenderRef.equals(asyncTempAppender.getName())) { appender = asyncTempAppender; break; } } if (appender != null) { break; } } } } if (appender instanceof FileAppender) { try { handler = new FileHandler(((FileAppender) appender).getFile()); } catch (IOException e) { throw new IllegalArgumentException( "IOException encountered when trying to setup jul logging: " + e, e); } } else if (appender instanceof ConsoleAppender) { handler = new ConsoleHandler(); } else { getLogger(FoundationLogger.class) .error("got a reference to an unsupported appender: " + appenderRef); } if (handler != null) { // System.setProperty("java.util.logging.config.file",resource.getPath()); java.util.logging.LogManager.getLogManager().reset(); try { java.util.logging.LogManager.getLogManager().readConfiguration(resource.openStream()); } catch (IOException e) { throw new IllegalArgumentException( "IOException encountered when trying to read log4j properties file: " + e, e); } handler.setLevel(java.util.logging.Level.FINEST); handler.setFormatter(new FoundationLogFormatter()); java.util.logging.Logger rootLogger = java.util.logging.Logger.getLogger(""); rootLogger.addHandler(handler); rootLogger.setLevel(java.util.logging.Level.SEVERE); Properties julLoggerSubset = getPropertiesSubset("jul.logger"); if (!julLoggerSubset.isEmpty()) { Set<Object> keySet = julLoggerSubset.keySet(); for (Object key : keySet) { java.util.logging.Logger logger = java.util.logging.Logger.getLogger((String) key); logger.setLevel(java.util.logging.Level.parse((String) julLoggerSubset.get(key))); } } } } } private static Properties getPropertiesSubset(String prefix) { Properties subset = new Properties(); Enumeration<Object> keys = log4jConfigProps.keys(); boolean validSubset = false; while (keys.hasMoreElements()) { Object key = keys.nextElement(); if (key instanceof String && ((String) key).startsWith(prefix)) { if (!validSubset) { validSubset = true; } /* * Check to make sure that subset.subset(prefix) doesn't * blow up when there is only a single property * with the key prefix. This is not a useful * subset but it is a valid subset. */ String newKey = null; if (((String) key).length() == prefix.length()) { newKey = prefix; } else { newKey = ((String) key).substring(prefix.length() + 1); } /* * use addPropertyDirect() - this will plug the data as * is into the Map, but will also do the right thing * re key accounting */ subset.setProperty(newKey, (String) log4jConfigProps.get(key)); } } if (validSubset) { return subset; } else { return new Properties(); } } // private static void parseMarkerPatterns(Properties properties) { // // Set<String> markerMappingKeySet = new HashSet<String>(); // // Set<String> entrySet = properties.stringPropertyNames(); // for (String key : entrySet) { // if (key.startsWith("logevent")) { // markerMappingKeySet.add(key); // } // } // // for (String key : markerMappingKeySet) { // // String[] split = key.split("\\."); // if (split.length != 4) { // throw new IllegalArgumentException("the key " + key + " does not contain a four part mapping."); // } // // String markerName = split[1]; // String appenderName = split[2]; // String pattern = properties.getProperty(key); // // if (markerAppendersMap.get(markerName) == null) { // markerAppendersMap.put(markerName, new HashMap<String, Layout>()); // } // // Map<String, Layout> markerAppenderMap = markerAppendersMap.get(markerName); // Layout patternLayout = new FoundationLoggingPatternLayout(pattern); // markerAppenderMap.put(appenderName, patternLayout); // // } // // } /** * The sniffing Loggers are some special Loggers, whose level will be set to TRACE forcedly. * @param logger */ private static void updateSniffingLoggersLevel(Logger logger) { InputStream settingIS = FoundationLogger.class.getResourceAsStream("/sniffingLogger.xml"); if (settingIS == null) { logger.debug("file sniffingLogger.xml not found in classpath"); } else { try { SAXBuilder builder = new SAXBuilder(); Document document = builder.build(settingIS); settingIS.close(); Element rootElement = document.getRootElement(); List<Element> sniffingloggers = rootElement.getChildren("sniffingLogger"); for (Element sniffinglogger : sniffingloggers) { String loggerName = sniffinglogger.getAttributeValue("id"); Logger.getLogger(loggerName).setLevel(Level.TRACE); } } catch (Exception e) { logger.error("cannot load the sniffing logger configuration file. error is: " + e, e); throw new IllegalArgumentException("Problem parsing sniffingLogger.xml", e); } } } private static void determineIfNTEventLogIsSupported() { boolean supported = true; try { new NTEventLogAppender(); } catch (Throwable t) {// NOPMD supported = false; } ntEventLogSupported = supported; } // private static void setupOSSystemLog(final Logger logger, final Properties log4jConfigProps) { // // final Layout layout = new FoundationLoggingPatternLayout(FondationLoggerConstants.DEFAULT_CONV_PATTERN.toString()); // final Logger rootLogger = LogManager.getRootLogger(); // // final OperatingSystem operatingSystem = OperatingSystem.getOperatingSystem(); // AppenderSkeleton systemLogAppender = null; // // Level defaultThreshold = Level.WARN; // if (log4jConfigProps != null && log4jConfigProps.getProperty("FoundationdefaultSystemLoggerThreshold") != null) { // defaultThreshold = Level.toLevel(log4jConfigProps.getProperty("FoundationdefaultSystemLoggerThreshold")); // } // // if (operatingSystem.equals(OperatingSystem.Windows) && ntEventLogSupported) { // // systemLogAppender = new NTEventLogAppender("Foundation Logging", layout); // systemLogAppender.setName("nteventlog"); // systemLogAppender.setThreshold(defaultThreshold); // systemLogAppender.activateOptions(); // // rootLogger.addAppender(systemLogAppender); // // } else if (operatingSystem.equals(OperatingSystem.HPUX) || operatingSystem.equals(OperatingSystem.Linux)) { // // systemLogAppender = new SyslogAppender(layout, "localhost", SyslogAppender.LOG_USER); // systemLogAppender.setName("systemlog"); // systemLogAppender.setThreshold(defaultThreshold); // systemLogAppender.activateOptions(); // // rootLogger.addAppender(systemLogAppender); // } // if (systemLogAppender == null) { // logger.error("System log appender was not initialized! Probably \"NTEventLogAppender.dll\" is not in the computer path."); // } // // } private static void setUpPropFileReloading(final Logger logger, final String logPropFile, final Properties properties) { int fileReloadDelay = FILE_RELOAD_DELAY; if (properties.containsKey(Foundation_FILE_RELOAD_DELAY)) { final String fileReloadDelayStr = properties.getProperty(Foundation_FILE_RELOAD_DELAY); try { fileReloadDelay = Integer.parseInt(fileReloadDelayStr); } catch (NumberFormatException e) { logger.error("Can not format to integer the property: " + Foundation_FILE_RELOAD_DELAY + ". using default of: " + FILE_RELOAD_DELAY); } } PropertyConfigurator.configureAndWatch(logPropFile, fileReloadDelay); } private static Properties getLogProperties(final URL logPropFileResource) { final Properties properties = new Properties(); InputStream propertiesInStream = null; final String log4jFilePath = logPropFileResource.getPath(); try { propertiesInStream = logPropFileResource.openStream(); properties.load(propertiesInStream); } catch (FileNotFoundException e) { System.err.println("[FoundationLogger] Can not find the file: " + log4jFilePath); // NOPMD throw new FoundationIOException("Can not find the file: " + log4jFilePath, e); } catch (IOException e) { System.err.println("[FoundationLogger] IO Exception during load of file: " + log4jFilePath + ". Exception is: " + e.toString()); // NOPMD throw new FoundationIOException( "IO Exception during load of file: " + log4jFilePath + ". Exception is: " + e.toString(), e); } finally { if (propertiesInStream != null) { try { propertiesInStream.close(); } catch (IOException e) { System.err.println("[FoundationLogger] IO Exception during close of file: " + log4jFilePath + ". Exception is: " + e.toString()); // NOPMD } } } return properties; } /** * Log a message object at level TRACE. * * @param msg * - the message object to be logged */ public void trace(String msg) { log(FQCN, Level.TRACE, msg, null); } /** * Log a message at level TRACE according to the specified format and * argument. * * <p> * This form avoids superfluous object creation when the logger is disabled * for level TRACE. * </p> * * @param format * the format string * @param arg * the argument */ public void trace(String format, Object arg) { if (isTraceEnabled()) { FormattingTuple ft = MessageFormatter.format(format, arg); log(FQCN, Level.TRACE, ft.getMessage(), ft.getThrowable()); } } /** * Log a message at level TRACE according to the specified format and * arguments. * * <p> * This form avoids superfluous object creation when the logger is disabled * for the TRACE level. * </p> * * @param format * the format string * @param arg1 * the first argument * @param arg2 * the second argument */ public void trace(String format, Object arg1, Object arg2) { if (isTraceEnabled()) { FormattingTuple ft = MessageFormatter.format(format, arg1, arg2); log(FQCN, Level.TRACE, ft.getMessage(), ft.getThrowable()); } } /** * Log a message at level TRACE according to the specified format and * arguments. * * <p> * This form avoids superfluous object creation when the logger is disabled * for the TRACE level. * </p> * * @param format * the format string * @param argArray * an array of arguments */ public void trace(String format, Object[] argArray) { if (isTraceEnabled()) { FormattingTuple ft = MessageFormatter.arrayFormat(format, argArray); log(FQCN, Level.TRACE, ft.getMessage(), ft.getThrowable()); } } /** * Log an exception (throwable) at level TRACE with an accompanying message. * * @param msg * the message accompanying the exception * @param t * the exception (throwable) to log */ public void trace(String msg, Throwable t) { log(FQCN, Level.TRACE, msg, t); } // /** // * Is this logger instance enabled for the DEBUG level? // * // * @return True if this Logger is enabled for level DEBUG, false // otherwise. // */ // public boolean isDebugEnabled() { // return super.isDebugEnabled(); // } /** * Log a message object at level DEBUG. * * @param msg * - the message object to be logged */ public void debug(String msg) { log(FQCN, Level.DEBUG, msg, null); } /** * Log a message at level DEBUG according to the specified format and * argument. * * <p> * This form avoids superfluous object creation when the logger is disabled * for level DEBUG. * </p> * * @param format * the format string * @param arg * the argument */ public void debug(String format, Object arg) { if (isDebugEnabled()) { FormattingTuple ft = MessageFormatter.format(format, arg); log(FQCN, Level.DEBUG, ft.getMessage(), ft.getThrowable()); } } /** * Log a message at level DEBUG according to the specified format and * arguments. * * <p> * This form avoids superfluous object creation when the logger is disabled * for the DEBUG level. * </p> * * @param format * the format string * @param arg1 * the first argument * @param arg2 * the second argument */ public void debug(String format, Object arg1, Object arg2) { if (isDebugEnabled()) { FormattingTuple ft = MessageFormatter.format(format, arg1, arg2); log(FQCN, Level.DEBUG, ft.getMessage(), ft.getThrowable()); } } /** * Log a message at level DEBUG according to the specified format and * arguments. * * <p> * This form avoids superfluous object creation when the logger is disabled * for the DEBUG level. * </p> * * @param format * the format string * @param argArray * an array of arguments */ public void debug(String format, Object[] argArray) { if (isDebugEnabled()) { FormattingTuple ft = MessageFormatter.arrayFormat(format, argArray); log(FQCN, Level.DEBUG, ft.getMessage(), ft.getThrowable()); } } /** * Log an exception (throwable) at level DEBUG with an accompanying message. * * @param msg * the message accompanying the exception * @param t * the exception (throwable) to log */ public void debug(String msg, Throwable t) { log(FQCN, Level.DEBUG, msg, t); } // /** // * Is this logger instance enabled for the INFO level? // * // * @return True if this Logger is enabled for the INFO level, false // otherwise. // */ // public boolean isInfoEnabled() { // return super.isInfoEnabled(); // } /** * Log a message object at the INFO level. * * @param msg * - the message object to be logged */ public void info(String msg) { log(FQCN, Level.INFO, msg, null); } /** * Log a message at level INFO according to the specified format and * argument. * * <p> * This form avoids superfluous object creation when the logger is disabled * for the INFO level. * </p> * * @param format * the format string * @param arg * the argument */ public void info(String format, Object arg) { if (isInfoEnabled()) { FormattingTuple ft = MessageFormatter.format(format, arg); log(FQCN, Level.INFO, ft.getMessage(), ft.getThrowable()); } } /** * Log a message at the INFO level according to the specified format and * arguments. * * <p> * This form avoids superfluous object creation when the logger is disabled * for the INFO level. * </p> * * @param format * the format string * @param arg1 * the first argument * @param arg2 * the second argument */ public void info(String format, Object arg1, Object arg2) { if (isInfoEnabled()) { FormattingTuple ft = MessageFormatter.format(format, arg1, arg2); log(FQCN, Level.INFO, ft.getMessage(), ft.getThrowable()); } } /** * Log a message at level INFO according to the specified format and * arguments. * * <p> * This form avoids superfluous object creation when the logger is disabled * for the INFO level. * </p> * * @param format * the format string * @param argArray * an array of arguments */ public void info(String format, Object[] argArray) { if (isInfoEnabled()) { FormattingTuple ft = MessageFormatter.arrayFormat(format, argArray); log(FQCN, Level.INFO, ft.getMessage(), ft.getThrowable()); } } /** * Log an exception (throwable) at the INFO level with an accompanying * message. * * @param msg * the message accompanying the exception * @param t * the exception (throwable) to log */ public void info(String msg, Throwable t) { log(FQCN, Level.INFO, msg, t); } /** * Is this logger instance enabled for the WARN level? * * @return True if this Logger is enabled for the WARN level, false * otherwise. */ public boolean isWarnEnabled() { return super.isEnabledFor(Level.WARN); } /** * Log a message object at the WARN level. * * @param msg * - the message object to be logged */ public void warn(String msg) { log(FQCN, Level.WARN, msg, null); } /** * Log a message at the WARN level according to the specified format and * argument. * * <p> * This form avoids superfluous object creation when the logger is disabled * for the WARN level. * </p> * * @param format * the format string * @param arg * the argument */ public void warn(String format, Object arg) { if (isEnabledFor(Level.WARN)) { FormattingTuple ft = MessageFormatter.format(format, arg); log(FQCN, Level.WARN, ft.getMessage(), ft.getThrowable()); } } /** * Log a message at the WARN level according to the specified format and * arguments. * * <p> * This form avoids superfluous object creation when the logger is disabled * for the WARN level. * </p> * * @param format * the format string * @param arg1 * the first argument * @param arg2 * the second argument */ public void warn(String format, Object arg1, Object arg2) { if (isEnabledFor(Level.WARN)) { FormattingTuple ft = MessageFormatter.format(format, arg1, arg2); log(FQCN, Level.WARN, ft.getMessage(), ft.getThrowable()); } } /** * Log a message at level WARN according to the specified format and * arguments. * * <p> * This form avoids superfluous object creation when the logger is disabled * for the WARN level. * </p> * * @param format * the format string * @param argArray * an array of arguments */ public void warn(String format, Object[] argArray) { if (isEnabledFor(Level.WARN)) { FormattingTuple ft = MessageFormatter.arrayFormat(format, argArray); log(FQCN, Level.WARN, ft.getMessage(), ft.getThrowable()); } } /** * Log an exception (throwable) at the WARN level with an accompanying * message. * * @param msg * the message accompanying the exception * @param t * the exception (throwable) to log */ public void warn(String msg, Throwable t) { log(FQCN, Level.WARN, msg, t); } /** * Is this logger instance enabled for level ERROR? * * @return True if this Logger is enabled for level ERROR, false otherwise. */ public boolean isErrorEnabled() { return super.isEnabledFor(Level.ERROR); } /** * Log a message object at the ERROR level. * * @param msg * - the message object to be logged */ public void error(String msg) { log(FQCN, Level.ERROR, msg, null); } /** * Log a message at the ERROR level according to the specified format and * argument. * * <p> * This form avoids superfluous object creation when the logger is disabled * for the ERROR level. * </p> * * @param format * the format string * @param arg * the argument */ public void error(String format, Object arg) { if (isEnabledFor(Level.ERROR)) { FormattingTuple ft = MessageFormatter.format(format, arg); log(FQCN, Level.ERROR, ft.getMessage(), ft.getThrowable()); } } /** * Log a message at the ERROR level according to the specified format and * arguments. * * <p> * This form avoids superfluous object creation when the logger is disabled * for the ERROR level. * </p> * * @param format * the format string * @param arg1 * the first argument * @param arg2 * the second argument */ public void error(String format, Object arg1, Object arg2) { if (isEnabledFor(Level.ERROR)) { FormattingTuple ft = MessageFormatter.format(format, arg1, arg2); log(FQCN, Level.ERROR, ft.getMessage(), ft.getThrowable()); } } /** * Log a message at level ERROR according to the specified format and * arguments. * * <p> * This form avoids superfluous object creation when the logger is disabled * for the ERROR level. * </p> * * @param format * the format string * @param argArray * an array of arguments */ public void error(String format, Object[] argArray) { if (isEnabledFor(Level.ERROR)) { FormattingTuple ft = MessageFormatter.arrayFormat(format, argArray); log(FQCN, Level.ERROR, ft.getMessage(), ft.getThrowable()); } } /** * Log an exception (throwable) at the ERROR level with an accompanying * message. * * @param msg * the message accompanying the exception * @param t * the exception (throwable) to log */ public void error(String msg, Throwable t) { log(FQCN, Level.ERROR, msg, t); } @Override public boolean isTraceEnabled(Marker marker) { return isTraceEnabled(); } @Override public void trace(Marker marker, String msg) { log(marker, FQCN, Level.TRACE, msg, null); } @Override public void trace(Marker marker, String format, Object arg) { if (isTraceEnabled()) { FormattingTuple ft = MessageFormatter.format(format, arg); log(marker, FQCN, Level.TRACE, ft.getMessage(), ft.getThrowable()); } } @Override public void trace(Marker marker, String format, Object arg1, Object arg2) { if (isTraceEnabled()) { FormattingTuple ft = MessageFormatter.format(format, arg1, arg2); log(marker, FQCN, Level.TRACE, ft.getMessage(), ft.getThrowable()); } } @Override public void trace(Marker marker, String format, Object[] argArray) { if (isTraceEnabled()) { FormattingTuple ft = MessageFormatter.arrayFormat(format, argArray); log(marker, FQCN, Level.TRACE, ft.getMessage(), ft.getThrowable()); } } @Override public void trace(Marker marker, String msg, Throwable t) { log(marker, FQCN, Level.TRACE, msg, t); } @Override public boolean isDebugEnabled(Marker marker) { return isDebugEnabled(); } @Override public void debug(Marker marker, String msg) { log(marker, FQCN, Level.DEBUG, msg, null); } @Override public void debug(Marker marker, String format, Object arg) { if (isDebugEnabled()) { FormattingTuple ft = MessageFormatter.format(format, arg); log(marker, FQCN, Level.DEBUG, ft.getMessage(), ft.getThrowable()); } } @Override public void debug(Marker marker, String format, Object arg1, Object arg2) { if (isDebugEnabled()) { FormattingTuple ft = MessageFormatter.format(format, arg1, arg2); log(marker, FQCN, Level.DEBUG, ft.getMessage(), ft.getThrowable()); } } @Override public void debug(Marker marker, String format, Object[] argArray) { if (isDebugEnabled()) { FormattingTuple ft = MessageFormatter.arrayFormat(format, argArray); log(marker, FQCN, Level.DEBUG, ft.getMessage(), ft.getThrowable()); } } @Override public void debug(Marker marker, String msg, Throwable t) { log(marker, FQCN, Level.DEBUG, msg, t); } @Override public boolean isInfoEnabled(Marker marker) { return isInfoEnabled(); } @Override public void info(Marker marker, String msg) { log(marker, FQCN, Level.INFO, msg, null); } @Override public void info(Marker marker, String format, Object arg) { if (isInfoEnabled()) { FormattingTuple ft = MessageFormatter.format(format, arg); log(marker, FQCN, Level.INFO, ft.getMessage(), ft.getThrowable()); } } @Override public void info(Marker marker, String format, Object arg1, Object arg2) { if (isInfoEnabled()) { FormattingTuple ft = MessageFormatter.format(format, arg1, arg2); log(marker, FQCN, Level.INFO, ft.getMessage(), ft.getThrowable()); } } @Override public void info(Marker marker, String format, Object[] argArray) { if (isInfoEnabled()) { FormattingTuple ft = MessageFormatter.arrayFormat(format, argArray); log(marker, FQCN, Level.INFO, ft.getMessage(), ft.getThrowable()); } } @Override public void info(Marker marker, String msg, Throwable t) { log(marker, FQCN, Level.INFO, msg, t); } @Override public boolean isWarnEnabled(Marker marker) { return isWarnEnabled(); } @Override public void warn(Marker marker, String msg) { log(marker, FQCN, Level.WARN, msg, null); } @Override public void warn(Marker marker, String format, Object arg) { if (isEnabledFor(Level.WARN)) { FormattingTuple ft = MessageFormatter.format(format, arg); log(marker, FQCN, Level.WARN, ft.getMessage(), ft.getThrowable()); } } @Override public void warn(Marker marker, String format, Object arg1, Object arg2) { if (isEnabledFor(Level.WARN)) { FormattingTuple ft = MessageFormatter.format(format, arg1, arg2); log(marker, FQCN, Level.WARN, ft.getMessage(), ft.getThrowable()); } } @Override public void warn(Marker marker, String format, Object[] argArray) { if (isEnabledFor(Level.WARN)) { FormattingTuple ft = MessageFormatter.arrayFormat(format, argArray); log(marker, FQCN, Level.WARN, ft.getMessage(), ft.getThrowable()); } } @Override public void warn(Marker marker, String msg, Throwable t) { log(marker, FQCN, Level.WARN, msg, t); } @Override public boolean isErrorEnabled(Marker marker) { return isErrorEnabled(); } @Override public void error(Marker marker, String msg) { log(marker, FQCN, Level.ERROR, msg, null); } @Override public void error(Marker marker, String format, Object arg) { if (isEnabledFor(Level.ERROR)) { FormattingTuple ft = MessageFormatter.format(format, arg); log(marker, FQCN, Level.ERROR, ft.getMessage(), ft.getThrowable()); } } @Override public void error(Marker marker, String format, Object arg1, Object arg2) { if (isEnabledFor(Level.ERROR)) { FormattingTuple ft = MessageFormatter.format(format, arg1, arg2); log(marker, FQCN, Level.ERROR, ft.getMessage(), ft.getThrowable()); } } @Override public void error(Marker marker, String format, Object[] argArray) { if (isEnabledFor(Level.ERROR)) { FormattingTuple ft = MessageFormatter.arrayFormat(format, argArray); log(marker, FQCN, Level.ERROR, ft.getMessage(), ft.getThrowable()); } } @Override public void error(Marker marker, String msg, Throwable t) { log(marker, FQCN, Level.ERROR, msg, t); } @Override public void log(Marker marker, String fqcn, int level, String msg, Object[] argArray, Throwable t) { Level log4jLevel; switch (level) { case LocationAwareLogger.TRACE_INT: log4jLevel = Level.TRACE; break; case LocationAwareLogger.DEBUG_INT: log4jLevel = Level.DEBUG; break; case LocationAwareLogger.INFO_INT: log4jLevel = Level.INFO; break; case LocationAwareLogger.WARN_INT: log4jLevel = Level.WARN; break; case LocationAwareLogger.ERROR_INT: log4jLevel = Level.ERROR; break; default: throw new IllegalStateException("Level number " + level + " is not recognized."); } log(FQCN, log4jLevel, msg, t); } public void log(Marker marker, String callerFQCN, Priority level, Object message, Throwable t) { if (repository.isDisabled(level.toInt())) { return; } if (level.isGreaterOrEqual(this.getEffectiveLevel())) { forcedLog(marker, callerFQCN, level, message, t); } } /** * This method creates a new logging event and logs the event without * further checks. */ protected void forcedLog(Marker marker, String fqcn, Priority level, Object message, Throwable t) { callAppenders(new FoundationLof4jLoggingEvent(marker, fqcn, this, level, message, t)); } @Override public void callAppenders(LoggingEvent event) { int writes = 0; Category category = this; while (category != null) { // Protected against simultaneous call to addAppender, // removeAppender,... synchronized (category) { @SuppressWarnings("unchecked") Enumeration<Appender> allAppenders = category.getAllAppenders(); while (allAppenders.hasMoreElements()) { Appender appender = allAppenders.nextElement(); // since we may update the appender layout we must sync so // other threads won't use it by mistake synchronized (appender) { if (event instanceof FoundationLof4jLoggingEvent) { appender.doAppend(new FoundationLof4jLoggingEvent((FoundationLof4jLoggingEvent) event)); } else { appender.doAppend(event); } } writes++; } if (!category.getAdditivity()) { break; } } category = category.getParent(); } if (writes == 0) { repository.emitNoAppenderWarning(this); } } private static class FoundationRepositorySelector implements RepositorySelector { final private LoggerRepository repository; public FoundationRepositorySelector(final LoggerRepository repository) { this.repository = repository; } @Override public LoggerRepository getLoggerRepository() { return repository; } } private static class FoundationLogFormatter extends java.util.logging.Formatter { MessageFormat messageFormat = new MessageFormat("{3} [{0}] [{2}]: {1}: {5} {4} \n"); DateTimeFormatter dateFormatter = new DateTimeFormatterBuilder().appendPattern("yyyy/MM/dd HH:mm:ss.SSS") .toFormatter(); @Override public String format(LogRecord record) { Object[] arguments = new Object[] { truncateLoggerName(record.getLoggerName(), 1), record.getLevel(), Thread.currentThread().getName(), (new DateTime(record.getMillis(), DateTimeZone.UTC)).toString(dateFormatter), record.getMessage(), FlowContextFactory.getFlowContext() == null ? "" : FlowContextFactory.getFlowContext().toString() }; return messageFormat.format(arguments); } private String truncateLoggerName(String n, int precision) { String[] split = n.split("\\."); return split[split.length - 1]; } } }