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