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.message.LoggerNameAwareMessage;
33 import org.apache.logging.log4j.message.Message;
34 import org.apache.logging.log4j.message.TimestampMessage;
35
36
37
38
39 public class Log4jLogEvent implements LogEvent {
40
41 private static final long serialVersionUID = -1351367343806656055L;
42 private static final String NOT_AVAIL = "?";
43 private final String fqcnOfLogger;
44 private final Marker marker;
45 private final Level level;
46 private final String name;
47 private final Message message;
48 private final long timestamp;
49 private final ThrowableProxy throwable;
50 private final Map<String, String> mdc;
51 private final ThreadContext.ContextStack ndc;
52 private String threadName = null;
53 private StackTraceElement location;
54 private boolean includeLocation;
55 private boolean endOfBatch = false;
56
57
58
59
60 public Log4jLogEvent(final long timestamp) {
61 this("", null, "", null, null, (ThrowableProxy) null, null, null, null, null, timestamp);
62 }
63
64
65
66
67
68
69
70
71
72
73 public Log4jLogEvent(final String loggerName, final Marker marker, final String fqcn, final Level level,
74 final Message message, final Throwable t) {
75 this(loggerName, marker, fqcn, level, message, null, t);
76 }
77
78
79
80
81
82
83
84
85
86
87
88 public Log4jLogEvent(final String loggerName, final Marker marker, final String fqcn, final Level level,
89 final Message message, final List<Property> properties, final Throwable t) {
90 this(loggerName, marker, fqcn, level, message, t,
91 createMap(properties),
92 ThreadContext.getDepth() == 0 ? null : ThreadContext.cloneStack(), null,
93 null, System.currentTimeMillis());
94 }
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110 public Log4jLogEvent(final String loggerName, final Marker marker, final String fqcn, final Level level,
111 final Message message, final Throwable t,
112 final Map<String, String> mdc, final ThreadContext.ContextStack ndc, final String threadName,
113 final StackTraceElement location, final long timestamp) {
114 this(loggerName, marker, fqcn, level, message, t == null ? null : new ThrowableProxy(t), mdc, ndc, threadName,
115 location, timestamp);
116 }
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132 public static Log4jLogEvent createEvent(final String loggerName, final Marker marker, final String fqcn,
133 final Level level, final Message message, final ThrowableProxy t,
134 final Map<String, String> mdc, final ThreadContext.ContextStack ndc,
135 final String threadName, final StackTraceElement location,
136 final long timestamp) {
137 return new Log4jLogEvent(loggerName, marker, fqcn, level, message, t, mdc, ndc, threadName, location, timestamp);
138 }
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154 private Log4jLogEvent(final String loggerName, final Marker marker, final String fqcn, final Level level,
155 final Message message, final ThrowableProxy t,
156 final Map<String, String> mdc, final ThreadContext.ContextStack ndc, final String threadName,
157 final StackTraceElement location, final long timestamp) {
158 name = loggerName;
159 this.marker = marker;
160 this.fqcnOfLogger = fqcn;
161 this.level = level;
162 this.message = message;
163 this.throwable = t;
164 this.mdc = mdc;
165 this.ndc = ndc;
166 this.timestamp = message instanceof TimestampMessage ? ((TimestampMessage) message).getTimestamp() : timestamp;
167 this.threadName = threadName;
168 this.location = location;
169 if (message != null && message instanceof LoggerNameAwareMessage) {
170 ((LoggerNameAwareMessage) message).setLoggerName(name);
171 }
172 }
173
174 private static Map<String, String> createMap(final List<Property> properties) {
175 final Map<String, String> contextMap = ThreadContext.getImmutableContext();
176 if (contextMap == null && (properties == null || properties.size() == 0)) {
177 return null;
178 }
179 if (properties == null || properties.size() == 0) {
180 return contextMap;
181 }
182 final Map<String, String> map = new HashMap<String, String>(contextMap);
183
184 for (final Property prop : properties) {
185 if (!map.containsKey(prop.getName())) {
186 map.put(prop.getName(), prop.getValue());
187 }
188 }
189 return Collections.unmodifiableMap(map);
190 }
191
192
193
194
195
196 @Override
197 public Level getLevel() {
198 return level;
199 }
200
201
202
203
204
205 @Override
206 public String getLoggerName() {
207 return name;
208 }
209
210
211
212
213
214 @Override
215 public Message getMessage() {
216 return message;
217 }
218
219
220
221
222
223 @Override
224 public String getThreadName() {
225 if (threadName == null) {
226 threadName = Thread.currentThread().getName();
227 }
228 return threadName;
229 }
230
231
232
233
234
235 @Override
236 public long getMillis() {
237 return timestamp;
238 }
239
240
241
242
243
244 @Override
245 public Throwable getThrown() {
246 return throwable == null ? null : throwable.getThrowable();
247 }
248
249
250
251
252
253 public ThrowableProxy getThrownProxy() {
254 return throwable;
255 }
256
257
258
259
260
261
262 @Override
263 public Marker getMarker() {
264 return marker;
265 }
266
267
268
269
270
271 @Override
272 public String getFQCN() {
273 return fqcnOfLogger;
274 }
275
276
277
278
279
280 @Override
281 public Map<String, String> getContextMap() {
282 return mdc == null ? ThreadContext.EMPTY_MAP : mdc;
283 }
284
285
286
287
288
289 @Override
290 public ThreadContext.ContextStack getContextStack() {
291 return ndc == null ? ThreadContext.EMPTY_STACK : ndc;
292 }
293
294
295
296
297
298
299 @Override
300 public StackTraceElement getSource() {
301 if (location != null) {
302 return location;
303 }
304 if (fqcnOfLogger == null || !includeLocation) {
305 return null;
306 }
307 location = calcLocation(fqcnOfLogger);
308 return location;
309 }
310
311 public static StackTraceElement calcLocation(final String fqcnOfLogger) {
312 if (fqcnOfLogger == null) {
313 return null;
314 }
315 final StackTraceElement[] stackTrace = Thread.currentThread().getStackTrace();
316 boolean next = false;
317 for (final StackTraceElement element : stackTrace) {
318 final String className = element.getClassName();
319 if (next) {
320 if (fqcnOfLogger.equals(className)) {
321 continue;
322 }
323 return element;
324 }
325
326 if (fqcnOfLogger.equals(className)) {
327 next = true;
328 } else if (NOT_AVAIL.equals(className)) {
329 break;
330 }
331 }
332 return null;
333 }
334
335 @Override
336 public boolean isIncludeLocation() {
337 return includeLocation;
338 }
339
340 @Override
341 public void setIncludeLocation(final boolean includeLocation) {
342 this.includeLocation = includeLocation;
343 }
344
345 @Override
346 public boolean isEndOfBatch() {
347 return endOfBatch;
348 }
349
350 @Override
351 public void setEndOfBatch(final boolean endOfBatch) {
352 this.endOfBatch = endOfBatch;
353 }
354
355
356
357
358
359 protected Object writeReplace() {
360 return new LogEventProxy(this, this.includeLocation);
361 }
362
363 public static Serializable serialize(final Log4jLogEvent event,
364 final boolean includeLocation) {
365 return new LogEventProxy(event, includeLocation);
366 }
367
368 public static Log4jLogEvent deserialize(final Serializable event) {
369 if (event == null) {
370 throw new NullPointerException("Event cannot be null");
371 }
372 if (event instanceof LogEventProxy) {
373 final LogEventProxy proxy = (LogEventProxy) event;
374 final Log4jLogEvent result = new Log4jLogEvent(proxy.name, proxy.marker,
375 proxy.fqcnOfLogger, proxy.level, proxy.message,
376 proxy.throwable, proxy.mdc, proxy.ndc, proxy.threadName,
377 proxy.location, proxy.timestamp);
378 result.setEndOfBatch(proxy.isEndOfBatch);
379 result.setIncludeLocation(proxy.isLocationRequired);
380 return result;
381 }
382 throw new IllegalArgumentException("Event is not a serialized LogEvent: " + event.toString());
383 }
384
385 private void readObject(final ObjectInputStream stream) throws InvalidObjectException {
386 throw new InvalidObjectException("Proxy required");
387 }
388
389 @Override
390 public String toString() {
391 final StringBuilder sb = new StringBuilder();
392 final String n = name.isEmpty() ? "root" : name;
393 sb.append("Logger=").append(n);
394 sb.append(" Level=").append(level.name());
395 sb.append(" Message=").append(message.getFormattedMessage());
396 return sb.toString();
397 }
398
399
400
401
402 private static class LogEventProxy implements Serializable {
403
404 private static final long serialVersionUID = -7139032940312647146L;
405 private final String fqcnOfLogger;
406 private final Marker marker;
407 private final Level level;
408 private final String name;
409 private final Message message;
410 private final long timestamp;
411 private final ThrowableProxy throwable;
412 private final Map<String, String> mdc;
413 private final ThreadContext.ContextStack ndc;
414 private final String threadName;
415 private final StackTraceElement location;
416 private final boolean isLocationRequired;
417 private final boolean isEndOfBatch;
418
419 public LogEventProxy(final Log4jLogEvent event, final boolean includeLocation) {
420 this.fqcnOfLogger = event.fqcnOfLogger;
421 this.marker = event.marker;
422 this.level = event.level;
423 this.name = event.name;
424 this.message = event.message;
425 this.timestamp = event.timestamp;
426 this.throwable = event.throwable;
427 this.mdc = event.mdc;
428 this.ndc = event.ndc;
429 this.location = includeLocation ? event.getSource() : null;
430 this.threadName = event.getThreadName();
431 this.isLocationRequired = includeLocation;
432 this.isEndOfBatch = event.endOfBatch;
433 }
434
435
436
437
438
439 protected Object readResolve() {
440 final Log4jLogEvent result = new Log4jLogEvent(name, marker, fqcnOfLogger,
441 level, message, throwable, mdc, ndc, threadName, location,
442 timestamp);
443 result.setEndOfBatch(isEndOfBatch);
444 result.setIncludeLocation(isLocationRequired);
445 return result;
446 }
447 }
448 }