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.*;
30 import org.apache.logging.log4j.core.time.Instant;
31 import org.apache.logging.log4j.core.time.MutableInstant;
32 import org.apache.logging.log4j.message.*;
33 import org.apache.logging.log4j.util.ReadOnlyStringMap;
34 import org.apache.logging.log4j.util.StackLocatorUtil;
35 import org.apache.logging.log4j.util.StringBuilders;
36 import org.apache.logging.log4j.util.StringMap;
37 import org.apache.logging.log4j.util.Strings;
38
39
40
41
42
43 public class MutableLogEvent implements LogEvent, ReusableMessage, ParameterVisitable {
44 private static final Message EMPTY = new SimpleMessage(Strings.EMPTY);
45
46 private int threadPriority;
47 private long threadId;
48 private final MutableInstant instant = new MutableInstant();
49 private long nanoTime;
50 private short parameterCount;
51 private boolean includeLocation;
52 private boolean endOfBatch = false;
53 private Level level;
54 private String threadName;
55 private String loggerName;
56 private Message message;
57 private String messageFormat;
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
71 this(null, null);
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.thrown = event.getThrown();
100 this.thrownProxy = event.getThrownProxy();
101
102 this.instant.initFrom(event.getInstant());
103
104
105
106
107 this.contextData.putAll(event.getContextData());
108
109 this.contextStack = event.getContextStack();
110 this.source = event.isIncludeLocation() ? event.getSource() : null;
111 this.threadId = event.getThreadId();
112 this.threadName = event.getThreadName();
113 this.threadPriority = event.getThreadPriority();
114 this.endOfBatch = event.isEndOfBatch();
115 this.includeLocation = event.isIncludeLocation();
116 this.nanoTime = event.getNanoTime();
117 setMessage(event.getMessage());
118 }
119
120
121
122
123 public void clear() {
124 loggerFqcn = null;
125 marker = null;
126 level = null;
127 loggerName = null;
128 message = null;
129 messageFormat = null;
130 thrown = null;
131 thrownProxy = null;
132 source = null;
133 if (contextData != null) {
134 if (contextData.isFrozen()) {
135 contextData = null;
136 } else {
137 contextData.clear();
138 }
139 }
140 contextStack = null;
141
142
143
144
145
146
147 StringBuilders.trimToMaxSize(messageText, Constants.MAX_REUSABLE_MESSAGE_SIZE);
148
149 if (parameters != null) {
150 Arrays.fill(parameters, null);
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 this.messageFormat = msg.getFormat();
214 parameters = reusable.swapParameters(parameters == null ? new Object[10] : parameters);
215 parameterCount = reusable.getParameterCount();
216 } else {
217 this.message = InternalAsyncUtil.makeMessageImmutable(msg);
218 }
219 }
220
221 private StringBuilder getMessageTextForWriting() {
222 if (messageText == null) {
223
224 messageText = new StringBuilder(Constants.INITIAL_REUSABLE_MESSAGE_SIZE);
225 }
226 messageText.setLength(0);
227 return messageText;
228 }
229
230
231
232
233 @Override
234 public String getFormattedMessage() {
235 return messageText.toString();
236 }
237
238
239
240
241 @Override
242 public String getFormat() {
243 return messageFormat;
244 }
245
246
247
248
249 @Override
250 public Object[] getParameters() {
251 return parameters == null ? null : Arrays.copyOf(parameters, parameterCount);
252 }
253
254 @Override
255 public <S> void forEachParameter(final ParameterConsumer<S> action, final S state) {
256 if (parameters != null) {
257 for (short i = 0; i < parameterCount; i++) {
258 action.accept(parameters[i], i, state);
259 }
260 }
261 }
262
263
264
265
266 @Override
267 public Throwable getThrowable() {
268 return getThrown();
269 }
270
271
272
273
274 @Override
275 public void formatTo(final StringBuilder buffer) {
276 buffer.append(messageText);
277 }
278
279
280
281
282
283
284
285 @Override
286 public Object[] swapParameters(final Object[] emptyReplacement) {
287 final Object[] result = this.parameters;
288 this.parameters = emptyReplacement;
289 return result;
290 }
291
292
293
294
295 @Override
296 public short getParameterCount() {
297 return parameterCount;
298 }
299
300 @Override
301 public Message memento() {
302 if (message == null) {
303 message = new MementoMessage(String.valueOf(messageText), messageFormat, getParameters());
304 }
305 return message;
306 }
307
308 @Override
309 public Throwable getThrown() {
310 return thrown;
311 }
312
313 public void setThrown(final Throwable thrown) {
314 this.thrown = thrown;
315 }
316
317 void initTime(final Clock clock, final NanoClock nanoClock) {
318 if (message instanceof TimestampMessage) {
319 instant.initFromEpochMilli(((TimestampMessage) message).getTimestamp(), 0);
320 } else {
321 instant.initFrom(clock);
322 }
323 nanoTime = nanoClock.nanoTime();
324 }
325
326 @Override
327 public long getTimeMillis() {
328 return instant.getEpochMillisecond();
329 }
330
331 public void setTimeMillis(final long timeMillis) {
332 this.instant.initFromEpochMilli(timeMillis, 0);
333 }
334
335 @Override
336 public Instant getInstant() {
337 return instant;
338 }
339
340
341
342
343
344 @Override
345 public ThrowableProxy getThrownProxy() {
346 if (thrownProxy == null && thrown != null) {
347 thrownProxy = new ThrowableProxy(thrown);
348 }
349 return thrownProxy;
350 }
351
352 public void setSource(StackTraceElement source) {
353 this.source = source;
354 }
355
356
357
358
359
360
361 @Override
362 public StackTraceElement getSource() {
363 if (source != null) {
364 return source;
365 }
366 if (loggerFqcn == null || !includeLocation) {
367 return null;
368 }
369 source = StackLocatorUtil.calcLocation(loggerFqcn);
370 return source;
371 }
372
373 @SuppressWarnings("unchecked")
374 @Override
375 public ReadOnlyStringMap getContextData() {
376 return contextData;
377 }
378
379 @Override
380 public Map<String, String> getContextMap() {
381 return contextData.toMap();
382 }
383
384 public void setContextData(final StringMap mutableContextData) {
385 this.contextData = mutableContextData;
386 }
387
388 @Override
389 public ThreadContext.ContextStack getContextStack() {
390 return contextStack;
391 }
392
393 public void setContextStack(final ThreadContext.ContextStack contextStack) {
394 this.contextStack = contextStack;
395 }
396
397 @Override
398 public long getThreadId() {
399 return threadId;
400 }
401
402 public void setThreadId(final long threadId) {
403 this.threadId = threadId;
404 }
405
406 @Override
407 public String getThreadName() {
408 return threadName;
409 }
410
411 public void setThreadName(final String threadName) {
412 this.threadName = threadName;
413 }
414
415 @Override
416 public int getThreadPriority() {
417 return threadPriority;
418 }
419
420 public void setThreadPriority(final int threadPriority) {
421 this.threadPriority = threadPriority;
422 }
423
424 @Override
425 public boolean isIncludeLocation() {
426 return includeLocation;
427 }
428
429 @Override
430 public void setIncludeLocation(final boolean includeLocation) {
431 this.includeLocation = includeLocation;
432 }
433
434 @Override
435 public boolean isEndOfBatch() {
436 return endOfBatch;
437 }
438
439 @Override
440 public void setEndOfBatch(final boolean endOfBatch) {
441 this.endOfBatch = endOfBatch;
442 }
443
444 @Override
445 public long getNanoTime() {
446 return nanoTime;
447 }
448
449 public void setNanoTime(final long nanoTime) {
450 this.nanoTime = nanoTime;
451 }
452
453
454
455
456
457 protected Object writeReplace() {
458 return new Log4jLogEvent.LogEventProxy(this, this.includeLocation);
459 }
460
461 private void readObject(final ObjectInputStream stream) throws InvalidObjectException {
462 throw new InvalidObjectException("Proxy required");
463 }
464
465
466
467
468
469
470
471 public Log4jLogEvent createMemento() {
472 return Log4jLogEvent.deserialize(Log4jLogEvent.serialize(this, includeLocation));
473 }
474
475
476
477
478
479 public void initializeBuilder(final Log4jLogEvent.Builder builder) {
480 builder.setContextData(contextData)
481 .setContextStack(contextStack)
482 .setEndOfBatch(endOfBatch)
483 .setIncludeLocation(includeLocation)
484 .setLevel(getLevel())
485 .setLoggerFqcn(loggerFqcn)
486 .setLoggerName(loggerName)
487 .setMarker(marker)
488 .setMessage(memento())
489 .setNanoTime(nanoTime)
490 .setSource(source)
491 .setThreadId(threadId)
492 .setThreadName(threadName)
493 .setThreadPriority(threadPriority)
494 .setThrown(getThrown())
495 .setThrownProxy(thrownProxy)
496 .setInstant(instant)
497 ;
498 }
499 }