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