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