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
27 import org.apache.logging.log4j.Level;
28 import org.apache.logging.log4j.Marker;
29 import org.apache.logging.log4j.ThreadContext;
30 import org.apache.logging.log4j.core.LogEvent;
31 import org.apache.logging.log4j.core.config.Property;
32 import org.apache.logging.log4j.core.util.Clock;
33 import org.apache.logging.log4j.core.util.ClockFactory;
34 import org.apache.logging.log4j.message.LoggerNameAwareMessage;
35 import org.apache.logging.log4j.message.Message;
36 import org.apache.logging.log4j.message.TimestampMessage;
37 import org.apache.logging.log4j.util.Strings;
38
39
40
41
42 public class Log4jLogEvent implements LogEvent {
43
44 private static final long serialVersionUID = -1351367343806656055L;
45 private static final Clock clock = ClockFactory.getClock();
46 private final String loggerFqcn;
47 private final Marker marker;
48 private final Level level;
49 private final String loggerName;
50 private final Message message;
51 private final long timeMillis;
52 private transient final Throwable thrown;
53 private ThrowableProxy thrownProxy;
54 private final Map<String, String> contextMap;
55 private final ThreadContext.ContextStack contextStack;
56 private String threadName = null;
57 private StackTraceElement source;
58 private boolean includeLocation;
59 private boolean endOfBatch = false;
60
61 public static class Builder implements org.apache.logging.log4j.core.util.Builder<LogEvent> {
62
63 private String loggerFqcn;
64 private Marker marker;
65 private Level level;
66 private String loggerName;
67 private Message message;
68 private Throwable thrown;
69
70 public Builder setLoggerFqcn(final String loggerFqcn) {
71 this.loggerFqcn = loggerFqcn;
72 return this;
73 }
74
75 public Builder setMarker(final Marker marker) {
76 this.marker = marker;
77 return this;
78 }
79
80 public Builder setLevel(final Level level) {
81 this.level = level;
82 return this;
83 }
84
85 public Builder setLoggerName(final String loggerName) {
86 this.loggerName = loggerName;
87 return this;
88 }
89
90 public Builder setMessage(final Message message) {
91 this.message = message;
92 return this;
93 }
94
95 public Builder setThrown(final Throwable thrown) {
96 this.thrown = thrown;
97 return this;
98 }
99
100 @Override
101 public Log4jLogEvent build() {
102 return new Log4jLogEvent(loggerName, marker, loggerFqcn, level, message, thrown);
103 }
104 }
105
106 public static Builder newBuilder() {
107 return new Builder();
108 }
109
110 public Log4jLogEvent() {
111 this(clock.currentTimeMillis());
112 }
113
114
115
116
117 public Log4jLogEvent(final long timestamp) {
118 this(Strings.EMPTY, null, Strings.EMPTY, null, null, (Throwable) null, null, null, null, null, timestamp);
119 }
120
121
122
123
124
125
126
127
128
129
130 public Log4jLogEvent(final String loggerName, final Marker marker, final String loggerFQCN, final Level level,
131 final Message message, final Throwable t) {
132 this(loggerName, marker, loggerFQCN, level, message, null, t);
133 }
134
135
136
137
138
139
140
141
142
143
144
145 public Log4jLogEvent(final String loggerName, final Marker marker, final String loggerFQCN, final Level level,
146 final Message message, final List<Property> properties, final Throwable t) {
147 this(loggerName, marker, loggerFQCN, level, message, t,
148 createMap(properties),
149 ThreadContext.getDepth() == 0 ? null : ThreadContext.cloneStack(), null,
150 null,
151
152
153 message instanceof TimestampMessage ? ((TimestampMessage) message).getTimestamp() :
154 clock.currentTimeMillis());
155 }
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171 public Log4jLogEvent(final String loggerName, final Marker marker, final String loggerFQCN, final Level level,
172 final Message message, final Throwable t, final Map<String, String> mdc,
173 final ThreadContext.ContextStack ndc, final String threadName,
174 final StackTraceElement location, final long timestamp) {
175 this(loggerName, marker, loggerFQCN, level, message, t, null, mdc, ndc, threadName,
176 location, timestamp);
177 }
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194 public static Log4jLogEvent createEvent(final String loggerName, final Marker marker, final String loggerFQCN,
195 final Level level, final Message message, final Throwable thrown,
196 final ThrowableProxy thrownProxy,
197 final Map<String, String> mdc, final ThreadContext.ContextStack ndc,
198 final String threadName, final StackTraceElement location,
199 final long timestamp) {
200 final Log4jLogEvent result = new Log4jLogEvent(loggerName, marker, loggerFQCN, level, message, thrown,
201 thrownProxy, mdc, ndc, threadName, location, timestamp);
202 return result;
203 }
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220 private Log4jLogEvent(final String loggerName, final Marker marker, final String loggerFQCN, final Level level,
221 final Message message, final Throwable thrown, final ThrowableProxy thrownProxy,
222 final Map<String, String> contextMap, final ThreadContext.ContextStack contextStack,
223 final String threadName, final StackTraceElement source, final long timestamp) {
224 this.loggerName = loggerName;
225 this.marker = marker;
226 this.loggerFqcn = loggerFQCN;
227 this.level = (level == null) ? Level.OFF : level;
228 this.message = message;
229 this.thrown = thrown;
230 this.thrownProxy = thrownProxy;
231 this.contextMap = contextMap == null ? ThreadContext.EMPTY_MAP : contextMap;
232 this.contextStack = contextStack == null ? ThreadContext.EMPTY_STACK : contextStack;
233 this.timeMillis = message instanceof TimestampMessage ? ((TimestampMessage) message).getTimestamp() : timestamp;
234 this.threadName = threadName;
235 this.source = source;
236 if (message != null && message instanceof LoggerNameAwareMessage) {
237 ((LoggerNameAwareMessage) message).setLoggerName(loggerName);
238 }
239 }
240
241 private static Map<String, String> createMap(final List<Property> properties) {
242 final Map<String, String> contextMap = ThreadContext.getImmutableContext();
243 if (contextMap == null && (properties == null || properties.isEmpty())) {
244 return null;
245 }
246 if (properties == null || properties.isEmpty()) {
247 return contextMap;
248 }
249 final Map<String, String> map = new HashMap<String, String>(contextMap);
250
251 for (final Property prop : properties) {
252 if (!map.containsKey(prop.getName())) {
253 map.put(prop.getName(), prop.getValue());
254 }
255 }
256 return Collections.unmodifiableMap(map);
257 }
258
259
260
261
262
263 @Override
264 public Level getLevel() {
265 return level;
266 }
267
268
269
270
271
272 @Override
273 public String getLoggerName() {
274 return loggerName;
275 }
276
277
278
279
280
281 @Override
282 public Message getMessage() {
283 return message;
284 }
285
286
287
288
289
290 @Override
291 public String getThreadName() {
292 if (threadName == null) {
293 threadName = Thread.currentThread().getName();
294 }
295 return threadName;
296 }
297
298
299
300
301
302 @Override
303 public long getTimeMillis() {
304 return timeMillis;
305 }
306
307
308
309
310
311 @Override
312 public Throwable getThrown() {
313 return thrown;
314 }
315
316
317
318
319
320 @Override
321 public ThrowableProxy getThrownProxy() {
322 if (thrownProxy == null && thrown != null) {
323 thrownProxy = new ThrowableProxy(thrown);
324 }
325 return thrownProxy;
326 }
327
328
329
330
331
332
333 @Override
334 public Marker getMarker() {
335 return marker;
336 }
337
338
339
340
341
342 @Override
343 public String getLoggerFqcn() {
344 return loggerFqcn;
345 }
346
347
348
349
350
351 @Override
352 public Map<String, String> getContextMap() {
353 return contextMap;
354 }
355
356
357
358
359
360 @Override
361 public ThreadContext.ContextStack getContextStack() {
362 return contextStack;
363 }
364
365
366
367
368
369
370 @Override
371 public StackTraceElement getSource() {
372 if (source != null) {
373 return source;
374 }
375 if (loggerFqcn == null || !includeLocation) {
376 return null;
377 }
378 source = calcLocation(loggerFqcn);
379 return source;
380 }
381
382 public static StackTraceElement calcLocation(final String fqcnOfLogger) {
383 if (fqcnOfLogger == null) {
384 return null;
385 }
386 final StackTraceElement[] stackTrace = Thread.currentThread().getStackTrace();
387 StackTraceElement last = null;
388 for (int i = stackTrace.length - 1; i > 0; i--) {
389 final String className = stackTrace[i].getClassName();
390 if (fqcnOfLogger.equals(className)) {
391 return last;
392 }
393 last = stackTrace[i];
394 }
395 return null;
396 }
397
398 @Override
399 public boolean isIncludeLocation() {
400 return includeLocation;
401 }
402
403 @Override
404 public void setIncludeLocation(final boolean includeLocation) {
405 this.includeLocation = includeLocation;
406 }
407
408 @Override
409 public boolean isEndOfBatch() {
410 return endOfBatch;
411 }
412
413 @Override
414 public void setEndOfBatch(final boolean endOfBatch) {
415 this.endOfBatch = endOfBatch;
416 }
417
418
419
420
421
422 protected Object writeReplace() {
423 getThrownProxy();
424 return new LogEventProxy(this, this.includeLocation);
425 }
426
427 public static Serializable serialize(final Log4jLogEvent event,
428 final boolean includeLocation) {
429 event.getThrownProxy();
430 return new LogEventProxy(event, includeLocation);
431 }
432
433 public static boolean canDeserialize(final Serializable event) {
434 return event instanceof LogEventProxy;
435 }
436
437 public static Log4jLogEvent deserialize(final Serializable event) {
438 if (event == null) {
439 throw new NullPointerException("Event cannot be null");
440 }
441 if (event instanceof LogEventProxy) {
442 final LogEventProxy proxy = (LogEventProxy) event;
443 final Log4jLogEvent result = new Log4jLogEvent(proxy.loggerName, proxy.marker,
444 proxy.loggerFQCN, proxy.level, proxy.message,
445 proxy.thrown, proxy.thrownProxy, proxy.contextMap, proxy.contextStack, proxy.threadName,
446 proxy.source, proxy.timeMillis);
447 result.setEndOfBatch(proxy.isEndOfBatch);
448 result.setIncludeLocation(proxy.isLocationRequired);
449 return result;
450 }
451 throw new IllegalArgumentException("Event is not a serialized LogEvent: " + event.toString());
452 }
453
454 private void readObject(final ObjectInputStream stream) throws InvalidObjectException {
455 throw new InvalidObjectException("Proxy required");
456 }
457
458 @Override
459 public String toString() {
460 final StringBuilder sb = new StringBuilder();
461 final String n = loggerName.isEmpty() ? "root" : loggerName;
462 sb.append("Logger=").append(n);
463 sb.append(" Level=").append(level.name());
464 sb.append(" Message=").append(message.getFormattedMessage());
465 return sb.toString();
466 }
467
468 @Override
469 public boolean equals(final Object o) {
470 if (this == o) {
471 return true;
472 }
473 if (o == null || getClass() != o.getClass()) {
474 return false;
475 }
476
477 final Log4jLogEvent that = (Log4jLogEvent) o;
478
479 if (endOfBatch != that.endOfBatch) {
480 return false;
481 }
482 if (includeLocation != that.includeLocation) {
483 return false;
484 }
485 if (timeMillis != that.timeMillis) {
486 return false;
487 }
488 if (loggerFqcn != null ? !loggerFqcn.equals(that.loggerFqcn) : that.loggerFqcn != null) {
489 return false;
490 }
491 if (level != null ? !level.equals(that.level) : that.level != null) {
492 return false;
493 }
494 if (source != null ? !source.equals(that.source) : that.source != null) {
495 return false;
496 }
497 if (marker != null ? !marker.equals(that.marker) : that.marker != null) {
498 return false;
499 }
500 if (contextMap != null ? !contextMap.equals(that.contextMap) : that.contextMap != null) {
501 return false;
502 }
503 if (!message.equals(that.message)) {
504 return false;
505 }
506 if (!loggerName.equals(that.loggerName)) {
507 return false;
508 }
509 if (contextStack != null ? !contextStack.equals(that.contextStack) : that.contextStack != null) {
510 return false;
511 }
512 if (threadName != null ? !threadName.equals(that.threadName) : that.threadName != null) {
513 return false;
514 }
515 if (thrown != null ? !thrown.equals(that.thrown) : that.thrown != null) {
516 return false;
517 }
518 if (thrownProxy != null ? !thrownProxy.equals(that.thrownProxy) : that.thrownProxy != null) {
519 return false;
520 }
521
522 return true;
523 }
524
525 @Override
526 public int hashCode() {
527 int result = loggerFqcn != null ? loggerFqcn.hashCode() : 0;
528 result = 31 * result + (marker != null ? marker.hashCode() : 0);
529 result = 31 * result + (level != null ? level.hashCode() : 0);
530 result = 31 * result + loggerName.hashCode();
531 result = 31 * result + message.hashCode();
532 result = 31 * result + (int) (timeMillis ^ (timeMillis >>> 32));
533 result = 31 * result + (thrown != null ? thrown.hashCode() : 0);
534 result = 31 * result + (thrownProxy != null ? thrownProxy.hashCode() : 0);
535 result = 31 * result + (contextMap != null ? contextMap.hashCode() : 0);
536 result = 31 * result + (contextStack != null ? contextStack.hashCode() : 0);
537 result = 31 * result + (threadName != null ? threadName.hashCode() : 0);
538 result = 31 * result + (source != null ? source.hashCode() : 0);
539 result = 31 * result + (includeLocation ? 1 : 0);
540 result = 31 * result + (endOfBatch ? 1 : 0);
541 return result;
542 }
543
544
545
546
547 private static class LogEventProxy implements Serializable {
548
549 private static final long serialVersionUID = -7139032940312647146L;
550 private final String loggerFQCN;
551 private final Marker marker;
552 private final Level level;
553 private final String loggerName;
554 private final Message message;
555 private final long timeMillis;
556 private final transient Throwable thrown;
557 private final ThrowableProxy thrownProxy;
558 private final Map<String, String> contextMap;
559 private final ThreadContext.ContextStack contextStack;
560 private final String threadName;
561 private final StackTraceElement source;
562 private final boolean isLocationRequired;
563 private final boolean isEndOfBatch;
564
565 public LogEventProxy(final Log4jLogEvent event, final boolean includeLocation) {
566 this.loggerFQCN = event.loggerFqcn;
567 this.marker = event.marker;
568 this.level = event.level;
569 this.loggerName = event.loggerName;
570 this.message = event.message;
571 this.timeMillis = event.timeMillis;
572 this.thrown = event.thrown;
573 this.thrownProxy = event.thrownProxy;
574 this.contextMap = event.contextMap;
575 this.contextStack = event.contextStack;
576 this.source = includeLocation ? event.getSource() : null;
577 this.threadName = event.getThreadName();
578 this.isLocationRequired = includeLocation;
579 this.isEndOfBatch = event.endOfBatch;
580 }
581
582
583
584
585
586 protected Object readResolve() {
587 final Log4jLogEvent result = new Log4jLogEvent(loggerName, marker, loggerFQCN, level, message, thrown,
588 thrownProxy, contextMap, contextStack, threadName, source, timeMillis);
589 result.setEndOfBatch(isEndOfBatch);
590 result.setIncludeLocation(isLocationRequired);
591 return result;
592 }
593 }
594 }