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