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