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