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