001/** 002 * Copyright (c) 2004-2011 QOS.ch 003 * All rights reserved. 004 * 005 * Permission is hereby granted, free of charge, to any person obtaining 006 * a copy of this software and associated documentation files (the 007 * "Software"), to deal in the Software without restriction, including 008 * without limitation the rights to use, copy, modify, merge, publish, 009 * distribute, sublicense, and/or sell copies of the Software, and to 010 * permit persons to whom the Software is furnished to do so, subject to 011 * the following conditions: 012 * 013 * The above copyright notice and this permission notice shall be 014 * included in all copies or substantial portions of the Software. 015 * 016 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 017 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 018 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 019 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 020 * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 021 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 022 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 023 * 024 */ 025package org.slf4j.log4j12; 026 027import static org.slf4j.event.EventConstants.NA_SUBST; 028 029import java.io.Serializable; 030 031import org.apache.log4j.Level; 032import org.apache.log4j.spi.LocationInfo; 033import org.apache.log4j.spi.ThrowableInformation; 034import org.slf4j.Logger; 035import org.slf4j.Marker; 036import org.slf4j.event.LoggingEvent; 037import org.slf4j.event.SubstituteLoggingEvent; 038import org.slf4j.helpers.LegacyAbstractLogger; 039import org.slf4j.helpers.MessageFormatter; 040import org.slf4j.helpers.NormalizedParameters; 041import org.slf4j.helpers.SubstituteLogger; 042import org.slf4j.spi.LocationAwareLogger; 043import org.slf4j.spi.LoggingEventAware; 044import org.slf4j.spi.LoggingEventBuilder; 045 046/** 047 * A wrapper over {@link org.apache.log4j.Logger org.apache.log4j.Logger} in 048 * conforming to the {@link Logger} interface. 049 * 050 * <p> 051 * Note that the logging levels mentioned in this class refer to those defined 052 * in the <a href= 053 * "http://logging.apache.org/log4j/docs/api/org/apache/log4j/Level.html"> 054 * <code>org.apache.log4j.Level</code></a> class. 055 * 056 * <p> 057 * The TRACE level was introduced in log4j version 1.2.12. In order to avoid 058 * crashing the host application, in the case the log4j version in use predates 059 * 1.2.12, the TRACE level will be mapped as DEBUG. See also 060 * <a href="http://jira.qos.ch/browse/SLF4J-59">SLF4J-59</a>. 061 * 062 * @author Ceki Gülcü 063 */ 064public final class Log4jLoggerAdapter extends LegacyAbstractLogger implements LocationAwareLogger, LoggingEventAware, Serializable { 065 066 private static final long serialVersionUID = 6182834493563598289L; 067 068 final transient org.apache.log4j.Logger logger; 069 070 /** 071 * Following the pattern discussed in pages 162 through 168 of "The complete 072 * log4j manual". 073 */ 074 075 final static String FQCN_NOMINAL = org.slf4j.helpers.AbstractLogger.class.getName(); 076 final static String FQCN_SUBSTITUE = FQCN_NOMINAL; 077 final static String FQCN_FLUENT = org.slf4j.spi.DefaultLoggingEventBuilder.class.getName(); 078 079 // Does the log4j version in use recognize the TRACE level? 080 // The trace level was introduced in log4j 1.2.12. 081 final boolean traceCapable; 082 083 // WARN: Log4jLoggerAdapter constructor should have only package access so 084 // that only Log4jLoggerFactory be able to create one. 085 Log4jLoggerAdapter(org.apache.log4j.Logger logger) { 086 this.logger = logger; 087 this.name = logger.getName(); 088 traceCapable = isTraceCapable(); 089 } 090 091 private boolean isTraceCapable() { 092 try { 093 logger.isTraceEnabled(); 094 return true; 095 } catch (NoSuchMethodError e) { 096 return false; 097 } 098 } 099 100 /** 101 * Is this logger instance enabled for the TRACE level? 102 * 103 * @return True if this Logger is enabled for level TRACE, false otherwise. 104 */ 105 public boolean isTraceEnabled() { 106 if (traceCapable) { 107 return logger.isTraceEnabled(); 108 } else { 109 return logger.isDebugEnabled(); 110 } 111 } 112 113 /** 114 * Is this logger instance enabled for the DEBUG level? 115 * 116 * @return True if this Logger is enabled for level DEBUG, false otherwise. 117 */ 118 public boolean isDebugEnabled() { 119 return logger.isDebugEnabled(); 120 } 121 122 /** 123 * Is this logger instance enabled for the INFO level? 124 * 125 * @return True if this Logger is enabled for the INFO level, false otherwise. 126 */ 127 public boolean isInfoEnabled() { 128 return logger.isInfoEnabled(); 129 } 130 131 /** 132 * Is this logger instance enabled for the WARN level? 133 * 134 * @return True if this Logger is enabled for the WARN level, false otherwise. 135 */ 136 public boolean isWarnEnabled() { 137 return logger.isEnabledFor(Level.WARN); 138 } 139 140 /** 141 * Is this logger instance enabled for level ERROR? 142 * 143 * @return True if this Logger is enabled for level ERROR, false otherwise. 144 */ 145 public boolean isErrorEnabled() { 146 return logger.isEnabledFor(Level.ERROR); 147 } 148 149 @Override 150 public void log(Marker marker, String callerFQCN, int level, String msg, Object[] arguments, Throwable t) { 151 Level log4jLevel = toLog4jLevel(level); 152 NormalizedParameters np = NormalizedParameters.normalize(msg, arguments, t); 153 String formattedMessage = MessageFormatter.basicArrayFormat(np.getMessage(), np.getArguments()); 154 logger.log(callerFQCN, log4jLevel, formattedMessage, np.getThrowable()); 155 } 156 157 @Override 158 protected void handleNormalizedLoggingCall(org.slf4j.event.Level level, Marker marker, String msg, Object[] arguments, Throwable throwable) { 159 Level log4jLevel = toLog4jLevel(level.toInt()); 160 String formattedMessage = MessageFormatter.basicArrayFormat(msg, arguments); 161 logger.log(getFullyQualifiedCallerName(), log4jLevel, formattedMessage, throwable); 162 } 163 164 /** 165 * Called by {@link SubstituteLogger} or by {@link LoggingEventBuilder} instances 166 * @param event 167 */ 168 public void log(LoggingEvent event) { 169 Level log4jLevel = toLog4jLevel(event.getLevel().toInt()); 170 if (!logger.isEnabledFor(log4jLevel)) 171 return; 172 173 org.apache.log4j.spi.LoggingEvent log4jevent = event2Log4jEvent(event, log4jLevel); 174 logger.callAppenders(log4jevent); 175 176 } 177 178 private org.apache.log4j.spi.LoggingEvent event2Log4jEvent(LoggingEvent event, Level log4jLevel) { 179 180 String formattedMessage = MessageFormatter.basicArrayFormat(event.getMessage(), event.getArgumentArray()); 181 182 LocationInfo locationInfo = null; 183 String fcqn = null; 184 185 if (event instanceof SubstituteLoggingEvent) { 186 locationInfo = new LocationInfo(NA_SUBST, NA_SUBST, NA_SUBST, "0"); 187 fcqn = FQCN_SUBSTITUE; 188 } else { 189 fcqn = FQCN_FLUENT; 190 } 191 192 ThrowableInformation ti = null; 193 Throwable t = event.getThrowable(); 194 if (t != null) 195 ti = new ThrowableInformation(t); 196 197 org.apache.log4j.spi.LoggingEvent log4jEvent = new org.apache.log4j.spi.LoggingEvent(fcqn, logger, event.getTimeStamp(), log4jLevel, formattedMessage, 198 event.getThreadName(), ti, null, locationInfo, null); 199 200 return log4jEvent; 201 } 202 203 private Level toLog4jLevel(int slf4jLevelInt) { 204 Level log4jLevel; 205 switch (slf4jLevelInt) { 206 case LocationAwareLogger.TRACE_INT: 207 log4jLevel = traceCapable ? Level.TRACE : Level.DEBUG; 208 break; 209 case LocationAwareLogger.DEBUG_INT: 210 log4jLevel = Level.DEBUG; 211 break; 212 case LocationAwareLogger.INFO_INT: 213 log4jLevel = Level.INFO; 214 break; 215 case LocationAwareLogger.WARN_INT: 216 log4jLevel = Level.WARN; 217 break; 218 case LocationAwareLogger.ERROR_INT: 219 log4jLevel = Level.ERROR; 220 break; 221 default: 222 throw new IllegalStateException("Level number " + slf4jLevelInt + " is not recognized."); 223 } 224 return log4jLevel; 225 } 226 227 @Override 228 protected String getFullyQualifiedCallerName() { 229 return FQCN_NOMINAL; 230 } 231 232}