View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements. See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache license, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License. You may obtain a copy of the License at
8    *
9    *      http://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the license for the specific language governing permissions and
15   * limitations under the license.
16   */
17  package org.apache.logging.log4j.core.impl;
18  
19  import java.io.IOException;
20  import java.io.InvalidObjectException;
21  import java.io.ObjectInputStream;
22  import java.io.Serializable;
23  import java.rmi.MarshalledObject;
24  import java.util.List;
25  import java.util.Map;
26  import java.util.Objects;
27  
28  import org.apache.logging.log4j.Level;
29  import org.apache.logging.log4j.Marker;
30  import org.apache.logging.log4j.ThreadContext;
31  import org.apache.logging.log4j.core.ContextDataInjector;
32  import org.apache.logging.log4j.core.util.*;
33  import org.apache.logging.log4j.core.time.Instant;
34  import org.apache.logging.log4j.core.time.MutableInstant;
35  import org.apache.logging.log4j.util.ReadOnlyStringMap;
36  import org.apache.logging.log4j.core.LogEvent;
37  import org.apache.logging.log4j.core.async.RingBufferLogEvent;
38  import org.apache.logging.log4j.core.config.LoggerConfig;
39  import org.apache.logging.log4j.core.config.Property;
40  import org.apache.logging.log4j.message.LoggerNameAwareMessage;
41  import org.apache.logging.log4j.message.Message;
42  import org.apache.logging.log4j.message.ReusableMessage;
43  import org.apache.logging.log4j.message.SimpleMessage;
44  import org.apache.logging.log4j.message.TimestampMessage;
45  import org.apache.logging.log4j.util.StackLocatorUtil;
46  import org.apache.logging.log4j.util.StringMap;
47  import org.apache.logging.log4j.status.StatusLogger;
48  import org.apache.logging.log4j.util.Strings;
49  
50  /**
51   * Implementation of a LogEvent.
52   */
53  public class Log4jLogEvent implements LogEvent {
54  
55      private static final long serialVersionUID = -8393305700508709443L;
56      private static final Clock CLOCK = ClockFactory.getClock();
57      private static volatile NanoClock nanoClock = new DummyNanoClock();
58      private static final ContextDataInjector CONTEXT_DATA_INJECTOR = ContextDataInjectorFactory.createInjector();
59  
60      private final String loggerFqcn;
61      private final Marker marker;
62      private final Level level;
63      private final String loggerName;
64      private Message message;
65      private final MutableInstant instant = new MutableInstant();
66      private final transient Throwable thrown;
67      private ThrowableProxy thrownProxy;
68      private final StringMap contextData;
69      private final ThreadContext.ContextStack contextStack;
70      private long threadId;
71      private String threadName;
72      private int threadPriority;
73      private StackTraceElement source;
74      private boolean includeLocation;
75      private boolean endOfBatch = false;
76      /** @since Log4J 2.4 */
77      private final transient long nanoTime;
78  
79      /** LogEvent Builder helper class. */
80      public static class Builder implements org.apache.logging.log4j.core.util.Builder<LogEvent> {
81  
82          private String loggerFqcn;
83          private Marker marker;
84          private Level level;
85          private String loggerName;
86          private Message message;
87          private Throwable thrown;
88          private final MutableInstant instant = new MutableInstant();
89          private ThrowableProxy thrownProxy;
90          private StringMap contextData = createContextData((List<Property>) null);
91          private ThreadContext.ContextStack contextStack = ThreadContext.getImmutableStack();
92          private long threadId;
93          private String threadName;
94          private int threadPriority;
95          private StackTraceElement source;
96          private boolean includeLocation;
97          private boolean endOfBatch = false;
98          private long nanoTime;
99  
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 }