SLF4JBridgeHandler.java revision 6f9b373977390c1e094d98caa83ee9ea13ffcea7
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.io.IOException; 35import java.text.MessageFormat; 36import java.util.MissingResourceException; 37import java.util.ResourceBundle; 38import java.util.logging.Handler; 39import java.util.logging.Level; 40import java.util.logging.LogManager; 41import java.util.logging.LogRecord; 42 43import org.slf4j.Logger; 44import org.slf4j.LoggerFactory; 45import org.slf4j.spi.LocationAwareLogger; 46 47// Based on http://bugzilla.slf4j.org/show_bug.cgi?id=38 48 49/** 50 * Bridge/route all JUL log records to the SLF4J API. 51 * 52 * <p> 53 * Essentially, the idea is to install on the root logger an instance of 54 * SLF4JBridgeHandler as the sole JUL handler in the system. Subsequently, the 55 * SLF4JBridgeHandler instance will redirect all JUL log records are redirected 56 * to the SLF4J API based on the following mapping of levels: 57 * 58 * <pre> 59 * FINEST -> TRACE 60 * FINER -> DEBUG 61 * FINE -> DEBUG 62 * INFO -> INFO 63 * WARNING -> WARN 64 * SEVER -> ERROR 65 * </pre> 66 * 67 * Usage: 68 * 69 * <pre> 70 * // call only once during initialization time of your application 71 * SLF4JBridgeHandler.install(); 72 * 73 * // usual pattern: get a Logger and then log a message 74 * java.util.logging.Logger julLogger = java.util.logging.Logger 75 * .getLogger("org.wombat"); 76 * julLogger.fine("hello world"); // this will get redirected to SLF4J 77 * </pre> 78 * 79 * @author Christian Stein 80 * @author Joern Huxhorn 81 * @author Ceki Gülcü 82 * @author Darryl Smith 83 * 84 * @since 1.5.1 85 */ 86public class SLF4JBridgeHandler extends Handler { 87 88 // The caller is java.util.logging.Logger 89 private static final String FQCN = java.util.logging.Logger.class.getName(); 90 private static final String UNKNOWN_LOGGER_NAME = "unknown.jul.logger"; 91 92 private static final int TRACE_LEVEL_THRESHOLD = Level.FINEST.intValue(); 93 private static final int DEBUG_LEVEL_THRESHOLD = Level.FINE.intValue(); 94 private static final int INFO_LEVEL_THRESHOLD = Level.INFO.intValue(); 95 private static final int WARN_LEVEL_THRESHOLD = Level.WARNING.intValue(); 96 97 /** 98 * Resets the entire JUL logging system and adds new SLF4JHandler instance to 99 * the root logger. 100 */ 101 public static void install() { 102 LogManager.getLogManager().reset(); 103 LogManager.getLogManager().getLogger("").addHandler( 104 new SLF4JBridgeHandler()); 105 } 106 107 /** 108 * Rereads the JUL configuration. 109 * 110 * @see LogManager#readConfiguration() 111 * 112 * @throws IOException 113 * <code>IOException</code> if there are IO problems reading 114 * the configuration. 115 * @throws SecurityException 116 * A <code>SecurityException</code> is thrown, if a security 117 * manager exists and if the caller does not have 118 * LoggingPermission("control"). 119 */ 120 public static void uninstall() throws SecurityException, IOException { 121 LogManager.getLogManager().readConfiguration(); 122 } 123 124 /** 125 * Initialize this handler. 126 * 127 */ 128 public SLF4JBridgeHandler() { 129 } 130 131 /** 132 * No-op implementation. 133 */ 134 public void close() { 135 // empty 136 } 137 138 /** 139 * No-op implementation. 140 */ 141 public void flush() { 142 // empty 143 } 144 145 /** 146 * Return the Logger instance that will be used for logging. 147 */ 148 protected Logger getSLF4JLogger(LogRecord record) { 149 String name = record.getLoggerName(); 150 if (name == null) { 151 name = UNKNOWN_LOGGER_NAME; 152 } 153 return LoggerFactory.getLogger(name); 154 } 155 156 protected void callLocationAwareLogger(LocationAwareLogger lal, 157 LogRecord record) { 158 int julLevelValue = record.getLevel().intValue(); 159 int slf4jLevel; 160 161 if (julLevelValue <= TRACE_LEVEL_THRESHOLD) { 162 slf4jLevel = LocationAwareLogger.TRACE_INT; 163 } else if (julLevelValue <= DEBUG_LEVEL_THRESHOLD) { 164 slf4jLevel = LocationAwareLogger.DEBUG_INT; 165 } else if (julLevelValue <= INFO_LEVEL_THRESHOLD) { 166 slf4jLevel = LocationAwareLogger.INFO_INT; 167 } else if (julLevelValue <= WARN_LEVEL_THRESHOLD) { 168 slf4jLevel = LocationAwareLogger.WARN_INT; 169 } else { 170 slf4jLevel = LocationAwareLogger.ERROR_INT; 171 } 172 String i18nMessage = getMessageI18N(record); 173 lal.log(null, FQCN, slf4jLevel, i18nMessage, record.getThrown()); 174 } 175 176 protected void callPlainSLF4JLogger(Logger slf4jLogger, LogRecord record) { 177 String i18nMessage = getMessageI18N(record); 178 int julLevelValue = record.getLevel().intValue(); 179 if (julLevelValue <= TRACE_LEVEL_THRESHOLD) { 180 slf4jLogger.trace(i18nMessage, record.getThrown()); 181 } else if (julLevelValue <= DEBUG_LEVEL_THRESHOLD) { 182 slf4jLogger.debug(i18nMessage, record.getThrown()); 183 } else if (julLevelValue <= INFO_LEVEL_THRESHOLD) { 184 slf4jLogger.info(i18nMessage, record.getThrown()); 185 } else if (julLevelValue <= WARN_LEVEL_THRESHOLD) { 186 slf4jLogger.warn(i18nMessage, record.getThrown()); 187 } else { 188 slf4jLogger.error(i18nMessage, record.getThrown()); 189 } 190 } 191 192 /** 193 * Get the record's message, possibly via a resource bundle. 194 * 195 * @param record 196 * @return 197 */ 198 private String getMessageI18N(LogRecord record) { 199 String message = record.getMessage(); 200 201 if (message == null) { 202 return null; 203 } 204 205 ResourceBundle bundle = record.getResourceBundle(); 206 if (bundle != null) { 207 try { 208 message = bundle.getString(message); 209 } catch (MissingResourceException e) { 210 } 211 } 212 Object[] params = record.getParameters(); 213 if (params != null) { 214 message = MessageFormat.format(message, params); 215 } 216 return message; 217 } 218 219 /** 220 * Publish a LogRecord. 221 * <p> 222 * The logging request was made initially to a Logger object, which 223 * initialized the LogRecord and forwarded it here. 224 * <p> 225 * This handler ignores the Level attached to the LogRecord, as SLF4J cares 226 * about discarding log statements. 227 * 228 * @param record 229 * Description of the log event. A null record is silently 230 * ignored and is not published. 231 */ 232 public void publish(LogRecord record) { 233 // Silently ignore null records. 234 if (record == null) { 235 return; 236 } 237 238 Logger slf4jLogger = getSLF4JLogger(record); 239 String message = record.getMessage(); // can be null! 240 // this is a check to avoid calling the underlying logging system 241 // with a null message 242 if (message == null) { 243 return; 244 } 245 if (slf4jLogger instanceof LocationAwareLogger) { 246 callLocationAwareLogger((LocationAwareLogger) slf4jLogger, record); 247 } else { 248 callPlainSLF4JLogger(slf4jLogger, record); 249 } 250 } 251 252} 253