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