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