1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.apache.logging.log4j.core.impl;
18
19 import java.io.InvalidObjectException;
20 import java.io.ObjectInputStream;
21 import java.io.Serializable;
22 import java.util.Collections;
23 import java.util.HashMap;
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.LogEvent;
32 import org.apache.logging.log4j.core.async.RingBufferLogEvent;
33 import org.apache.logging.log4j.core.config.LoggerConfig;
34 import org.apache.logging.log4j.core.config.Property;
35 import org.apache.logging.log4j.core.util.Clock;
36 import org.apache.logging.log4j.core.util.ClockFactory;
37 import org.apache.logging.log4j.core.util.DummyNanoClock;
38 import org.apache.logging.log4j.core.util.NanoClock;
39 import org.apache.logging.log4j.message.LoggerNameAwareMessage;
40 import org.apache.logging.log4j.message.Message;
41 import org.apache.logging.log4j.message.ReusableMessage;
42 import org.apache.logging.log4j.message.SimpleMessage;
43 import org.apache.logging.log4j.message.TimestampMessage;
44 import org.apache.logging.log4j.status.StatusLogger;
45 import org.apache.logging.log4j.util.Strings;
46
47
48
49
50 public class Log4jLogEvent implements LogEvent {
51
52 private static final long serialVersionUID = -8393305700508709443L;
53 private static final Clock CLOCK = ClockFactory.getClock();
54 private static volatile NanoClock nanoClock = new DummyNanoClock();
55 private final String loggerFqcn;
56 private final Marker marker;
57 private final Level level;
58 private final String loggerName;
59 private Message message;
60 private final long timeMillis;
61 private final transient Throwable thrown;
62 private ThrowableProxy thrownProxy;
63 private final Map<String, String> contextMap;
64 private final ThreadContext.ContextStack contextStack;
65 private long threadId;
66 private String threadName;
67 private int threadPriority;
68 private StackTraceElement source;
69 private boolean includeLocation;
70 private boolean endOfBatch = false;
71
72 private final transient long nanoTime;
73
74
75 public static class Builder implements org.apache.logging.log4j.core.util.Builder<LogEvent> {
76
77 private String loggerFqcn;
78 private Marker marker;
79 private Level level;
80 private String loggerName;
81 private Message message;
82 private Throwable thrown;
83 private long timeMillis = CLOCK.currentTimeMillis();
84 private ThrowableProxy thrownProxy;
85 private Map<String, String> contextMap = ThreadContext.getImmutableContext();
86 private ThreadContext.ContextStack contextStack = ThreadContext.getImmutableStack();
87 private long threadId;
88 private String threadName;
89 private int threadPriority;
90 private StackTraceElement source;
91 private boolean includeLocation;
92 private boolean endOfBatch = false;
93 private long nanoTime;
94
95 public Builder() {
96 }
97
98 public Builder(final LogEvent other) {
99 Objects.requireNonNull(other);
100 if (other instanceof RingBufferLogEvent) {
101 ((RingBufferLogEvent) other).initializeBuilder(this);
102 return;
103 }
104 if (other instanceof MutableLogEvent) {
105 ((MutableLogEvent) other).initializeBuilder(this);
106 return;
107 }
108 this.loggerFqcn = other.getLoggerFqcn();
109 this.marker = other.getMarker();
110 this.level = other.getLevel();
111 this.loggerName = other.getLoggerName();
112 this.message = other.getMessage();
113 this.timeMillis = other.getTimeMillis();
114 this.thrown = other.getThrown();
115 this.contextMap = other.getContextMap();
116 this.contextStack = other.getContextStack();
117 this.includeLocation = other.isIncludeLocation();
118 this.endOfBatch = other.isEndOfBatch();
119 this.nanoTime = other.getNanoTime();
120
121
122 if (other instanceof Log4jLogEvent) {
123 final Log4jLogEvent evt = (Log4jLogEvent) other;
124 this.thrownProxy = evt.thrownProxy;
125 this.source = evt.source;
126 this.threadId = evt.threadId;
127 this.threadName = evt.threadName;
128 this.threadPriority = evt.threadPriority;
129 } else {
130 this.thrownProxy = other.getThrownProxy();
131 this.source = other.getSource();
132 this.threadId = other.getThreadId();
133 this.threadName = other.getThreadName();
134 this.threadPriority = other.getThreadPriority();
135 }
136 }
137
138 public Builder setLevel(final Level level) {
139 this.level = level;
140 return this;
141 }
142
143 public Builder setLoggerFqcn(final String loggerFqcn) {
144 this.loggerFqcn = loggerFqcn;
145 return this;
146 }
147
148 public Builder setLoggerName(final String loggerName) {
149 this.loggerName = loggerName;
150 return this;
151 }
152
153 public Builder setMarker(final Marker marker) {
154 this.marker = marker;
155 return this;
156 }
157
158 public Builder setMessage(final Message message) {
159 this.message = message;
160 return this;
161 }
162
163 public Builder setThrown(final Throwable thrown) {
164 this.thrown = thrown;
165 return this;
166 }
167
168 public Builder setTimeMillis(final long timeMillis) {
169 this.timeMillis = timeMillis;
170 return this;
171 }
172
173 public Builder setThrownProxy(final ThrowableProxy thrownProxy) {
174 this.thrownProxy = thrownProxy;
175 return this;
176 }
177
178 public Builder setContextMap(final Map<String, String> contextMap) {
179 this.contextMap = contextMap;
180 return this;
181 }
182
183 public Builder setContextStack(final ThreadContext.ContextStack contextStack) {
184 this.contextStack = contextStack;
185 return this;
186 }
187
188 public Builder setThreadId(final long threadId) {
189 this.threadId = threadId;
190 return this;
191 }
192
193 public Builder setThreadName(final String threadName) {
194 this.threadName = threadName;
195 return this;
196 }
197
198 public Builder setThreadPriority(final int threadPriority) {
199 this.threadPriority = threadPriority;
200 return this;
201 }
202
203 public Builder setSource(final StackTraceElement source) {
204 this.source = source;
205 return this;
206 }
207
208 public Builder setIncludeLocation(final boolean includeLocation) {
209 this.includeLocation = includeLocation;
210 return this;
211 }
212
213 public Builder setEndOfBatch(final boolean endOfBatch) {
214 this.endOfBatch = endOfBatch;
215 return this;
216 }
217
218
219
220
221
222
223
224 public Builder setNanoTime(final long nanoTime) {
225 this.nanoTime = nanoTime;
226 return this;
227 }
228
229 @Override
230 public Log4jLogEvent build() {
231 final Log4jLogEvent result = new Log4jLogEvent(loggerName, marker, loggerFqcn, level, message, thrown,
232 thrownProxy, contextMap, contextStack, threadId, threadName, threadPriority, source, timeMillis, nanoTime);
233 result.setIncludeLocation(includeLocation);
234 result.setEndOfBatch(endOfBatch);
235 return result;
236 }
237 }
238
239
240
241
242
243 public static Builder newBuilder() {
244 return new Builder();
245 }
246
247 public Log4jLogEvent() {
248 this(Strings.EMPTY, null, Strings.EMPTY, null, null, (Throwable) null, null, null, null, 0, null,
249 0, null, CLOCK.currentTimeMillis(), nanoClock.nanoTime());
250 }
251
252
253
254
255
256 @Deprecated
257 public Log4jLogEvent(final long timestamp) {
258 this(Strings.EMPTY, null, Strings.EMPTY, null, null, (Throwable) null, null, null, null, 0, null,
259 0, null, timestamp, nanoClock.nanoTime());
260 }
261
262
263
264
265
266
267
268
269
270
271
272 @Deprecated
273 public Log4jLogEvent(final String loggerName, final Marker marker, final String loggerFQCN, final Level level,
274 final Message message, final Throwable t) {
275 this(loggerName, marker, loggerFQCN, level, message, null, t);
276 }
277
278
279
280
281
282
283
284
285
286
287
288
289 public Log4jLogEvent(final String loggerName, final Marker marker, final String loggerFQCN, final Level level,
290 final Message message, final List<Property> properties, final Throwable t) {
291 this(loggerName, marker, loggerFQCN, level, message, t, null,
292 createMap(properties),
293 ThreadContext.getDepth() == 0 ? null : ThreadContext.cloneStack(),
294 0,
295 null,
296 0,
297 null,
298
299 message instanceof TimestampMessage ? ((TimestampMessage) message).getTimestamp() :
300 CLOCK.currentTimeMillis(), nanoClock.nanoTime());
301 }
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318 @Deprecated
319 public Log4jLogEvent(final String loggerName, final Marker marker, final String loggerFQCN, final Level level,
320 final Message message, final Throwable t, final Map<String, String> mdc,
321 final ThreadContext.ContextStack ndc, final String threadName,
322 final StackTraceElement location, final long timestampMillis) {
323 this(loggerName, marker, loggerFQCN, level, message, t, null, mdc, ndc, 0,
324 threadName, 0, location, timestampMillis, nanoClock.nanoTime());
325 }
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344 @Deprecated
345 public static Log4jLogEvent createEvent(final String loggerName, final Marker marker, final String loggerFQCN,
346 final Level level, final Message message, final Throwable thrown,
347 final ThrowableProxy thrownProxy,
348 final Map<String, String> mdc, final ThreadContext.ContextStack ndc,
349 final String threadName, final StackTraceElement location,
350 final long timestamp) {
351 final Log4jLogEvent result = new Log4jLogEvent(loggerName, marker, loggerFQCN, level, message, thrown,
352 thrownProxy, mdc, ndc, 0, threadName, 0, location, timestamp, nanoClock.nanoTime());
353 return result;
354 }
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375 private Log4jLogEvent(final String loggerName, final Marker marker, final String loggerFQCN, final Level level,
376 final Message message, final Throwable thrown, final ThrowableProxy thrownProxy,
377 final Map<String, String> contextMap, final ThreadContext.ContextStack contextStack, final long threadId,
378 final String threadName, final int threadPriority, final StackTraceElement source, final long timestampMillis,
379 final long nanoTime) {
380 this.loggerName = loggerName;
381 this.marker = marker;
382 this.loggerFqcn = loggerFQCN;
383 this.level = level == null ? Level.OFF : level;
384 this.message = message;
385 this.thrown = thrown;
386 this.thrownProxy = thrownProxy;
387 this.contextMap = contextMap == null ? ThreadContext.EMPTY_MAP : contextMap;
388 this.contextStack = contextStack == null ? ThreadContext.EMPTY_STACK : contextStack;
389 this.timeMillis = message instanceof TimestampMessage
390 ? ((TimestampMessage) message).getTimestamp()
391 : timestampMillis;
392 this.threadId = threadId;
393 this.threadName = threadName;
394 this.threadPriority = threadPriority;
395 this.source = source;
396 if (message != null && message instanceof LoggerNameAwareMessage) {
397 ((LoggerNameAwareMessage) message).setLoggerName(loggerName);
398 }
399 this.nanoTime = nanoTime;
400 }
401
402 static Map<String, String> createMap(final List<Property> properties) {
403 final Map<String, String> contextMap = ThreadContext.getImmutableContext();
404 if (properties == null || properties.isEmpty()) {
405 return contextMap;
406 }
407 final Map<String, String> map = new HashMap<>(contextMap);
408
409 for (final Property prop : properties) {
410 if (!map.containsKey(prop.getName())) {
411 map.put(prop.getName(), prop.getValue());
412 }
413 }
414 return Collections.unmodifiableMap(map);
415 }
416
417
418
419
420
421 public static NanoClock getNanoClock() {
422 return nanoClock;
423 }
424
425
426
427
428
429
430
431
432
433 public static void setNanoClock(final NanoClock nanoClock) {
434 Log4jLogEvent.nanoClock = Objects.requireNonNull(nanoClock, "NanoClock must be non-null");
435 StatusLogger.getLogger().trace("Using {} for nanosecond timestamps.", nanoClock.getClass().getSimpleName());
436 }
437
438
439
440
441
442 public Builder asBuilder() {
443 return new Builder(this);
444 }
445
446
447
448
449
450 @Override
451 public Level getLevel() {
452 return level;
453 }
454
455
456
457
458
459 @Override
460 public String getLoggerName() {
461 return loggerName;
462 }
463
464
465
466
467
468 @Override
469 public Message getMessage() {
470 return message;
471 }
472
473 public void makeMessageImmutable() {
474 message = new SimpleMessage(message.getFormattedMessage());
475 }
476
477 @Override
478 public long getThreadId() {
479 if (threadId == 0) {
480 threadId = Thread.currentThread().getId();
481 }
482 return threadId;
483 }
484
485
486
487
488
489 @Override
490 public String getThreadName() {
491 if (threadName == null) {
492 threadName = Thread.currentThread().getName();
493 }
494 return threadName;
495 }
496
497 @Override
498 public int getThreadPriority() {
499 if (threadPriority == 0) {
500 threadPriority = Thread.currentThread().getPriority();
501 }
502 return threadPriority;
503 }
504
505
506
507
508
509 @Override
510 public long getTimeMillis() {
511 return timeMillis;
512 }
513
514
515
516
517
518 @Override
519 public Throwable getThrown() {
520 return thrown;
521 }
522
523
524
525
526
527 @Override
528 public ThrowableProxy getThrownProxy() {
529 if (thrownProxy == null && thrown != null) {
530 thrownProxy = new ThrowableProxy(thrown);
531 }
532 return thrownProxy;
533 }
534
535
536
537
538
539
540 @Override
541 public Marker getMarker() {
542 return marker;
543 }
544
545
546
547
548
549 @Override
550 public String getLoggerFqcn() {
551 return loggerFqcn;
552 }
553
554
555
556
557
558 @Override
559 public Map<String, String> getContextMap() {
560 return contextMap;
561 }
562
563
564
565
566
567 @Override
568 public ThreadContext.ContextStack getContextStack() {
569 return contextStack;
570 }
571
572
573
574
575
576
577 @Override
578 public StackTraceElement getSource() {
579 if (source != null) {
580 return source;
581 }
582 if (loggerFqcn == null || !includeLocation) {
583 return null;
584 }
585 source = calcLocation(loggerFqcn);
586 return source;
587 }
588
589 public static StackTraceElement calcLocation(final String fqcnOfLogger) {
590 if (fqcnOfLogger == null) {
591 return null;
592 }
593
594 final StackTraceElement[] stackTrace = new Throwable().getStackTrace();
595 StackTraceElement last = null;
596 for (int i = stackTrace.length - 1; i > 0; i--) {
597 final String className = stackTrace[i].getClassName();
598 if (fqcnOfLogger.equals(className)) {
599 return last;
600 }
601 last = stackTrace[i];
602 }
603 return null;
604 }
605
606 @Override
607 public boolean isIncludeLocation() {
608 return includeLocation;
609 }
610
611 @Override
612 public void setIncludeLocation(final boolean includeLocation) {
613 this.includeLocation = includeLocation;
614 }
615
616 @Override
617 public boolean isEndOfBatch() {
618 return endOfBatch;
619 }
620
621 @Override
622 public void setEndOfBatch(final boolean endOfBatch) {
623 this.endOfBatch = endOfBatch;
624 }
625
626 @Override
627 public long getNanoTime() {
628 return nanoTime;
629 }
630
631
632
633
634
635 protected Object writeReplace() {
636 getThrownProxy();
637 return new LogEventProxy(this, this.includeLocation);
638 }
639
640
641
642
643
644
645
646
647
648
649 public static Serializable serialize(final LogEvent event, final boolean includeLocation) {
650 if (event instanceof Log4jLogEvent) {
651 event.getThrownProxy();
652 return new LogEventProxy((Log4jLogEvent) event, includeLocation);
653 }
654 return new LogEventProxy(event, includeLocation);
655 }
656
657
658
659
660
661
662
663
664
665
666 public static Serializable serialize(final Log4jLogEvent event, final boolean includeLocation) {
667 event.getThrownProxy();
668 return new LogEventProxy(event, includeLocation);
669 }
670
671 public static boolean canDeserialize(final Serializable event) {
672 return event instanceof LogEventProxy;
673 }
674
675 public static Log4jLogEvent deserialize(final Serializable event) {
676 Objects.requireNonNull(event, "Event cannot be null");
677 if (event instanceof LogEventProxy) {
678 final LogEventProxy proxy = (LogEventProxy) event;
679 final Log4jLogEvent result = new Log4jLogEvent(proxy.loggerName, proxy.marker,
680 proxy.loggerFQCN, proxy.level, proxy.message,
681 proxy.thrown, proxy.thrownProxy, proxy.contextMap, proxy.contextStack, proxy.threadId,
682 proxy.threadName, proxy.threadPriority, proxy.source, proxy.timeMillis, proxy.nanoTime);
683 result.setEndOfBatch(proxy.isEndOfBatch);
684 result.setIncludeLocation(proxy.isLocationRequired);
685 return result;
686 }
687 throw new IllegalArgumentException("Event is not a serialized LogEvent: " + event.toString());
688 }
689
690 private void readObject(final ObjectInputStream stream) throws InvalidObjectException {
691 throw new InvalidObjectException("Proxy required");
692 }
693
694
695
696
697
698
699 public static Log4jLogEvent createMemento(final LogEvent event, final boolean includeLocation) {
700
701 return deserialize(serialize(event, includeLocation));
702 }
703
704 @Override
705 public String toString() {
706 final StringBuilder sb = new StringBuilder();
707 final String n = loggerName.isEmpty() ? LoggerConfig.ROOT : loggerName;
708 sb.append("Logger=").append(n);
709 sb.append(" Level=").append(level.name());
710 sb.append(" Message=").append(message.getFormattedMessage());
711 return sb.toString();
712 }
713
714 @Override
715 public boolean equals(final Object o) {
716 if (this == o) {
717 return true;
718 }
719 if (o == null || getClass() != o.getClass()) {
720 return false;
721 }
722
723 final Log4jLogEvent that = (Log4jLogEvent) o;
724
725 if (endOfBatch != that.endOfBatch) {
726 return false;
727 }
728 if (includeLocation != that.includeLocation) {
729 return false;
730 }
731 if (timeMillis != that.timeMillis) {
732 return false;
733 }
734 if (nanoTime != that.nanoTime) {
735 return false;
736 }
737 if (loggerFqcn != null ? !loggerFqcn.equals(that.loggerFqcn) : that.loggerFqcn != null) {
738 return false;
739 }
740 if (level != null ? !level.equals(that.level) : that.level != null) {
741 return false;
742 }
743 if (source != null ? !source.equals(that.source) : that.source != null) {
744 return false;
745 }
746 if (marker != null ? !marker.equals(that.marker) : that.marker != null) {
747 return false;
748 }
749 if (contextMap != null ? !contextMap.equals(that.contextMap) : that.contextMap != null) {
750 return false;
751 }
752 if (!message.equals(that.message)) {
753 return false;
754 }
755 if (!loggerName.equals(that.loggerName)) {
756 return false;
757 }
758 if (contextStack != null ? !contextStack.equals(that.contextStack) : that.contextStack != null) {
759 return false;
760 }
761 if (threadId != that.threadId) {
762 return false;
763 }
764 if (threadName != null ? !threadName.equals(that.threadName) : that.threadName != null) {
765 return false;
766 }
767 if (threadPriority != that.threadPriority) {
768 return false;
769 }
770 if (thrown != null ? !thrown.equals(that.thrown) : that.thrown != null) {
771 return false;
772 }
773 if (thrownProxy != null ? !thrownProxy.equals(that.thrownProxy) : that.thrownProxy != null) {
774 return false;
775 }
776
777 return true;
778 }
779
780 @Override
781 public int hashCode() {
782
783 int result = loggerFqcn != null ? loggerFqcn.hashCode() : 0;
784 result = 31 * result + (marker != null ? marker.hashCode() : 0);
785 result = 31 * result + (level != null ? level.hashCode() : 0);
786 result = 31 * result + loggerName.hashCode();
787 result = 31 * result + message.hashCode();
788 result = 31 * result + (int) (timeMillis ^ (timeMillis >>> 32));
789 result = 31 * result + (int) (nanoTime ^ (nanoTime >>> 32));
790 result = 31 * result + (thrown != null ? thrown.hashCode() : 0);
791 result = 31 * result + (thrownProxy != null ? thrownProxy.hashCode() : 0);
792 result = 31 * result + (contextMap != null ? contextMap.hashCode() : 0);
793 result = 31 * result + (contextStack != null ? contextStack.hashCode() : 0);
794 result = 31 * result + (int) (threadId ^ (threadId >>> 32));
795 result = 31 * result + (threadName != null ? threadName.hashCode() : 0);
796 result = 31 * result + (threadPriority ^ (threadPriority >>> 32));
797 result = 31 * result + (source != null ? source.hashCode() : 0);
798 result = 31 * result + (includeLocation ? 1 : 0);
799 result = 31 * result + (endOfBatch ? 1 : 0);
800
801 return result;
802 }
803
804
805
806
807 static class LogEventProxy implements Serializable {
808
809 private static final long serialVersionUID = -8634075037355293699L;
810 private final String loggerFQCN;
811 private final Marker marker;
812 private final Level level;
813 private final String loggerName;
814 private final Message message;
815 private final long timeMillis;
816 private final transient Throwable thrown;
817 private final ThrowableProxy thrownProxy;
818 private final Map<String, String> contextMap;
819 private final ThreadContext.ContextStack contextStack;
820
821 private final long threadId;
822 private final String threadName;
823
824 private final int threadPriority;
825 private final StackTraceElement source;
826 private final boolean isLocationRequired;
827 private final boolean isEndOfBatch;
828
829 private final transient long nanoTime;
830
831 public LogEventProxy(final Log4jLogEvent event, final boolean includeLocation) {
832 this.loggerFQCN = event.loggerFqcn;
833 this.marker = event.marker;
834 this.level = event.level;
835 this.loggerName = event.loggerName;
836 this.message = event.message instanceof ReusableMessage
837 ? memento((ReusableMessage) event.message)
838 : event.message;
839 this.timeMillis = event.timeMillis;
840 this.thrown = event.thrown;
841 this.thrownProxy = event.thrownProxy;
842 this.contextMap = event.contextMap;
843 this.contextStack = event.contextStack;
844 this.source = includeLocation ? event.getSource() : null;
845 this.threadId = event.getThreadId();
846 this.threadName = event.getThreadName();
847 this.threadPriority = event.getThreadPriority();
848 this.isLocationRequired = includeLocation;
849 this.isEndOfBatch = event.endOfBatch;
850 this.nanoTime = event.nanoTime;
851 }
852
853 public LogEventProxy(final LogEvent event, final boolean includeLocation) {
854 this.loggerFQCN = event.getLoggerFqcn();
855 this.marker = event.getMarker();
856 this.level = event.getLevel();
857 this.loggerName = event.getLoggerName();
858
859 final Message msg = event.getMessage();
860 this.message = msg instanceof ReusableMessage
861 ? memento((ReusableMessage) msg)
862 : msg;
863 this.timeMillis = event.getTimeMillis();
864 this.thrown = event.getThrown();
865 this.thrownProxy = event.getThrownProxy();
866 this.contextMap = event.getContextMap();
867 this.contextStack = event.getContextStack();
868 this.source = includeLocation ? event.getSource() : null;
869 this.threadId = event.getThreadId();
870 this.threadName = event.getThreadName();
871 this.threadPriority = event.getThreadPriority();
872 this.isLocationRequired = includeLocation;
873 this.isEndOfBatch = event.isEndOfBatch();
874 this.nanoTime = event.getNanoTime();
875 }
876
877 private Message memento(final ReusableMessage message) {
878 return message.memento();
879 }
880
881
882
883
884
885 protected Object readResolve() {
886 final Log4jLogEvent result = new Log4jLogEvent(loggerName, marker, loggerFQCN, level, message, thrown,
887 thrownProxy, contextMap, contextStack, threadId, threadName, threadPriority, source, timeMillis, nanoTime);
888 result.setEndOfBatch(isEndOfBatch);
889 result.setIncludeLocation(isLocationRequired);
890 return result;
891 }
892 }
893
894 }