001/* 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache license, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the license for the specific language governing permissions and 015 * limitations under the license. 016 */ 017package org.apache.log4j; 018 019import java.util.Enumeration; 020import java.util.Map; 021import java.util.ResourceBundle; 022import java.util.WeakHashMap; 023import java.util.concurrent.ConcurrentHashMap; 024import java.util.concurrent.ConcurrentMap; 025 026import org.apache.log4j.helpers.NullEnumeration; 027import org.apache.log4j.legacy.core.CategoryUtil; 028import org.apache.log4j.spi.LoggerFactory; 029import org.apache.log4j.spi.LoggingEvent; 030import org.apache.logging.log4j.spi.ExtendedLogger; 031import org.apache.logging.log4j.spi.LoggerContext; 032import org.apache.logging.log4j.message.LocalizedMessage; 033import org.apache.logging.log4j.message.Message; 034import org.apache.logging.log4j.message.ObjectMessage; 035import org.apache.logging.log4j.spi.AbstractLoggerAdapter; 036import org.apache.logging.log4j.util.Strings; 037 038 039/** 040 * Implementation of the Category class for compatibility, despite it having been deprecated a long, long time ago. 041 */ 042public class Category { 043 044 private static PrivateAdapter adapter = new PrivateAdapter(); 045 046 private static final Map<LoggerContext, ConcurrentMap<String, Logger>> CONTEXT_MAP = 047 new WeakHashMap<>(); 048 049 private static final String FQCN = Category.class.getName(); 050 051 private static final boolean isCoreAvailable; 052 053 054 static { 055 boolean available; 056 057 try { 058 available = Class.forName("org.apache.logging.log4j.core.Logger") != null; 059 } catch (Exception ex) { 060 available = false; 061 } 062 isCoreAvailable = available; 063 } 064 065 /** 066 * Resource bundle for localized messages. 067 */ 068 protected ResourceBundle bundle = null; 069 070 private final org.apache.logging.log4j.Logger logger; 071 072 /** 073 * Constructor used by Logger to specify a LoggerContext. 074 * @param context The LoggerContext. 075 * @param name The name of the Logger. 076 */ 077 protected Category(final LoggerContext context, final String name) { 078 this.logger = context.getLogger(name); 079 } 080 081 /** 082 * Constructor exposed by Log4j 1.2. 083 * @param name The name of the Logger. 084 */ 085 protected Category(final String name) { 086 this(PrivateManager.getContext(), name); 087 } 088 089 private Category(final org.apache.logging.log4j.Logger logger) { 090 this.logger = logger; 091 } 092 093 public static Category getInstance(final String name) { 094 return getInstance(PrivateManager.getContext(), name, adapter); 095 } 096 097 static Logger getInstance(final LoggerContext context, final String name) { 098 return getInstance(context, name, adapter); 099 } 100 101 static Logger getInstance(final LoggerContext context, final String name, final LoggerFactory factory) { 102 final ConcurrentMap<String, Logger> loggers = getLoggersMap(context); 103 Logger logger = loggers.get(name); 104 if (logger != null) { 105 return logger; 106 } 107 logger = factory.makeNewLoggerInstance(name); 108 final Logger prev = loggers.putIfAbsent(name, logger); 109 return prev == null ? logger : prev; 110 } 111 112 static Logger getInstance(final LoggerContext context, final String name, final PrivateAdapter factory) { 113 final ConcurrentMap<String, Logger> loggers = getLoggersMap(context); 114 Logger logger = loggers.get(name); 115 if (logger != null) { 116 return logger; 117 } 118 logger = factory.newLogger(name, context); 119 final Logger prev = loggers.putIfAbsent(name, logger); 120 return prev == null ? logger : prev; 121 } 122 123 public static Category getInstance(@SuppressWarnings("rawtypes") final Class clazz) { 124 return getInstance(clazz.getName()); 125 } 126 127 static Logger getInstance(final LoggerContext context, @SuppressWarnings("rawtypes") final Class clazz) { 128 return getInstance(context, clazz.getName()); 129 } 130 131 public final String getName() { 132 return logger.getName(); 133 } 134 135 org.apache.logging.log4j.Logger getLogger() { 136 return logger; 137 } 138 139 public final Category getParent() { 140 if (!isCoreAvailable) { 141 return null; 142 } 143 org.apache.logging.log4j.Logger parent = CategoryUtil.getParent(logger); 144 LoggerContext loggerContext = CategoryUtil.getLoggerContext(logger); 145 if (parent == null || loggerContext == null) { 146 return null; 147 } 148 final ConcurrentMap<String, Logger> loggers = getLoggersMap(loggerContext); 149 final Logger l = loggers.get(parent.getName()); 150 return l == null ? new Category(parent) : l; 151 } 152 153 public static Category getRoot() { 154 return getInstance(Strings.EMPTY); 155 } 156 157 static Logger getRoot(final LoggerContext context) { 158 return getInstance(context, Strings.EMPTY); 159 } 160 161 private static ConcurrentMap<String, Logger> getLoggersMap(final LoggerContext context) { 162 synchronized (CONTEXT_MAP) { 163 ConcurrentMap<String, Logger> map = CONTEXT_MAP.get(context); 164 if (map == null) { 165 map = new ConcurrentHashMap<>(); 166 CONTEXT_MAP.put(context, map); 167 } 168 return map; 169 } 170 } 171 172 /** 173 Returns all the currently defined categories in the default 174 hierarchy as an {@link java.util.Enumeration Enumeration}. 175 176 <p>The root category is <em>not</em> included in the returned 177 {@link Enumeration}. 178 @return and Enumeration of the Categories. 179 180 @deprecated Please use {@link LogManager#getCurrentLoggers()} instead. 181 */ 182 @SuppressWarnings("rawtypes") 183 @Deprecated 184 public static Enumeration getCurrentCategories() { 185 return LogManager.getCurrentLoggers(); 186 } 187 188 public final Level getEffectiveLevel() { 189 switch (logger.getLevel().getStandardLevel()) { 190 case ALL: 191 return Level.ALL; 192 case TRACE: 193 return Level.TRACE; 194 case DEBUG: 195 return Level.DEBUG; 196 case INFO: 197 return Level.INFO; 198 case WARN: 199 return Level.WARN; 200 case ERROR: 201 return Level.ERROR; 202 case FATAL: 203 return Level.FATAL; 204 default: 205 // TODO Should this be an IllegalStateException? 206 return Level.OFF; 207 } 208 } 209 210 public final Priority getChainedPriority() { 211 return getEffectiveLevel(); 212 } 213 214 public final Level getLevel() { 215 return getEffectiveLevel(); 216 } 217 218 public void setLevel(final Level level) { 219 setLevel(level.levelStr); 220 } 221 222 public final Level getPriority() { 223 return getEffectiveLevel(); 224 } 225 226 public void setPriority(final Priority priority) { 227 setLevel(priority.levelStr); 228 } 229 230 private void setLevel(final String levelStr) { 231 if (isCoreAvailable) { 232 CategoryUtil.setLevel(logger, org.apache.logging.log4j.Level.toLevel(levelStr)); 233 } 234 } 235 236 public void debug(final Object message) { 237 maybeLog(FQCN, org.apache.logging.log4j.Level.DEBUG, message, null); 238 } 239 240 public void debug(final Object message, final Throwable t) { 241 maybeLog(FQCN, org.apache.logging.log4j.Level.DEBUG, message, t); 242 } 243 244 public boolean isDebugEnabled() { 245 return logger.isDebugEnabled(); 246 } 247 248 public void error(final Object message) { 249 maybeLog(FQCN, org.apache.logging.log4j.Level.ERROR, message, null); 250 } 251 252 public void error(final Object message, final Throwable t) { 253 maybeLog(FQCN, org.apache.logging.log4j.Level.ERROR, message, t); 254 } 255 256 public boolean isErrorEnabled() { 257 return logger.isErrorEnabled(); 258 } 259 260 public void warn(final Object message) { 261 maybeLog(FQCN, org.apache.logging.log4j.Level.WARN, message, null); 262 } 263 264 public void warn(final Object message, final Throwable t) { 265 maybeLog(FQCN, org.apache.logging.log4j.Level.WARN, message, t); 266 } 267 268 public boolean isWarnEnabled() { 269 return logger.isWarnEnabled(); 270 } 271 272 public void fatal(final Object message) { 273 maybeLog(FQCN, org.apache.logging.log4j.Level.FATAL, message, null); 274 } 275 276 public void fatal(final Object message, final Throwable t) { 277 maybeLog(FQCN, org.apache.logging.log4j.Level.FATAL, message, t); 278 } 279 280 public boolean isFatalEnabled() { 281 return logger.isFatalEnabled(); 282 } 283 284 public void info(final Object message) { 285 maybeLog(FQCN, org.apache.logging.log4j.Level.INFO, message, null); 286 } 287 288 public void info(final Object message, final Throwable t) { 289 maybeLog(FQCN, org.apache.logging.log4j.Level.INFO, message, t); 290 } 291 292 public boolean isInfoEnabled() { 293 return logger.isInfoEnabled(); 294 } 295 296 public void trace(final Object message) { 297 maybeLog(FQCN, org.apache.logging.log4j.Level.TRACE, message, null); 298 } 299 300 public void trace(final Object message, final Throwable t) { 301 maybeLog(FQCN, org.apache.logging.log4j.Level.TRACE, message, t); 302 } 303 304 public boolean isTraceEnabled() { 305 return logger.isTraceEnabled(); 306 } 307 308 public boolean isEnabledFor(final Priority level) { 309 final org.apache.logging.log4j.Level lvl = org.apache.logging.log4j.Level.toLevel(level.toString()); 310 return isEnabledFor(lvl); 311 } 312 313 /** 314 * No-op implementation. 315 * @param appender The Appender to add. 316 */ 317 public void addAppender(final Appender appender) { 318 } 319 320 /** 321 * No-op implementation. 322 * @param event The logging event. 323 */ 324 public void callAppenders(final LoggingEvent event) { 325 } 326 327 @SuppressWarnings("rawtypes") 328 public Enumeration getAllAppenders() { 329 return NullEnumeration.getInstance(); 330 } 331 332 /** 333 * No-op implementation. 334 * @param name The name of the Appender. 335 * @return null. 336 */ 337 public Appender getAppender(final String name) { 338 return null; 339 } 340 341 /** 342 Is the appender passed as parameter attached to this category? 343 * @param appender The Appender to add. 344 * @return true if the appender is attached. 345 */ 346 public boolean isAttached(final Appender appender) { 347 return false; 348 } 349 350 /** 351 * No-op implementation. 352 */ 353 public void removeAllAppenders() { 354 } 355 356 /** 357 * No-op implementation. 358 * @param appender The Appender to remove. 359 */ 360 public void removeAppender(final Appender appender) { 361 } 362 363 /** 364 * No-op implementation. 365 * @param name The Appender to remove. 366 */ 367 public void removeAppender(final String name) { 368 } 369 370 /** 371 * No-op implementation. 372 */ 373 public static void shutdown() { 374 } 375 376 377 public void forcedLog(final String fqcn, final Priority level, final Object message, final Throwable t) { 378 final org.apache.logging.log4j.Level lvl = org.apache.logging.log4j.Level.toLevel(level.toString()); 379 final Message msg = message instanceof Message ? (Message) message : new ObjectMessage(message); 380 if (logger instanceof ExtendedLogger) { 381 ((ExtendedLogger) logger).logMessage(fqcn, lvl, null, new ObjectMessage(message), t); 382 } else { 383 logger.log(lvl, msg, t); 384 } 385 } 386 387 public boolean exists(final String name) { 388 return PrivateManager.getContext().hasLogger(name); 389 } 390 391 public boolean getAdditivity() { 392 return isCoreAvailable ? CategoryUtil.isAdditive(logger) : false; 393 } 394 395 public void setAdditivity(final boolean additivity) { 396 if (isCoreAvailable) { 397 CategoryUtil.setAdditivity(logger, additivity); 398 } 399 } 400 401 public void setResourceBundle(final ResourceBundle bundle) { 402 this.bundle = bundle; 403 } 404 405 public ResourceBundle getResourceBundle() { 406 if (bundle != null) { 407 return bundle; 408 } 409 String name = logger.getName(); 410 if (isCoreAvailable) { 411 LoggerContext ctx = CategoryUtil.getLoggerContext(logger); 412 if (ctx != null) { 413 final ConcurrentMap<String, Logger> loggers = getLoggersMap(ctx); 414 while ((name = getSubName(name)) != null) { 415 final Logger subLogger = loggers.get(name); 416 if (subLogger != null) { 417 final ResourceBundle rb = subLogger.bundle; 418 if (rb != null) { 419 return rb; 420 } 421 } 422 } 423 } 424 } 425 return null; 426 } 427 428 private static String getSubName(final String name) { 429 if (Strings.isEmpty(name)) { 430 return null; 431 } 432 final int i = name.lastIndexOf('.'); 433 return i > 0 ? name.substring(0, i) : Strings.EMPTY; 434 } 435 436 /** 437 If <code>assertion</code> parameter is {@code false}, then 438 logs <code>msg</code> as an {@link #error(Object) error} statement. 439 440 <p>The <code>assert</code> method has been renamed to 441 <code>assertLog</code> because <code>assert</code> is a language 442 reserved word in JDK 1.4. 443 444 @param assertion The assertion. 445 @param msg The message to print if <code>assertion</code> is 446 false. 447 448 @since 1.2 449 */ 450 public void assertLog(final boolean assertion, final String msg) { 451 if (!assertion) { 452 this.error(msg); 453 } 454 } 455 456 public void l7dlog(final Priority priority, final String key, final Throwable t) { 457 if (isEnabledFor(priority)) { 458 final Message msg = new LocalizedMessage(bundle, key, null); 459 forcedLog(FQCN, priority, msg, t); 460 } 461 } 462 463 public void l7dlog(final Priority priority, final String key, final Object[] params, final Throwable t) { 464 if (isEnabledFor(priority)) { 465 final Message msg = new LocalizedMessage(bundle, key, params); 466 forcedLog(FQCN, priority, msg, t); 467 } 468 } 469 470 public void log(final Priority priority, final Object message, final Throwable t) { 471 if (isEnabledFor(priority)) { 472 final Message msg = new ObjectMessage(message); 473 forcedLog(FQCN, priority, msg, t); 474 } 475 } 476 477 public void log(final Priority priority, final Object message) { 478 if (isEnabledFor(priority)) { 479 final Message msg = new ObjectMessage(message); 480 forcedLog(FQCN, priority, msg, null); 481 } 482 } 483 484 public void log(final String fqcn, final Priority priority, final Object message, final Throwable t) { 485 if (isEnabledFor(priority)) { 486 final Message msg = new ObjectMessage(message); 487 forcedLog(fqcn, priority, msg, t); 488 } 489 } 490 491 private void maybeLog(final String fqcn, final org.apache.logging.log4j.Level level, 492 final Object message, final Throwable throwable) { 493 if (logger.isEnabled(level)) { 494 if (logger instanceof ExtendedLogger) { 495 ((ExtendedLogger) logger).logMessage(fqcn, level, null, new ObjectMessage(message), throwable); 496 } else { 497 logger.log(level, message, throwable); 498 } 499 } 500 } 501 502 private static class PrivateAdapter extends AbstractLoggerAdapter<Logger> { 503 504 @Override 505 protected Logger newLogger(final String name, final org.apache.logging.log4j.spi.LoggerContext context) { 506 return new Logger(context, name); 507 } 508 509 @Override 510 protected org.apache.logging.log4j.spi.LoggerContext getContext() { 511 return PrivateManager.getContext(); 512 } 513 } 514 515 /** 516 * Private LogManager. 517 */ 518 private static class PrivateManager extends org.apache.logging.log4j.LogManager { 519 private static final String FQCN = Category.class.getName(); 520 521 public static LoggerContext getContext() { 522 return getContext(FQCN, false); 523 } 524 525 public static org.apache.logging.log4j.Logger getLogger(final String name) { 526 return getLogger(FQCN, name); 527 } 528 } 529 530 private boolean isEnabledFor(final org.apache.logging.log4j.Level level) { 531 return logger.isEnabled(level); 532 } 533 534}