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