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.impl; 018 019import java.io.InvalidObjectException; 020import java.io.ObjectInputStream; 021import java.io.Serializable; 022import java.util.Collections; 023import java.util.HashMap; 024import java.util.List; 025import java.util.Map; 026import java.util.Objects; 027 028import org.apache.logging.log4j.Level; 029import org.apache.logging.log4j.Marker; 030import org.apache.logging.log4j.ThreadContext; 031import org.apache.logging.log4j.core.LogEvent; 032import org.apache.logging.log4j.core.async.RingBufferLogEvent; 033import org.apache.logging.log4j.core.config.LoggerConfig; 034import org.apache.logging.log4j.core.config.Property; 035import org.apache.logging.log4j.core.util.Clock; 036import org.apache.logging.log4j.core.util.ClockFactory; 037import org.apache.logging.log4j.core.util.DummyNanoClock; 038import org.apache.logging.log4j.core.util.NanoClock; 039import org.apache.logging.log4j.message.LoggerNameAwareMessage; 040import org.apache.logging.log4j.message.Message; 041import org.apache.logging.log4j.message.ReusableMessage; 042import org.apache.logging.log4j.message.SimpleMessage; 043import org.apache.logging.log4j.message.TimestampMessage; 044import org.apache.logging.log4j.status.StatusLogger; 045import org.apache.logging.log4j.util.Strings; 046 047/** 048 * Implementation of a LogEvent. 049 */ 050public class Log4jLogEvent implements LogEvent { 051 052 private static final long serialVersionUID = -8393305700508709443L; 053 private static final Clock CLOCK = ClockFactory.getClock(); 054 private static volatile NanoClock nanoClock = new DummyNanoClock(); 055 private final String loggerFqcn; 056 private final Marker marker; 057 private final Level level; 058 private final String loggerName; 059 private Message message; 060 private final long timeMillis; 061 private final transient Throwable thrown; 062 private ThrowableProxy thrownProxy; 063 private final Map<String, String> contextMap; 064 private final ThreadContext.ContextStack contextStack; 065 private long threadId; 066 private String threadName; 067 private int threadPriority; 068 private StackTraceElement source; 069 private boolean includeLocation; 070 private boolean endOfBatch = false; 071 /** @since Log4J 2.4 */ 072 private final transient long nanoTime; 073 074 /** LogEvent Builder helper class. */ 075 public static class Builder implements org.apache.logging.log4j.core.util.Builder<LogEvent> { 076 077 private String loggerFqcn; 078 private Marker marker; 079 private Level level; 080 private String loggerName; 081 private Message message; 082 private Throwable thrown; 083 private long timeMillis = CLOCK.currentTimeMillis(); 084 private ThrowableProxy thrownProxy; 085 private Map<String, String> contextMap = ThreadContext.getImmutableContext(); 086 private ThreadContext.ContextStack contextStack = ThreadContext.getImmutableStack(); 087 private long threadId; 088 private String threadName; 089 private int threadPriority; 090 private StackTraceElement source; 091 private boolean includeLocation; 092 private boolean endOfBatch = false; 093 private long nanoTime; 094 095 public Builder() { 096 } 097 098 public Builder(final LogEvent other) { 099 Objects.requireNonNull(other); 100 if (other instanceof RingBufferLogEvent) { 101 ((RingBufferLogEvent) other).initializeBuilder(this); 102 return; 103 } 104 if (other instanceof MutableLogEvent) { 105 ((MutableLogEvent) other).initializeBuilder(this); 106 return; 107 } 108 this.loggerFqcn = other.getLoggerFqcn(); 109 this.marker = other.getMarker(); 110 this.level = other.getLevel(); 111 this.loggerName = other.getLoggerName(); 112 this.message = other.getMessage(); 113 this.timeMillis = other.getTimeMillis(); 114 this.thrown = other.getThrown(); 115 this.contextMap = other.getContextMap(); 116 this.contextStack = other.getContextStack(); 117 this.includeLocation = other.isIncludeLocation(); 118 this.endOfBatch = other.isEndOfBatch(); 119 this.nanoTime = other.getNanoTime(); 120 121 // Avoid unnecessarily initializing thrownProxy, threadName and source if possible 122 if (other instanceof Log4jLogEvent) { 123 final Log4jLogEvent evt = (Log4jLogEvent) other; 124 this.thrownProxy = evt.thrownProxy; 125 this.source = evt.source; 126 this.threadId = evt.threadId; 127 this.threadName = evt.threadName; 128 this.threadPriority = evt.threadPriority; 129 } else { 130 this.thrownProxy = other.getThrownProxy(); 131 this.source = other.getSource(); 132 this.threadId = other.getThreadId(); 133 this.threadName = other.getThreadName(); 134 this.threadPriority = other.getThreadPriority(); 135 } 136 } 137 138 public Builder setLevel(final Level level) { 139 this.level = level; 140 return this; 141 } 142 143 public Builder setLoggerFqcn(final String loggerFqcn) { 144 this.loggerFqcn = loggerFqcn; 145 return this; 146 } 147 148 public Builder setLoggerName(final String loggerName) { 149 this.loggerName = loggerName; 150 return this; 151 } 152 153 public Builder setMarker(final Marker marker) { 154 this.marker = marker; 155 return this; 156 } 157 158 public Builder setMessage(final Message message) { 159 this.message = message; 160 return this; 161 } 162 163 public Builder setThrown(final Throwable thrown) { 164 this.thrown = thrown; 165 return this; 166 } 167 168 public Builder setTimeMillis(final long timeMillis) { 169 this.timeMillis = timeMillis; 170 return this; 171 } 172 173 public Builder setThrownProxy(final ThrowableProxy thrownProxy) { 174 this.thrownProxy = thrownProxy; 175 return this; 176 } 177 178 public Builder setContextMap(final Map<String, String> contextMap) { 179 this.contextMap = contextMap; 180 return this; 181 } 182 183 public Builder setContextStack(final ThreadContext.ContextStack contextStack) { 184 this.contextStack = contextStack; 185 return this; 186 } 187 188 public Builder setThreadId(final long threadId) { 189 this.threadId = threadId; 190 return this; 191 } 192 193 public Builder setThreadName(final String threadName) { 194 this.threadName = threadName; 195 return this; 196 } 197 198 public Builder setThreadPriority(final int threadPriority) { 199 this.threadPriority = threadPriority; 200 return this; 201 } 202 203 public Builder setSource(final StackTraceElement source) { 204 this.source = source; 205 return this; 206 } 207 208 public Builder setIncludeLocation(final boolean includeLocation) { 209 this.includeLocation = includeLocation; 210 return this; 211 } 212 213 public Builder setEndOfBatch(final boolean endOfBatch) { 214 this.endOfBatch = endOfBatch; 215 return this; 216 } 217 218 /** 219 * Sets the nano time for the event. 220 * @param nanoTime The value of the running Java Virtual Machine's high-resolution time source when the event 221 * was created. 222 * @return this builder 223 */ 224 public Builder setNanoTime(final long nanoTime) { 225 this.nanoTime = nanoTime; 226 return this; 227 } 228 229 @Override 230 public Log4jLogEvent build() { 231 final Log4jLogEvent result = new Log4jLogEvent(loggerName, marker, loggerFqcn, level, message, thrown, 232 thrownProxy, contextMap, contextStack, threadId, threadName, threadPriority, source, timeMillis, nanoTime); 233 result.setIncludeLocation(includeLocation); 234 result.setEndOfBatch(endOfBatch); 235 return result; 236 } 237 } 238 239 /** 240 * Returns a new empty {@code Log4jLogEvent.Builder} with all fields empty. 241 * @return a new empty builder. 242 */ 243 public static Builder newBuilder() { 244 return new Builder(); 245 } 246 247 public Log4jLogEvent() { 248 this(Strings.EMPTY, null, Strings.EMPTY, null, null, (Throwable) null, null, null, null, 0, null, 249 0, null, CLOCK.currentTimeMillis(), nanoClock.nanoTime()); 250 } 251 252 /** 253 * 254 * @deprecated use {@link Log4jLogEvent.Builder} instead. This constructor will be removed in an upcoming release. 255 */ 256 @Deprecated 257 public Log4jLogEvent(final long timestamp) { 258 this(Strings.EMPTY, null, Strings.EMPTY, null, null, (Throwable) null, null, null, null, 0, null, 259 0, null, timestamp, nanoClock.nanoTime()); 260 } 261 262 /** 263 * Constructor. 264 * @param loggerName The name of the Logger. 265 * @param marker The Marker or null. 266 * @param loggerFQCN The fully qualified class name of the caller. 267 * @param level The logging Level. 268 * @param message The Message. 269 * @param t A Throwable or null. 270 * @deprecated use {@link Log4jLogEvent.Builder} instead. This constructor will be removed in an upcoming release. 271 */ 272 @Deprecated 273 public Log4jLogEvent(final String loggerName, final Marker marker, final String loggerFQCN, final Level level, 274 final Message message, final Throwable t) { 275 this(loggerName, marker, loggerFQCN, level, message, null, t); 276 } 277 278 /** 279 * Constructor. 280 * @param loggerName The name of the Logger. 281 * @param marker The Marker or null. 282 * @param loggerFQCN The fully qualified class name of the caller. 283 * @param level The logging Level. 284 * @param message The Message. 285 * @param properties properties to add to the event. 286 * @param t A Throwable or null. 287 */ 288 // This constructor is called from LogEventFactories. 289 public Log4jLogEvent(final String loggerName, final Marker marker, final String loggerFQCN, final Level level, 290 final Message message, final List<Property> properties, final Throwable t) { 291 this(loggerName, marker, loggerFQCN, level, message, t, null, 292 createMap(properties), 293 ThreadContext.getDepth() == 0 ? null : ThreadContext.cloneStack(), // mutable copy 294 0, // thread name 295 null, // stack trace element 296 0, 297 null, // LOG4J2-628 use log4j.Clock for timestamps 298 // LOG4J2-744 unless TimestampMessage already has one 299 message instanceof TimestampMessage ? ((TimestampMessage) message).getTimestamp() : 300 CLOCK.currentTimeMillis(), nanoClock.nanoTime()); 301 } 302 303 /** 304 * Constructor. 305 * @param loggerName The name of the Logger. 306 * @param marker The Marker or null. 307 * @param loggerFQCN The fully qualified class name of the caller. 308 * @param level The logging Level. 309 * @param message The Message. 310 * @param t A Throwable or null. 311 * @param mdc The mapped diagnostic context. 312 * @param ndc the nested diagnostic context. 313 * @param threadName The name of the thread. 314 * @param location The locations of the caller. 315 * @param timestampMillis The timestamp of the event. 316 * @deprecated use {@link Log4jLogEvent.Builder} instead. This constructor will be removed in an upcoming release. 317 */ 318 @Deprecated 319public Log4jLogEvent(final String loggerName, final Marker marker, final String loggerFQCN, final Level level, 320 final Message message, final Throwable t, final Map<String, String> mdc, 321 final ThreadContext.ContextStack ndc, final String threadName, 322 final StackTraceElement location, final long timestampMillis) { 323 this(loggerName, marker, loggerFQCN, level, message, t, null, mdc, ndc, 0, 324 threadName, 0, location, timestampMillis, nanoClock.nanoTime()); 325 } 326 327 /** 328 * Create a new LogEvent. 329 * @param loggerName The name of the Logger. 330 * @param marker The Marker or null. 331 * @param loggerFQCN The fully qualified class name of the caller. 332 * @param level The logging Level. 333 * @param message The Message. 334 * @param thrown A Throwable or null. 335 * @param thrownProxy A ThrowableProxy or null. 336 * @param mdc The mapped diagnostic context. 337 * @param ndc the nested diagnostic context. 338 * @param threadName The name of the thread. 339 * @param location The locations of the caller. 340 * @param timestamp The timestamp of the event. 341 * @return a new LogEvent 342 * @deprecated use {@link Log4jLogEvent.Builder} instead. This method will be removed in an upcoming release. 343 */ 344 @Deprecated 345 public static Log4jLogEvent createEvent(final String loggerName, final Marker marker, final String loggerFQCN, 346 final Level level, final Message message, final Throwable thrown, 347 final ThrowableProxy thrownProxy, 348 final Map<String, String> mdc, final ThreadContext.ContextStack ndc, 349 final String threadName, final StackTraceElement location, 350 final long timestamp) { 351 final Log4jLogEvent result = new Log4jLogEvent(loggerName, marker, loggerFQCN, level, message, thrown, 352 thrownProxy, mdc, ndc, 0, threadName, 0, location, timestamp, nanoClock.nanoTime()); 353 return result; 354 } 355 356 /** 357 * Constructor. 358 * @param loggerName The name of the Logger. 359 * @param marker The Marker or null. 360 * @param loggerFQCN The fully qualified class name of the caller. 361 * @param level The logging Level. 362 * @param message The Message. 363 * @param thrown A Throwable or null. 364 * @param thrownProxy A ThrowableProxy or null. 365 * @param contextMap The mapped diagnostic context. 366 * @param contextStack the nested diagnostic context. 367 * @param threadId the thread ID 368 * @param threadName The name of the thread. 369 * @param threadPriority the thread priority 370 * @param source The locations of the caller. 371 * @param timestampMillis The timestamp of the event. 372 * @param nanoTime The value of the running Java Virtual Machine's high-resolution time source when the event was 373 * created. 374 */ 375 private Log4jLogEvent(final String loggerName, final Marker marker, final String loggerFQCN, final Level level, 376 final Message message, final Throwable thrown, final ThrowableProxy thrownProxy, 377 final Map<String, String> contextMap, final ThreadContext.ContextStack contextStack, final long threadId, 378 final String threadName, final int threadPriority, final StackTraceElement source, final long timestampMillis, 379 final long nanoTime) { 380 this.loggerName = loggerName; 381 this.marker = marker; 382 this.loggerFqcn = loggerFQCN; 383 this.level = level == null ? Level.OFF : level; // LOG4J2-462, LOG4J2-465 384 this.message = message; 385 this.thrown = thrown; 386 this.thrownProxy = thrownProxy; 387 this.contextMap = contextMap == null ? ThreadContext.EMPTY_MAP : contextMap; 388 this.contextStack = contextStack == null ? ThreadContext.EMPTY_STACK : contextStack; 389 this.timeMillis = message instanceof TimestampMessage 390 ? ((TimestampMessage) message).getTimestamp() 391 : timestampMillis; 392 this.threadId = threadId; 393 this.threadName = threadName; 394 this.threadPriority = threadPriority; 395 this.source = source; 396 if (message != null && message instanceof LoggerNameAwareMessage) { 397 ((LoggerNameAwareMessage) message).setLoggerName(loggerName); 398 } 399 this.nanoTime = nanoTime; 400 } 401 402 static Map<String, String> createMap(final List<Property> properties) { 403 final Map<String, String> contextMap = ThreadContext.getImmutableContext(); 404 if (properties == null || properties.isEmpty()) { 405 return contextMap; // may be ThreadContext.EMPTY_MAP but not null 406 } 407 final Map<String, String> map = new HashMap<>(contextMap); 408 409 for (final Property prop : properties) { 410 if (!map.containsKey(prop.getName())) { 411 map.put(prop.getName(), prop.getValue()); 412 } 413 } 414 return Collections.unmodifiableMap(map); 415 } 416 417 /** 418 * Returns the {@code NanoClock} to use for creating the nanoTime timestamp of log events. 419 * @return the {@code NanoClock} to use for creating the nanoTime timestamp of log events 420 */ 421 public static NanoClock getNanoClock() { 422 return nanoClock; 423 } 424 425 /** 426 * Sets the {@code NanoClock} to use for creating the nanoTime timestamp of log events. 427 * <p> 428 * FOR INTERNAL USE. This method may be called with a different {@code NanoClock} implementation when the 429 * configuration changes. 430 * 431 * @param nanoClock the {@code NanoClock} to use for creating the nanoTime timestamp of log events 432 */ 433 public static void setNanoClock(final NanoClock nanoClock) { 434 Log4jLogEvent.nanoClock = Objects.requireNonNull(nanoClock, "NanoClock must be non-null"); 435 StatusLogger.getLogger().trace("Using {} for nanosecond timestamps.", nanoClock.getClass().getSimpleName()); 436 } 437 438 /** 439 * Returns a new fully initialized {@code Log4jLogEvent.Builder} containing a copy of all fields of this event. 440 * @return a new fully initialized builder. 441 */ 442 public Builder asBuilder() { 443 return new Builder(this); 444 } 445 446 /** 447 * Returns the logging Level. 448 * @return the Level associated with this event. 449 */ 450 @Override 451 public Level getLevel() { 452 return level; 453 } 454 455 /** 456 * Returns the name of the Logger used to generate the event. 457 * @return The Logger name. 458 */ 459 @Override 460 public String getLoggerName() { 461 return loggerName; 462 } 463 464 /** 465 * Returns the Message associated with the event. 466 * @return The Message. 467 */ 468 @Override 469 public Message getMessage() { 470 return message; 471 } 472 473 public void makeMessageImmutable() { 474 message = new SimpleMessage(message.getFormattedMessage()); 475 } 476 477 @Override 478 public long getThreadId() { 479 if (threadId == 0) { 480 threadId = Thread.currentThread().getId(); 481 } 482 return threadId; 483 } 484 485 /** 486 * Returns the name of the Thread on which the event was generated. 487 * @return The name of the Thread. 488 */ 489 @Override 490 public String getThreadName() { 491 if (threadName == null) { 492 threadName = Thread.currentThread().getName(); 493 } 494 return threadName; 495 } 496 497 @Override 498 public int getThreadPriority() { 499 if (threadPriority == 0) { 500 threadPriority = Thread.currentThread().getPriority(); 501 } 502 return threadPriority; 503 } 504 505 /** 506 * Returns the time in milliseconds from the epoch when the event occurred. 507 * @return The time the event occurred. 508 */ 509 @Override 510 public long getTimeMillis() { 511 return timeMillis; 512 } 513 514 /** 515 * Returns the Throwable associated with the event, or null. 516 * @return The Throwable associated with the event. 517 */ 518 @Override 519 public Throwable getThrown() { 520 return thrown; 521 } 522 523 /** 524 * Returns the ThrowableProxy associated with the event, or null. 525 * @return The ThrowableProxy associated with the event. 526 */ 527 @Override 528 public ThrowableProxy getThrownProxy() { 529 if (thrownProxy == null && thrown != null) { 530 thrownProxy = new ThrowableProxy(thrown); 531 } 532 return thrownProxy; 533 } 534 535 536 /** 537 * Returns the Marker associated with the event, or null. 538 * @return the Marker associated with the event. 539 */ 540 @Override 541 public Marker getMarker() { 542 return marker; 543 } 544 545 /** 546 * The fully qualified class name of the class that was called by the caller. 547 * @return the fully qualified class name of the class that is performing logging. 548 */ 549 @Override 550 public String getLoggerFqcn() { 551 return loggerFqcn; 552 } 553 554 /** 555 * Returns the immutable copy of the ThreadContext Map. 556 * @return The context Map. 557 */ 558 @Override 559 public Map<String, String> getContextMap() { 560 return contextMap; 561 } 562 563 /** 564 * Returns an immutable copy of the ThreadContext stack. 565 * @return The context Stack. 566 */ 567 @Override 568 public ThreadContext.ContextStack getContextStack() { 569 return contextStack; 570 } 571 572 /** 573 * Returns the StackTraceElement for the caller. This will be the entry that occurs right 574 * before the first occurrence of FQCN as a class name. 575 * @return the StackTraceElement for the caller. 576 */ 577 @Override 578 public StackTraceElement getSource() { 579 if (source != null) { 580 return source; 581 } 582 if (loggerFqcn == null || !includeLocation) { 583 return null; 584 } 585 source = calcLocation(loggerFqcn); 586 return source; 587 } 588 589 public static StackTraceElement calcLocation(final String fqcnOfLogger) { 590 if (fqcnOfLogger == null) { 591 return null; 592 } 593 // LOG4J2-1029 new Throwable().getStackTrace is faster than Thread.currentThread().getStackTrace(). 594 final StackTraceElement[] stackTrace = new Throwable().getStackTrace(); 595 StackTraceElement last = null; 596 for (int i = stackTrace.length - 1; i > 0; i--) { 597 final String className = stackTrace[i].getClassName(); 598 if (fqcnOfLogger.equals(className)) { 599 return last; 600 } 601 last = stackTrace[i]; 602 } 603 return null; 604 } 605 606 @Override 607 public boolean isIncludeLocation() { 608 return includeLocation; 609 } 610 611 @Override 612 public void setIncludeLocation(final boolean includeLocation) { 613 this.includeLocation = includeLocation; 614 } 615 616 @Override 617 public boolean isEndOfBatch() { 618 return endOfBatch; 619 } 620 621 @Override 622 public void setEndOfBatch(final boolean endOfBatch) { 623 this.endOfBatch = endOfBatch; 624 } 625 626 @Override 627 public long getNanoTime() { 628 return nanoTime; 629 } 630 631 /** 632 * Creates a LogEventProxy that can be serialized. 633 * @return a LogEventProxy. 634 */ 635 protected Object writeReplace() { 636 getThrownProxy(); // ensure ThrowableProxy is initialized 637 return new LogEventProxy(this, this.includeLocation); 638 } 639 640 /** 641 * Take a snapshot of the specified {@code LogEvent}. 642 * 643 * @param event the event to take a snapshot of 644 * @param includeLocation if true, this method will obtain caller location information 645 * @return snapshot of the event as a {@code Serializable} object 646 * @see #deserialize(Serializable) 647 * @see #serialize(Log4jLogEvent, boolean) 648 */ 649 public static Serializable serialize(final LogEvent event, final boolean includeLocation) { 650 if (event instanceof Log4jLogEvent) { 651 event.getThrownProxy(); // ensure ThrowableProxy is initialized 652 return new LogEventProxy((Log4jLogEvent) event, includeLocation); 653 } 654 return new LogEventProxy(event, includeLocation); 655 } 656 657 /** 658 * Take a snapshot of the specified {@code Log4jLogEvent}. 659 * 660 * @param event the event to take a snapshot of 661 * @param includeLocation if true, this method will obtain caller location information 662 * @return snapshot of the event as a {@code Serializable} object 663 * @see #deserialize(Serializable) 664 * @see #serialize(LogEvent, boolean) 665 */ 666 public static Serializable serialize(final Log4jLogEvent event, final boolean includeLocation) { 667 event.getThrownProxy(); // ensure ThrowableProxy is initialized 668 return new LogEventProxy(event, includeLocation); 669 } 670 671 public static boolean canDeserialize(final Serializable event) { 672 return event instanceof LogEventProxy; 673 } 674 675 public static Log4jLogEvent deserialize(final Serializable event) { 676 Objects.requireNonNull(event, "Event cannot be null"); 677 if (event instanceof LogEventProxy) { 678 final LogEventProxy proxy = (LogEventProxy) event; 679 final Log4jLogEvent result = new Log4jLogEvent(proxy.loggerName, proxy.marker, 680 proxy.loggerFQCN, proxy.level, proxy.message, 681 proxy.thrown, proxy.thrownProxy, proxy.contextMap, proxy.contextStack, proxy.threadId, 682 proxy.threadName, proxy.threadPriority, proxy.source, proxy.timeMillis, proxy.nanoTime); 683 result.setEndOfBatch(proxy.isEndOfBatch); 684 result.setIncludeLocation(proxy.isLocationRequired); 685 return result; 686 } 687 throw new IllegalArgumentException("Event is not a serialized LogEvent: " + event.toString()); 688 } 689 690 private void readObject(final ObjectInputStream stream) throws InvalidObjectException { 691 throw new InvalidObjectException("Proxy required"); 692 } 693 694 /** 695 * Creates and returns a new immutable copy of this {@code Log4jLogEvent}. 696 * 697 * @return a new immutable copy of the data in this {@code Log4jLogEvent} 698 */ 699 public static Log4jLogEvent createMemento(final LogEvent event, final boolean includeLocation) { 700 // TODO implement Log4jLogEvent.createMemento() 701 return deserialize(serialize(event, includeLocation)); 702 } 703 704 @Override 705 public String toString() { 706 final StringBuilder sb = new StringBuilder(); 707 final String n = loggerName.isEmpty() ? LoggerConfig.ROOT : loggerName; 708 sb.append("Logger=").append(n); 709 sb.append(" Level=").append(level.name()); 710 sb.append(" Message=").append(message.getFormattedMessage()); 711 return sb.toString(); 712 } 713 714 @Override 715 public boolean equals(final Object o) { 716 if (this == o) { 717 return true; 718 } 719 if (o == null || getClass() != o.getClass()) { 720 return false; 721 } 722 723 final Log4jLogEvent that = (Log4jLogEvent) o; 724 725 if (endOfBatch != that.endOfBatch) { 726 return false; 727 } 728 if (includeLocation != that.includeLocation) { 729 return false; 730 } 731 if (timeMillis != that.timeMillis) { 732 return false; 733 } 734 if (nanoTime != that.nanoTime) { 735 return false; 736 } 737 if (loggerFqcn != null ? !loggerFqcn.equals(that.loggerFqcn) : that.loggerFqcn != null) { 738 return false; 739 } 740 if (level != null ? !level.equals(that.level) : that.level != null) { 741 return false; 742 } 743 if (source != null ? !source.equals(that.source) : that.source != null) { 744 return false; 745 } 746 if (marker != null ? !marker.equals(that.marker) : that.marker != null) { 747 return false; 748 } 749 if (contextMap != null ? !contextMap.equals(that.contextMap) : that.contextMap != null) { 750 return false; 751 } 752 if (!message.equals(that.message)) { 753 return false; 754 } 755 if (!loggerName.equals(that.loggerName)) { 756 return false; 757 } 758 if (contextStack != null ? !contextStack.equals(that.contextStack) : that.contextStack != null) { 759 return false; 760 } 761 if (threadId != that.threadId) { 762 return false; 763 } 764 if (threadName != null ? !threadName.equals(that.threadName) : that.threadName != null) { 765 return false; 766 } 767 if (threadPriority != that.threadPriority) { 768 return false; 769 } 770 if (thrown != null ? !thrown.equals(that.thrown) : that.thrown != null) { 771 return false; 772 } 773 if (thrownProxy != null ? !thrownProxy.equals(that.thrownProxy) : that.thrownProxy != null) { 774 return false; 775 } 776 777 return true; 778 } 779 780 @Override 781 public int hashCode() { 782 // Check:OFF: MagicNumber 783 int result = loggerFqcn != null ? loggerFqcn.hashCode() : 0; 784 result = 31 * result + (marker != null ? marker.hashCode() : 0); 785 result = 31 * result + (level != null ? level.hashCode() : 0); 786 result = 31 * result + loggerName.hashCode(); 787 result = 31 * result + message.hashCode(); 788 result = 31 * result + (int) (timeMillis ^ (timeMillis >>> 32)); 789 result = 31 * result + (int) (nanoTime ^ (nanoTime >>> 32)); 790 result = 31 * result + (thrown != null ? thrown.hashCode() : 0); 791 result = 31 * result + (thrownProxy != null ? thrownProxy.hashCode() : 0); 792 result = 31 * result + (contextMap != null ? contextMap.hashCode() : 0); 793 result = 31 * result + (contextStack != null ? contextStack.hashCode() : 0); 794 result = 31 * result + (int) (threadId ^ (threadId >>> 32)); 795 result = 31 * result + (threadName != null ? threadName.hashCode() : 0); 796 result = 31 * result + (threadPriority ^ (threadPriority >>> 32)); 797 result = 31 * result + (source != null ? source.hashCode() : 0); 798 result = 31 * result + (includeLocation ? 1 : 0); 799 result = 31 * result + (endOfBatch ? 1 : 0); 800 // Check:ON: MagicNumber 801 return result; 802 } 803 804 /** 805 * Proxy pattern used to serialize the LogEvent. 806 */ 807 static class LogEventProxy implements Serializable { 808 809 private static final long serialVersionUID = -8634075037355293699L; 810 private final String loggerFQCN; 811 private final Marker marker; 812 private final Level level; 813 private final String loggerName; 814 private final Message message; 815 private final long timeMillis; 816 private final transient Throwable thrown; 817 private final ThrowableProxy thrownProxy; 818 private final Map<String, String> contextMap; 819 private final ThreadContext.ContextStack contextStack; 820 /** @since 2.6 */ 821 private final long threadId; 822 private final String threadName; 823 /** @since 2.6 */ 824 private final int threadPriority; 825 private final StackTraceElement source; 826 private final boolean isLocationRequired; 827 private final boolean isEndOfBatch; 828 /** @since 2.4 */ 829 private final transient long nanoTime; 830 831 public LogEventProxy(final Log4jLogEvent event, final boolean includeLocation) { 832 this.loggerFQCN = event.loggerFqcn; 833 this.marker = event.marker; 834 this.level = event.level; 835 this.loggerName = event.loggerName; 836 this.message = event.message instanceof ReusableMessage 837 ? memento((ReusableMessage) event.message) 838 : event.message; 839 this.timeMillis = event.timeMillis; 840 this.thrown = event.thrown; 841 this.thrownProxy = event.thrownProxy; 842 this.contextMap = event.contextMap; 843 this.contextStack = event.contextStack; 844 this.source = includeLocation ? event.getSource() : null; 845 this.threadId = event.getThreadId(); 846 this.threadName = event.getThreadName(); 847 this.threadPriority = event.getThreadPriority(); 848 this.isLocationRequired = includeLocation; 849 this.isEndOfBatch = event.endOfBatch; 850 this.nanoTime = event.nanoTime; 851 } 852 853 public LogEventProxy(final LogEvent event, final boolean includeLocation) { 854 this.loggerFQCN = event.getLoggerFqcn(); 855 this.marker = event.getMarker(); 856 this.level = event.getLevel(); 857 this.loggerName = event.getLoggerName(); 858 859 final Message msg = event.getMessage(); 860 this.message = msg instanceof ReusableMessage 861 ? memento((ReusableMessage) msg) 862 : msg; 863 this.timeMillis = event.getTimeMillis(); 864 this.thrown = event.getThrown(); 865 this.thrownProxy = event.getThrownProxy(); 866 this.contextMap = event.getContextMap(); 867 this.contextStack = event.getContextStack(); 868 this.source = includeLocation ? event.getSource() : null; 869 this.threadId = event.getThreadId(); 870 this.threadName = event.getThreadName(); 871 this.threadPriority = event.getThreadPriority(); 872 this.isLocationRequired = includeLocation; 873 this.isEndOfBatch = event.isEndOfBatch(); 874 this.nanoTime = event.getNanoTime(); 875 } 876 877 private Message memento(final ReusableMessage message) { 878 return message.memento(); 879 } 880 881 /** 882 * Returns a Log4jLogEvent using the data in the proxy. 883 * @return Log4jLogEvent. 884 */ 885 protected Object readResolve() { 886 final Log4jLogEvent result = new Log4jLogEvent(loggerName, marker, loggerFQCN, level, message, thrown, 887 thrownProxy, contextMap, contextStack, threadId, threadName, threadPriority, source, timeMillis, nanoTime); 888 result.setEndOfBatch(isEndOfBatch); 889 result.setIncludeLocation(isLocationRequired); 890 return result; 891 } 892 } 893 894}