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.logging.log4j.core; 018 019import java.io.ObjectStreamException; 020import java.io.Serializable; 021import java.util.ArrayList; 022import java.util.Iterator; 023import java.util.List; 024import java.util.Map; 025 026import org.apache.logging.log4j.Level; 027import org.apache.logging.log4j.Marker; 028import org.apache.logging.log4j.core.config.Configuration; 029import org.apache.logging.log4j.core.config.LocationAwareReliabilityStrategy; 030import org.apache.logging.log4j.core.config.LoggerConfig; 031import org.apache.logging.log4j.core.config.ReliabilityStrategy; 032import org.apache.logging.log4j.core.filter.CompositeFilter; 033import org.apache.logging.log4j.message.Message; 034import org.apache.logging.log4j.message.MessageFactory; 035import org.apache.logging.log4j.message.SimpleMessage; 036import org.apache.logging.log4j.spi.AbstractLogger; 037import org.apache.logging.log4j.util.Strings; 038import org.apache.logging.log4j.util.Supplier; 039 040/** 041 * The core implementation of the {@link org.apache.logging.log4j.Logger} interface. Besides providing an implementation 042 * of all the Logger methods, this class also provides some convenience methods for Log4j 1.x compatibility as well as 043 * access to the {@link org.apache.logging.log4j.core.Filter Filters} and {@link org.apache.logging.log4j.core.Appender 044 * Appenders} associated with this Logger. Note that access to these underlying objects is provided primarily for use in 045 * unit tests or bridging legacy Log4j 1.x code. Future versions of this class may or may not include the various 046 * methods that are noted as not being part of the public API. 047 * 048 * TODO All the isEnabled methods could be pushed into a filter interface. Not sure of the utility of having isEnabled 049 * be able to examine the message pattern and parameters. (RG) Moving the isEnabled methods out of Logger noticeably 050 * impacts performance. The message pattern and parameters are required so that they can be used in global filters. 051 */ 052public class Logger extends AbstractLogger implements Supplier<LoggerConfig> { 053 054 private static final long serialVersionUID = 1L; 055 056 /** 057 * Config should be consistent across threads. 058 */ 059 protected volatile PrivateConfig privateConfig; 060 061 // FIXME: ditto to the above 062 private final LoggerContext context; 063 064 /** 065 * The constructor. 066 * 067 * @param context The LoggerContext this Logger is associated with. 068 * @param messageFactory The message factory. 069 * @param name The name of the Logger. 070 */ 071 protected Logger(final LoggerContext context, final String name, final MessageFactory messageFactory) { 072 super(name, messageFactory); 073 this.context = context; 074 privateConfig = new PrivateConfig(context.getConfiguration(), this); 075 } 076 077 protected Object writeReplace() throws ObjectStreamException { 078 return new LoggerProxy(getName(), getMessageFactory()); 079 } 080 081 /** 082 * This method is only used for 1.x compatibility. Returns the parent of this Logger. If it doesn't already exist 083 * return a temporary Logger. 084 * 085 * @return The parent Logger. 086 */ 087 public Logger getParent() { 088 final LoggerConfig lc = privateConfig.loggerConfig.getName().equals(getName()) ? privateConfig.loggerConfig 089 .getParent() : privateConfig.loggerConfig; 090 if (lc == null) { 091 return null; 092 } 093 final String lcName = lc.getName(); 094 final MessageFactory messageFactory = getMessageFactory(); 095 if (context.hasLogger(lcName, messageFactory)) { 096 return context.getLogger(lcName, messageFactory); 097 } 098 return new Logger(context, lcName, messageFactory); 099 } 100 101 /** 102 * Returns the LoggerContext this Logger is associated with. 103 * 104 * @return the LoggerContext. 105 */ 106 public LoggerContext getContext() { 107 return context; 108 } 109 110 /** 111 * This method is not exposed through the public API and is provided primarily for unit testing. 112 * <p> 113 * If the new level is null, this logger inherits the level from its parent. 114 * </p> 115 * 116 * @param level The Level to use on this Logger, may be null. 117 */ 118 public synchronized void setLevel(final Level level) { 119 if (level == getLevel()) { 120 return; 121 } 122 Level actualLevel; 123 if (level != null) { 124 actualLevel = level; 125 } else { 126 final Logger parent = getParent(); 127 actualLevel = parent != null ? parent.getLevel() : privateConfig.loggerConfigLevel; 128 } 129 privateConfig = new PrivateConfig(privateConfig, actualLevel); 130 } 131 132 /* 133 * (non-Javadoc) 134 * 135 * @see org.apache.logging.log4j.util.Supplier#get() 136 */ 137 @Override 138 public LoggerConfig get() { 139 return privateConfig.loggerConfig; 140 } 141 142 @Override 143 protected boolean requiresLocation() { 144 145 return privateConfig.requiresLocation; 146 } 147 148 @Override 149 public void logMessage(final String fqcn, final Level level, final Marker marker, final Message message, 150 final Throwable t) { 151 final Message msg = message == null ? new SimpleMessage(Strings.EMPTY) : message; 152 final ReliabilityStrategy strategy = privateConfig.loggerConfig.getReliabilityStrategy(); 153 strategy.log(this, getName(), fqcn, marker, level, msg, t); 154 } 155 156 @Override 157 protected void log(final Level level, final Marker marker, final String fqcn, final StackTraceElement location, 158 final Message message, final Throwable throwable) { 159 final ReliabilityStrategy strategy = privateConfig.loggerConfig.getReliabilityStrategy(); 160 if (strategy instanceof LocationAwareReliabilityStrategy) { 161 ((LocationAwareReliabilityStrategy) strategy).log(this, getName(), fqcn, location, marker, level, 162 message, throwable); 163 } else { 164 strategy.log(this, getName(), fqcn, marker, level, message, throwable); 165 } 166 } 167 168 @Override 169 public boolean isEnabled(final Level level, final Marker marker, final String message, final Throwable t) { 170 return privateConfig.filter(level, marker, message, t); 171 } 172 173 @Override 174 public boolean isEnabled(final Level level, final Marker marker, final String message) { 175 return privateConfig.filter(level, marker, message); 176 } 177 178 @Override 179 public boolean isEnabled(final Level level, final Marker marker, final String message, final Object... params) { 180 return privateConfig.filter(level, marker, message, params); 181 } 182 183 @Override 184 public boolean isEnabled(final Level level, final Marker marker, final String message, final Object p0) { 185 return privateConfig.filter(level, marker, message, p0); 186 } 187 188 @Override 189 public boolean isEnabled(final Level level, final Marker marker, final String message, final Object p0, 190 final Object p1) { 191 return privateConfig.filter(level, marker, message, p0, p1); 192 } 193 194 @Override 195 public boolean isEnabled(final Level level, final Marker marker, final String message, final Object p0, 196 final Object p1, final Object p2) { 197 return privateConfig.filter(level, marker, message, p0, p1, p2); 198 } 199 200 @Override 201 public boolean isEnabled(final Level level, final Marker marker, final String message, final Object p0, 202 final Object p1, final Object p2, final Object p3) { 203 return privateConfig.filter(level, marker, message, p0, p1, p2, p3); 204 } 205 206 @Override 207 public boolean isEnabled(final Level level, final Marker marker, final String message, final Object p0, 208 final Object p1, final Object p2, final Object p3, 209 final Object p4) { 210 return privateConfig.filter(level, marker, message, p0, p1, p2, p3, p4); 211 } 212 213 @Override 214 public boolean isEnabled(final Level level, final Marker marker, final String message, final Object p0, 215 final Object p1, final Object p2, final Object p3, 216 final Object p4, final Object p5) { 217 return privateConfig.filter(level, marker, message, p0, p1, p2, p3, p4, p5); 218 } 219 220 @Override 221 public boolean isEnabled(final Level level, final Marker marker, final String message, final Object p0, 222 final Object p1, final Object p2, final Object p3, 223 final Object p4, final Object p5, final Object p6) { 224 return privateConfig.filter(level, marker, message, p0, p1, p2, p3, p4, p5, p6); 225 } 226 227 @Override 228 public boolean isEnabled(final Level level, final Marker marker, final String message, final Object p0, 229 final Object p1, final Object p2, final Object p3, 230 final Object p4, final Object p5, final Object p6, 231 final Object p7) { 232 return privateConfig.filter(level, marker, message, p0, p1, p2, p3, p4, p5, p6, p7); 233 } 234 235 @Override 236 public boolean isEnabled(final Level level, final Marker marker, final String message, final Object p0, 237 final Object p1, final Object p2, final Object p3, 238 final Object p4, final Object p5, final Object p6, 239 final Object p7, final Object p8) { 240 return privateConfig.filter(level, marker, message, p0, p1, p2, p3, p4, p5, p6, p7, p8); 241 } 242 243 @Override 244 public boolean isEnabled(final Level level, final Marker marker, final String message, final Object p0, 245 final Object p1, final Object p2, final Object p3, 246 final Object p4, final Object p5, final Object p6, 247 final Object p7, final Object p8, final Object p9) { 248 return privateConfig.filter(level, marker, message, p0, p1, p2, p3, p4, p5, p6, p7, p8, p9); 249 } 250 251 @Override 252 public boolean isEnabled(final Level level, final Marker marker, final CharSequence message, final Throwable t) { 253 return privateConfig.filter(level, marker, message, t); 254 } 255 256 @Override 257 public boolean isEnabled(final Level level, final Marker marker, final Object message, final Throwable t) { 258 return privateConfig.filter(level, marker, message, t); 259 } 260 261 @Override 262 public boolean isEnabled(final Level level, final Marker marker, final Message message, final Throwable t) { 263 return privateConfig.filter(level, marker, message, t); 264 } 265 266 /** 267 * This method is not exposed through the public API and is used primarily for unit testing. 268 * 269 * @param appender The Appender to add to the Logger. 270 */ 271 public void addAppender(final Appender appender) { 272 privateConfig.config.addLoggerAppender(this, appender); 273 } 274 275 /** 276 * This method is not exposed through the public API and is used primarily for unit testing. 277 * 278 * @param appender The Appender to remove from the Logger. 279 */ 280 public void removeAppender(final Appender appender) { 281 privateConfig.loggerConfig.removeAppender(appender.getName()); 282 } 283 284 /** 285 * This method is not exposed through the public API and is used primarily for unit testing. 286 * 287 * @return A Map containing the Appender's name as the key and the Appender as the value. 288 */ 289 public Map<String, Appender> getAppenders() { 290 return privateConfig.loggerConfig.getAppenders(); 291 } 292 293 /** 294 * This method is not exposed through the public API and is used primarily for unit testing. 295 * 296 * @return An Iterator over all the Filters associated with the Logger. 297 */ 298 // FIXME: this really ought to be an Iterable instead of an Iterator 299 public Iterator<Filter> getFilters() { 300 final Filter filter = privateConfig.loggerConfig.getFilter(); 301 if (filter == null) { 302 return new ArrayList<Filter>().iterator(); 303 } else if (filter instanceof CompositeFilter) { 304 return ((CompositeFilter) filter).iterator(); 305 } else { 306 final List<Filter> filters = new ArrayList<>(); 307 filters.add(filter); 308 return filters.iterator(); 309 } 310 } 311 312 /** 313 * Gets the Level associated with the Logger. 314 * 315 * @return the Level associate with the Logger. 316 */ 317 @Override 318 public Level getLevel() { 319 return privateConfig.loggerConfigLevel; 320 } 321 322 /** 323 * This method is not exposed through the public API and is used primarily for unit testing. 324 * 325 * @return The number of Filters associated with the Logger. 326 */ 327 public int filterCount() { 328 final Filter filter = privateConfig.loggerConfig.getFilter(); 329 if (filter == null) { 330 return 0; 331 } else if (filter instanceof CompositeFilter) { 332 return ((CompositeFilter) filter).size(); 333 } 334 return 1; 335 } 336 337 /** 338 * This method is not exposed through the public API and is used primarily for unit testing. 339 * 340 * @param filter The Filter to add. 341 */ 342 public void addFilter(final Filter filter) { 343 privateConfig.config.addLoggerFilter(this, filter); 344 } 345 346 /** 347 * This method is not exposed through the public API and is present only to support the Log4j 1.2 compatibility 348 * bridge. 349 * 350 * @return true if the associated LoggerConfig is additive, false otherwise. 351 */ 352 public boolean isAdditive() { 353 return privateConfig.loggerConfig.isAdditive(); 354 } 355 356 /** 357 * This method is not exposed through the public API and is present only to support the Log4j 1.2 compatibility 358 * bridge. 359 * 360 * @param additive Boolean value to indicate whether the Logger is additive or not. 361 */ 362 public void setAdditive(final boolean additive) { 363 privateConfig.config.setLoggerAdditive(this, additive); 364 } 365 366 /** 367 * Associates this Logger with a new Configuration. This method is not 368 * exposed through the public API. 369 * <p> 370 * There are two ways this could be used to guarantee all threads are aware 371 * of changes to config. 372 * <ol> 373 * <li>Synchronize this method. Accessors don't need to be synchronized as 374 * Java will treat all variables within a synchronized block as volatile. 375 * </li> 376 * <li>Declare the variable volatile. Option 2 is used here as the 377 * performance cost is very low and it does a better job at documenting how 378 * it is used.</li> 379 * 380 * @param newConfig 381 * The new Configuration. 382 */ 383 protected void updateConfiguration(final Configuration newConfig) { 384 this.privateConfig = new PrivateConfig(newConfig, this); 385 } 386 387 /** 388 * The binding between a Logger and its configuration. 389 */ 390 protected class PrivateConfig { 391 // config fields are public to make them visible to Logger subclasses 392 /** LoggerConfig to delegate the actual logging to. */ 393 public final LoggerConfig loggerConfig; // SUPPRESS CHECKSTYLE 394 /** The current Configuration associated with the LoggerConfig. */ 395 public final Configuration config; // SUPPRESS CHECKSTYLE 396 private final Level loggerConfigLevel; 397 private final int intLevel; 398 private final Logger logger; 399 private final boolean requiresLocation; 400 401 public PrivateConfig(final Configuration config, final Logger logger) { 402 this.config = config; 403 this.loggerConfig = config.getLoggerConfig(getName()); 404 this.loggerConfigLevel = this.loggerConfig.getLevel(); 405 this.intLevel = this.loggerConfigLevel.intLevel(); 406 this.logger = logger; 407 this.requiresLocation = this.loggerConfig.requiresLocation(); 408 } 409 410 public PrivateConfig(final PrivateConfig pc, final Level level) { 411 this.config = pc.config; 412 this.loggerConfig = pc.loggerConfig; 413 this.loggerConfigLevel = level; 414 this.intLevel = this.loggerConfigLevel.intLevel(); 415 this.logger = pc.logger; 416 this.requiresLocation = this.loggerConfig.requiresLocation(); 417 } 418 419 public PrivateConfig(final PrivateConfig pc, final LoggerConfig lc) { 420 this.config = pc.config; 421 this.loggerConfig = lc; 422 this.loggerConfigLevel = lc.getLevel(); 423 this.intLevel = this.loggerConfigLevel.intLevel(); 424 this.logger = pc.logger; 425 this.requiresLocation = this.loggerConfig.requiresLocation(); 426 } 427 428 // LOG4J2-151: changed visibility to public 429 public void logEvent(final LogEvent event) { 430 loggerConfig.log(event); 431 } 432 433 boolean filter(final Level level, final Marker marker, final String msg) { 434 final Filter filter = config.getFilter(); 435 if (filter != null) { 436 final Filter.Result r = filter.filter(logger, level, marker, msg); 437 if (r != Filter.Result.NEUTRAL) { 438 return r == Filter.Result.ACCEPT; 439 } 440 } 441 return level != null && intLevel >= level.intLevel(); 442 } 443 444 boolean filter(final Level level, final Marker marker, final String msg, final Throwable t) { 445 final Filter filter = config.getFilter(); 446 if (filter != null) { 447 final Filter.Result r = filter.filter(logger, level, marker, (Object) msg, t); 448 if (r != Filter.Result.NEUTRAL) { 449 return r == Filter.Result.ACCEPT; 450 } 451 } 452 return level != null && intLevel >= level.intLevel(); 453 } 454 455 boolean filter(final Level level, final Marker marker, final String msg, final Object... p1) { 456 final Filter filter = config.getFilter(); 457 if (filter != null) { 458 final Filter.Result r = filter.filter(logger, level, marker, msg, p1); 459 if (r != Filter.Result.NEUTRAL) { 460 return r == Filter.Result.ACCEPT; 461 } 462 } 463 return level != null && intLevel >= level.intLevel(); 464 } 465 466 boolean filter(final Level level, final Marker marker, final String msg, final Object p0) { 467 final Filter filter = config.getFilter(); 468 if (filter != null) { 469 final Filter.Result r = filter.filter(logger, level, marker, msg, p0); 470 if (r != Filter.Result.NEUTRAL) { 471 return r == Filter.Result.ACCEPT; 472 } 473 } 474 return level != null && intLevel >= level.intLevel(); 475 } 476 477 boolean filter(final Level level, final Marker marker, final String msg, final Object p0, 478 final Object p1) { 479 final Filter filter = config.getFilter(); 480 if (filter != null) { 481 final Filter.Result r = filter.filter(logger, level, marker, msg, p0, p1); 482 if (r != Filter.Result.NEUTRAL) { 483 return r == Filter.Result.ACCEPT; 484 } 485 } 486 return level != null && intLevel >= level.intLevel(); 487 } 488 489 boolean filter(final Level level, final Marker marker, final String msg, final Object p0, 490 final Object p1, final Object p2) { 491 final Filter filter = config.getFilter(); 492 if (filter != null) { 493 final Filter.Result r = filter.filter(logger, level, marker, msg, p0, p1, p2); 494 if (r != Filter.Result.NEUTRAL) { 495 return r == Filter.Result.ACCEPT; 496 } 497 } 498 return level != null && intLevel >= level.intLevel(); 499 } 500 501 boolean filter(final Level level, final Marker marker, final String msg, final Object p0, 502 final Object p1, final Object p2, final Object p3) { 503 final Filter filter = config.getFilter(); 504 if (filter != null) { 505 final Filter.Result r = filter.filter(logger, level, marker, msg, p0, p1, p2, p3); 506 if (r != Filter.Result.NEUTRAL) { 507 return r == Filter.Result.ACCEPT; 508 } 509 } 510 return level != null && intLevel >= level.intLevel(); 511 } 512 513 boolean filter(final Level level, final Marker marker, final String msg, final Object p0, 514 final Object p1, final Object p2, final Object p3, 515 final Object p4) { 516 final Filter filter = config.getFilter(); 517 if (filter != null) { 518 final Filter.Result r = filter.filter(logger, level, marker, msg, p0, p1, p2, p3, p4); 519 if (r != Filter.Result.NEUTRAL) { 520 return r == Filter.Result.ACCEPT; 521 } 522 } 523 return level != null && intLevel >= level.intLevel(); 524 } 525 526 boolean filter(final Level level, final Marker marker, final String msg, final Object p0, 527 final Object p1, final Object p2, final Object p3, 528 final Object p4, final Object p5) { 529 final Filter filter = config.getFilter(); 530 if (filter != null) { 531 final Filter.Result r = filter.filter(logger, level, marker, msg, p0, p1, p2, p3, p4, p5); 532 if (r != Filter.Result.NEUTRAL) { 533 return r == Filter.Result.ACCEPT; 534 } 535 } 536 return level != null && intLevel >= level.intLevel(); 537 } 538 539 boolean filter(final Level level, final Marker marker, final String msg, final Object p0, 540 final Object p1, final Object p2, final Object p3, 541 final Object p4, final Object p5, final Object p6) { 542 final Filter filter = config.getFilter(); 543 if (filter != null) { 544 final Filter.Result r = filter.filter(logger, level, marker, msg, p0, p1, p2, p3, p4, p5, p6); 545 if (r != Filter.Result.NEUTRAL) { 546 return r == Filter.Result.ACCEPT; 547 } 548 } 549 return level != null && intLevel >= level.intLevel(); 550 } 551 552 boolean filter(final Level level, final Marker marker, final String msg, final Object p0, 553 final Object p1, final Object p2, final Object p3, 554 final Object p4, final Object p5, final Object p6, 555 final Object p7) { 556 final Filter filter = config.getFilter(); 557 if (filter != null) { 558 final Filter.Result r = filter.filter(logger, level, marker, msg, p0, p1, p2, p3, p4, p5, p6, p7); 559 if (r != Filter.Result.NEUTRAL) { 560 return r == Filter.Result.ACCEPT; 561 } 562 } 563 return level != null && intLevel >= level.intLevel(); 564 } 565 566 boolean filter(final Level level, final Marker marker, final String msg, final Object p0, 567 final Object p1, final Object p2, final Object p3, 568 final Object p4, final Object p5, final Object p6, 569 final Object p7, final Object p8) { 570 final Filter filter = config.getFilter(); 571 if (filter != null) { 572 final Filter.Result r = filter.filter(logger, level, marker, msg, p0, p1, p2, p3, p4, p5, p6, p7, p8); 573 if (r != Filter.Result.NEUTRAL) { 574 return r == Filter.Result.ACCEPT; 575 } 576 } 577 return level != null && intLevel >= level.intLevel(); 578 } 579 580 boolean filter(final Level level, final Marker marker, final String msg, final Object p0, 581 final Object p1, final Object p2, final Object p3, 582 final Object p4, final Object p5, final Object p6, 583 final Object p7, final Object p8, final Object p9) { 584 final Filter filter = config.getFilter(); 585 if (filter != null) { 586 final Filter.Result r = filter.filter(logger, level, marker, msg, p0, p1, p2, p3, p4, p5, p6, p7, p8, 587 p9); 588 if (r != Filter.Result.NEUTRAL) { 589 return r == Filter.Result.ACCEPT; 590 } 591 } 592 return level != null && intLevel >= level.intLevel(); 593 } 594 595 boolean filter(final Level level, final Marker marker, final CharSequence msg, final Throwable t) { 596 final Filter filter = config.getFilter(); 597 if (filter != null) { 598 final Filter.Result r = filter.filter(logger, level, marker, msg, t); 599 if (r != Filter.Result.NEUTRAL) { 600 return r == Filter.Result.ACCEPT; 601 } 602 } 603 return level != null && intLevel >= level.intLevel(); 604 } 605 606 boolean filter(final Level level, final Marker marker, final Object msg, final Throwable t) { 607 final Filter filter = config.getFilter(); 608 if (filter != null) { 609 final Filter.Result r = filter.filter(logger, level, marker, msg, t); 610 if (r != Filter.Result.NEUTRAL) { 611 return r == Filter.Result.ACCEPT; 612 } 613 } 614 return level != null && intLevel >= level.intLevel(); 615 } 616 617 boolean filter(final Level level, final Marker marker, final Message msg, final Throwable t) { 618 final Filter filter = config.getFilter(); 619 if (filter != null) { 620 final Filter.Result r = filter.filter(logger, level, marker, msg, t); 621 if (r != Filter.Result.NEUTRAL) { 622 return r == Filter.Result.ACCEPT; 623 } 624 } 625 return level != null && intLevel >= level.intLevel(); 626 } 627 628 @Override 629 public String toString() { 630 final StringBuilder builder = new StringBuilder(); 631 builder.append("PrivateConfig [loggerConfig="); 632 builder.append(loggerConfig); 633 builder.append(", config="); 634 builder.append(config); 635 builder.append(", loggerConfigLevel="); 636 builder.append(loggerConfigLevel); 637 builder.append(", intLevel="); 638 builder.append(intLevel); 639 builder.append(", logger="); 640 builder.append(logger); 641 builder.append("]"); 642 return builder.toString(); 643 } 644 } 645 646 /** 647 * Serialization proxy class for Logger. Since the LoggerContext and config information can be reconstructed on the 648 * fly, the only information needed for a Logger are what's available in AbstractLogger. 649 * 650 * @since 2.5 651 */ 652 protected static class LoggerProxy implements Serializable { 653 private static final long serialVersionUID = 1L; 654 655 private final String name; 656 private final MessageFactory messageFactory; 657 658 public LoggerProxy(final String name, final MessageFactory messageFactory) { 659 this.name = name; 660 this.messageFactory = messageFactory; 661 } 662 663 protected Object readResolve() throws ObjectStreamException { 664 return new Logger(LoggerContext.getContext(), name, messageFactory); 665 } 666 } 667 668 /** 669 * Returns a String representation of this instance in the form {@code "name:level[ in context_name]"}. 670 * 671 * @return A String describing this Logger instance. 672 */ 673 @Override 674 public String toString() { 675 final String nameLevel = Strings.EMPTY + getName() + ':' + getLevel(); 676 if (context == null) { 677 return nameLevel; 678 } 679 final String contextName = context.getName(); 680 return contextName == null ? nameLevel : nameLevel + " in " + contextName; 681 } 682 683 @Override 684 public boolean equals(final Object o) { 685 if (this == o) { 686 return true; 687 } 688 if (o == null || getClass() != o.getClass()) { 689 return false; 690 } 691 final Logger that = (Logger) o; 692 return getName().equals(that.getName()); 693 } 694 695 @Override 696 public int hashCode() { 697 return getName().hashCode(); 698 } 699}