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