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.util.Arrays;
22 import java.util.Map;
23
24 import org.apache.logging.log4j.Level;
25 import org.apache.logging.log4j.Marker;
26 import org.apache.logging.log4j.ThreadContext;
27 import org.apache.logging.log4j.core.LogEvent;
28 import org.apache.logging.log4j.core.async.InternalAsyncUtil;
29 import org.apache.logging.log4j.core.util.Constants;
30 import org.apache.logging.log4j.message.Message;
31 import org.apache.logging.log4j.message.ParameterizedMessage;
32 import org.apache.logging.log4j.message.ReusableMessage;
33 import org.apache.logging.log4j.message.SimpleMessage;
34 import org.apache.logging.log4j.util.ReadOnlyStringMap;
35 import org.apache.logging.log4j.util.StackLocatorUtil;
36 import org.apache.logging.log4j.util.StringBuilders;
37 import org.apache.logging.log4j.util.StringMap;
38 import org.apache.logging.log4j.util.Strings;
39
40
41
42
43
44 public class MutableLogEvent implements LogEvent, ReusableMessage {
45 private static final Message EMPTY = new SimpleMessage(Strings.EMPTY);
46
47 private int threadPriority;
48 private long threadId;
49 private long timeMillis;
50 private long nanoTime;
51 private short parameterCount;
52 private boolean includeLocation;
53 private boolean endOfBatch = false;
54 private Level level;
55 private String threadName;
56 private String loggerName;
57 private Message message;
58 private StringBuilder messageText;
59 private Object[] parameters;
60 private Throwable thrown;
61 private ThrowableProxy thrownProxy;
62 private StringMap contextData = ContextDataFactory.createContextData();
63 private Marker marker;
64 private String loggerFqcn;
65 private StackTraceElement source;
66 private ThreadContext.ContextStack contextStack;
67 transient boolean reserved = false;
68
69 public MutableLogEvent() {
70 this(new StringBuilder(Constants.INITIAL_REUSABLE_MESSAGE_SIZE), new Object[10]);
71 }
72
73 public MutableLogEvent(final StringBuilder msgText, final Object[] replacementParameters) {
74 this.messageText = msgText;
75 this.parameters = replacementParameters;
76 }
77
78 @Override
79 public Log4jLogEvent toImmutable() {
80 return createMemento();
81 }
82
83
84
85
86
87
88
89
90
91
92
93 public void initFrom(final LogEvent event) {
94 this.loggerFqcn = event.getLoggerFqcn();
95 this.marker = event.getMarker();
96 this.level = event.getLevel();
97 this.loggerName = event.getLoggerName();
98 this.timeMillis = event.getTimeMillis();
99 this.thrown = event.getThrown();
100 this.thrownProxy = event.getThrownProxy();
101
102
103
104
105 this.contextData.putAll(event.getContextData());
106
107 this.contextStack = event.getContextStack();
108 this.source = event.isIncludeLocation() ? event.getSource() : null;
109 this.threadId = event.getThreadId();
110 this.threadName = event.getThreadName();
111 this.threadPriority = event.getThreadPriority();
112 this.endOfBatch = event.isEndOfBatch();
113 this.includeLocation = event.isIncludeLocation();
114 this.nanoTime = event.getNanoTime();
115 setMessage(event.getMessage());
116 }
117
118
119
120
121 public void clear() {
122 loggerFqcn = null;
123 marker = null;
124 level = null;
125 loggerName = null;
126 message = null;
127 thrown = null;
128 thrownProxy = null;
129 source = null;
130 if (contextData != null) {
131 if (contextData.isFrozen()) {
132 contextData = null;
133 } else {
134 contextData.clear();
135 }
136 }
137 contextStack = null;
138
139
140
141
142
143
144 StringBuilders.trimToMaxSize(messageText, Constants.MAX_REUSABLE_MESSAGE_SIZE);
145
146 if (parameters != null) {
147 for (int i = 0; i < parameters.length; i++) {
148 parameters[i] = null;
149 }
150 }
151
152
153
154
155
156
157
158
159 }
160
161 @Override
162 public String getLoggerFqcn() {
163 return loggerFqcn;
164 }
165
166 public void setLoggerFqcn(final String loggerFqcn) {
167 this.loggerFqcn = loggerFqcn;
168 }
169
170 @Override
171 public Marker getMarker() {
172 return marker;
173 }
174
175 public void setMarker(final Marker marker) {
176 this.marker = marker;
177 }
178
179 @Override
180 public Level getLevel() {
181 if (level == null) {
182 level = Level.OFF;
183 }
184 return level;
185 }
186
187 public void setLevel(final Level level) {
188 this.level = level;
189 }
190
191 @Override
192 public String getLoggerName() {
193 return loggerName;
194 }
195
196 public void setLoggerName(final String loggerName) {
197 this.loggerName = loggerName;
198 }
199
200 @Override
201 public Message getMessage() {
202 if (message == null) {
203 return messageText == null ? EMPTY : this;
204 }
205 return message;
206 }
207
208 public void setMessage(final Message msg) {
209 if (msg instanceof ReusableMessage) {
210 final ReusableMessage reusable = (ReusableMessage) msg;
211 reusable.formatTo(getMessageTextForWriting());
212 if (parameters != null) {
213 parameters = reusable.swapParameters(parameters);
214 parameterCount = reusable.getParameterCount();
215 }
216 } else {
217 this.message = InternalAsyncUtil.makeMessageImmutable(msg);
218 }
219 }
220
221 private StringBuilder getMessageTextForWriting() {
222 if (messageText == null) {
223
224
225 messageText = new StringBuilder(Constants.INITIAL_REUSABLE_MESSAGE_SIZE);
226 }
227 messageText.setLength(0);
228 return messageText;
229 }
230
231
232
233
234 @Override
235 public String getFormattedMessage() {
236 return messageText.toString();
237 }
238
239
240
241
242 @Override
243 public String getFormat() {
244 return null;
245 }
246
247
248
249
250 @Override
251 public Object[] getParameters() {
252 return parameters == null ? null : Arrays.copyOf(parameters, parameterCount);
253 }
254
255
256
257
258 @Override
259 public Throwable getThrowable() {
260 return getThrown();
261 }
262
263
264
265
266 @Override
267 public void formatTo(final StringBuilder buffer) {
268 buffer.append(messageText);
269 }
270
271
272
273
274
275
276
277 @Override
278 public Object[] swapParameters(final Object[] emptyReplacement) {
279 final Object[] result = this.parameters;
280 this.parameters = emptyReplacement;
281 return result;
282 }
283
284
285
286
287 @Override
288 public short getParameterCount() {
289 return parameterCount;
290 }
291
292 @Override
293 public Message memento() {
294 if (message != null) {
295 return message;
296 }
297 final Object[] params = parameters == null ? new Object[0] : Arrays.copyOf(parameters, parameterCount);
298 return new ParameterizedMessage(messageText.toString(), params);
299 }
300
301 @Override
302 public Throwable getThrown() {
303 return thrown;
304 }
305
306 public void setThrown(final Throwable thrown) {
307 this.thrown = thrown;
308 }
309
310 @Override
311 public long getTimeMillis() {
312 return timeMillis;
313 }
314
315 public void setTimeMillis(final long timeMillis) {
316 this.timeMillis = timeMillis;
317 }
318
319
320
321
322
323 @Override
324 public ThrowableProxy getThrownProxy() {
325 if (thrownProxy == null && thrown != null) {
326 thrownProxy = new ThrowableProxy(thrown);
327 }
328 return thrownProxy;
329 }
330
331
332
333
334
335
336 @Override
337 public StackTraceElement getSource() {
338 if (source != null) {
339 return source;
340 }
341 if (loggerFqcn == null || !includeLocation) {
342 return null;
343 }
344 source = StackLocatorUtil.calcLocation(loggerFqcn);
345 return source;
346 }
347
348 @SuppressWarnings("unchecked")
349 @Override
350 public ReadOnlyStringMap getContextData() {
351 return contextData;
352 }
353
354 @Override
355 public Map<String, String> getContextMap() {
356 return contextData.toMap();
357 }
358
359 public void setContextData(final StringMap mutableContextData) {
360 this.contextData = mutableContextData;
361 }
362
363 @Override
364 public ThreadContext.ContextStack getContextStack() {
365 return contextStack;
366 }
367
368 public void setContextStack(final ThreadContext.ContextStack contextStack) {
369 this.contextStack = contextStack;
370 }
371
372 @Override
373 public long getThreadId() {
374 return threadId;
375 }
376
377 public void setThreadId(final long threadId) {
378 this.threadId = threadId;
379 }
380
381 @Override
382 public String getThreadName() {
383 return threadName;
384 }
385
386 public void setThreadName(final String threadName) {
387 this.threadName = threadName;
388 }
389
390 @Override
391 public int getThreadPriority() {
392 return threadPriority;
393 }
394
395 public void setThreadPriority(final int threadPriority) {
396 this.threadPriority = threadPriority;
397 }
398
399 @Override
400 public boolean isIncludeLocation() {
401 return includeLocation;
402 }
403
404 @Override
405 public void setIncludeLocation(final boolean includeLocation) {
406 this.includeLocation = includeLocation;
407 }
408
409 @Override
410 public boolean isEndOfBatch() {
411 return endOfBatch;
412 }
413
414 @Override
415 public void setEndOfBatch(final boolean endOfBatch) {
416 this.endOfBatch = endOfBatch;
417 }
418
419 @Override
420 public long getNanoTime() {
421 return nanoTime;
422 }
423
424 public void setNanoTime(final long nanoTime) {
425 this.nanoTime = nanoTime;
426 }
427
428
429
430
431
432 protected Object writeReplace() {
433 return new Log4jLogEvent.LogEventProxy(this, this.includeLocation);
434 }
435
436 private void readObject(final ObjectInputStream stream) throws InvalidObjectException {
437 throw new InvalidObjectException("Proxy required");
438 }
439
440
441
442
443
444
445
446 public Log4jLogEvent createMemento() {
447 return Log4jLogEvent.deserialize(Log4jLogEvent.serialize(this, includeLocation));
448 }
449
450
451
452
453
454 public void initializeBuilder(final Log4jLogEvent.Builder builder) {
455 builder.setContextData(contextData)
456 .setContextStack(contextStack)
457 .setEndOfBatch(endOfBatch)
458 .setIncludeLocation(includeLocation)
459 .setLevel(getLevel())
460 .setLoggerFqcn(loggerFqcn)
461 .setLoggerName(loggerName)
462 .setMarker(marker)
463 .setMessage(getNonNullImmutableMessage())
464 .setNanoTime(nanoTime)
465 .setSource(source)
466 .setThreadId(threadId)
467 .setThreadName(threadName)
468 .setThreadPriority(threadPriority)
469 .setThrown(getThrown())
470 .setThrownProxy(thrownProxy)
471 .setTimeMillis(timeMillis);
472 }
473
474 private Message getNonNullImmutableMessage() {
475 return message != null ? message : new SimpleMessage(String.valueOf(messageText));
476 }
477 }