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