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