SLF4JBridgeHandler.java revision 664a696f44a70d2799611d1d23d834935ae399ea
1/* 2 * Copyright (c) 2004-2008 QOS.ch 3 * 4 * All rights reserved. 5 * 6 * Permission is hereby granted, free of charge, to any person obtaining 7 * a copy of this software and associated documentation files (the 8 * "Software"), to deal in the Software without restriction, including 9 * without limitation the rights to use, copy, modify, merge, publish, 10 * distribute, and/or sell copies of the Software, and to permit persons 11 * to whom the Software is furnished to do so, provided that the above 12 * copyright notice(s) and this permission notice appear in all copies of 13 * the Software and that both the above copyright notice(s) and this 14 * permission notice appear in supporting documentation. 15 * 16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT 19 * OF THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR 20 * HOLDERS INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY 21 * SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER 22 * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF 23 * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN 24 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 25 * 26 * Except as contained in this notice, the name of a copyright holder 27 * shall not be used in advertising or otherwise to promote the sale, use 28 * or other dealings in this Software without prior written authorization 29 * of the copyright holder. 30 */ 31 32package org.slf4j.bridge; 33 34import java.text.MessageFormat; 35import java.util.MissingResourceException; 36import java.util.ResourceBundle; 37import java.util.logging.Handler; 38import java.util.logging.Level; 39import java.util.logging.LogManager; 40import java.util.logging.LogRecord; 41 42import org.slf4j.Logger; 43import org.slf4j.LoggerFactory; 44import org.slf4j.spi.LocationAwareLogger; 45 46// Based on http://bugzilla.slf4j.org/show_bug.cgi?id=38 47 48/** 49 * Bridge/route all JUL log records to the SLF4J API. 50 * 51 * <p> 52 * Essentially, the idea is to install on the root logger an instance of 53 * SLF4JBridgeHandler as the sole JUL handler in the system. Subsequently, the 54 * SLF4JBridgeHandler instance will redirect all JUL log records are redirected 55 * to the SLF4J API based on the following mapping of levels: 56 * 57 * <pre> 58 * FINEST -> TRACE 59 * FINER -> DEBUG 60 * FINE -> DEBUG 61 * INFO -> INFO 62 * WARNING -> WARN 63 * SEVER -> ERROR 64 * </pre> 65 * 66 * Usage: 67 * 68 * <pre> 69 * // call only once during initialization time of your application 70 * SLF4JBridgeHandler.install(); 71 * 72 * // usual pattern: get a Logger and then log a message 73 * java.util.logging.Logger julLogger = java.util.logging.Logger 74 * .getLogger("org.wombat"); 75 * julLogger.fine("hello world"); // this will get redirected to SLF4J 76 * </pre> 77 * 78 * @author Christian Stein 79 * @author Joern Huxhorn 80 * @author Ceki G¨lc¨ 81 * @author Darryl Smith 82 * 83 * @since 1.5.1 84 */ 85public class SLF4JBridgeHandler extends Handler { 86 87 // The caller is java.util.logging.Logger 88 private static final String FQCN = java.util.logging.Logger.class.getName(); 89 private static final String UNKNOWN_LOGGER_NAME = "unknown.jul.logger"; 90 91 private static final int TRACE_LEVEL_THRESHOLD = Level.FINEST.intValue(); 92 private static final int DEBUG_LEVEL_THRESHOLD = Level.FINE.intValue(); 93 private static final int INFO_LEVEL_THRESHOLD = Level.INFO.intValue(); 94 private static final int WARN_LEVEL_THRESHOLD = Level.WARNING.intValue(); 95 96 /** 97 * Resets the entire JUL logging system and adds new SLF4JHandler instance to 98 * the root logger. 99 */ 100 public static void install() { 101 LogManager.getLogManager().reset(); 102 LogManager.getLogManager().getLogger("").addHandler( 103 new SLF4JBridgeHandler()); 104 } 105 106 /** 107 * Rereads the JUL configuration. 108 * 109 * @see LogManager#readConfiguration(); 110 * @throws Exception 111 * A <code>SecurityException</code> is thrown, if a security 112 * manager exists and if the caller does not have 113 * LoggingPermission("control"). <code>IOException</code> if 114 * there are IO problems reading the configuration. 115 */ 116 public static void uninstall() throws Exception { 117 LogManager.getLogManager().readConfiguration(); 118 } 119 120 /** 121 * Initialize this handler. 122 * 123 */ 124 public SLF4JBridgeHandler() { 125 } 126 127 /** 128 * No-op implementation. 129 */ 130 public void close() { 131 // empty 132 } 133 134 /** 135 * No-op implementation. 136 */ 137 public void flush() { 138 // empty 139 } 140 141 /** 142 * Return the Logger instance that will be used for logging. 143 */ 144 protected Logger getSLF4JLogger(LogRecord record) { 145 String name = record.getLoggerName(); 146 if (name == null) { 147 name = UNKNOWN_LOGGER_NAME; 148 } 149 return LoggerFactory.getLogger(name); 150 } 151 152 protected void callLocationAwareLogger(LocationAwareLogger lal, 153 LogRecord record) { 154 int julLevelValue = record.getLevel().intValue(); 155 int slf4jLevel; 156 157 if (julLevelValue <= TRACE_LEVEL_THRESHOLD) { 158 slf4jLevel = LocationAwareLogger.TRACE_INT; 159 } else if (julLevelValue <= DEBUG_LEVEL_THRESHOLD) { 160 slf4jLevel = LocationAwareLogger.DEBUG_INT; 161 } else if (julLevelValue <= INFO_LEVEL_THRESHOLD) { 162 slf4jLevel = LocationAwareLogger.INFO_INT; 163 } else if (julLevelValue <= WARN_LEVEL_THRESHOLD) { 164 slf4jLevel = LocationAwareLogger.WARN_INT; 165 } else { 166 slf4jLevel = LocationAwareLogger.ERROR_INT; 167 } 168 String i18nMessage = getMessageI18N(record); 169 lal.log(null, FQCN, slf4jLevel, i18nMessage, record.getThrown()); 170 } 171 172 protected void callPlainSLF4JLogger(Logger slf4jLogger, LogRecord record) { 173 String i18nMessage = getMessageI18N(record); 174 int julLevelValue = record.getLevel().intValue(); 175 if (julLevelValue <= TRACE_LEVEL_THRESHOLD) { 176 slf4jLogger.trace(i18nMessage, record.getThrown()); 177 } else if (julLevelValue <= DEBUG_LEVEL_THRESHOLD) { 178 slf4jLogger.debug(i18nMessage, record.getThrown()); 179 } else if (julLevelValue <= INFO_LEVEL_THRESHOLD) { 180 slf4jLogger.info(i18nMessage, record.getThrown()); 181 } else if (julLevelValue <= WARN_LEVEL_THRESHOLD) { 182 slf4jLogger.warn(i18nMessage, record.getThrown()); 183 } else { 184 slf4jLogger.error(i18nMessage, record.getThrown()); 185 } 186 } 187 188 /** 189 * Get the record's message, possibly via a resource bundle. 190 * 191 * @param record 192 * @return 193 */ 194 private String getMessageI18N(LogRecord record) { 195 String message = record.getMessage(); 196 197 if (message == null) { 198 return null; 199 } 200 201 ResourceBundle bundle = record.getResourceBundle(); 202 if (bundle != null) { 203 try { 204 message = bundle.getString(message); 205 } catch (MissingResourceException e) { 206 } 207 } 208 Object[] params = record.getParameters(); 209 if (params != null) { 210 message = MessageFormat.format(message, params); 211 } 212 return message; 213 } 214 215 /** 216 * Publish a LogRecord. 217 * <p> 218 * The logging request was made initially to a Logger object, which 219 * initialized the LogRecord and forwarded it here. 220 * <p> 221 * This handler ignores the Level attached to the LogRecord, as SLF4J cares 222 * about discarding log statements. 223 * 224 * @param record 225 * Description of the log event. A null record is silently 226 * ignored and is not published. 227 */ 228 public void publish(LogRecord record) { 229 // Silently ignore null records. 230 if (record == null) { 231 return; 232 } 233 234 Logger slf4jLogger = getSLF4JLogger(record); 235 String message = record.getMessage(); // can be null! 236 // this is a check to avoid calling the underlying logging system 237 // with a null message 238 if (message == null) { 239 return; 240 } 241 if (slf4jLogger instanceof LocationAwareLogger) { 242 callLocationAwareLogger((LocationAwareLogger) slf4jLogger, record); 243 } else { 244 callPlainSLF4JLogger(slf4jLogger, record); 245 } 246 } 247 248} 249