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 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.thrown = event.getThrown();
99 this.thrownProxy = event.getThrownProxy();
100
101 this.instant.initFrom(event.getInstant());
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 messageFormat = null;
129 thrown = null;
130 thrownProxy = null;
131 source = null;
132 if (contextData != null) {
133 if (contextData.isFrozen()) {
134 contextData = null;
135 } else {
136 contextData.clear();
137 }
138 }
139 contextStack = null;
140
141
142
143
144
145
146 StringBuilders.trimToMaxSize(messageText, Constants.MAX_REUSABLE_MESSAGE_SIZE);
147
148 if (parameters != null) {
149 for (int i = 0; i < parameters.length; i++) {
150 parameters[i] = null;
151 }
152 }
153
154
155
156
157
158
159
160
161 }
162
163 @Override
164 public String getLoggerFqcn() {
165 return loggerFqcn;
166 }
167
168 public void setLoggerFqcn(final String loggerFqcn) {
169 this.loggerFqcn = loggerFqcn;
170 }
171
172 @Override
173 public Marker getMarker() {
174 return marker;
175 }
176
177 public void setMarker(final Marker marker) {
178 this.marker = marker;
179 }
180
181 @Override
182 public Level getLevel() {
183 if (level == null) {
184 level = Level.OFF;
185 }
186 return level;
187 }
188
189 public void setLevel(final Level level) {
190 this.level = level;
191 }
192
193 @Override
194 public String getLoggerName() {
195 return loggerName;
196 }
197
198 public void setLoggerName(final String loggerName) {
199 this.loggerName = loggerName;
200 }
201
202 @Override
203 public Message getMessage() {
204 if (message == null) {
205 return messageText == null ? EMPTY : this;
206 }
207 return message;
208 }
209
210 public void setMessage(final Message msg) {
211 if (msg instanceof ReusableMessage) {
212 final ReusableMessage reusable = (ReusableMessage) msg;
213 reusable.formatTo(getMessageTextForWriting());
214 this.messageFormat = msg.getFormat();
215 if (parameters != null) {
216 parameters = reusable.swapParameters(parameters);
217 parameterCount = reusable.getParameterCount();
218 }
219 } else {
220 this.message = InternalAsyncUtil.makeMessageImmutable(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 messageFormat;
248 }
249
250
251
252
253 @Override
254 public Object[] getParameters() {
255 return parameters == null ? null : Arrays.copyOf(parameters, parameterCount);
256 }
257
258 @Override
259 public <S> void forEachParameter(final ParameterConsumer<S> action, final S state) {
260 if (parameters != null) {
261 for (short i = 0; i < parameterCount; i++) {
262 action.accept(parameters[i], i, state);
263 }
264 }
265 }
266
267
268
269
270 @Override
271 public Throwable getThrowable() {
272 return getThrown();
273 }
274
275
276
277
278 @Override
279 public void formatTo(final StringBuilder buffer) {
280 buffer.append(messageText);
281 }
282
283
284
285
286
287
288
289 @Override
290 public Object[] swapParameters(final Object[] emptyReplacement) {
291 final Object[] result = this.parameters;
292 this.parameters = emptyReplacement;
293 return result;
294 }
295
296
297
298
299 @Override
300 public short getParameterCount() {
301 return parameterCount;
302 }
303
304 @Override
305 public Message memento() {
306 if (message == null) {
307 message = new MementoMessage(String.valueOf(messageText), messageFormat, getParameters());
308 }
309 return message;
310 }
311
312 @Override
313 public Throwable getThrown() {
314 return thrown;
315 }
316
317 public void setThrown(final Throwable thrown) {
318 this.thrown = thrown;
319 }
320
321 void initTime(final Clock clock, final NanoClock nanoClock) {
322 if (message instanceof TimestampMessage) {
323 instant.initFromEpochMilli(((TimestampMessage) message).getTimestamp(), 0);
324 } else {
325 instant.initFrom(clock);
326 }
327 nanoTime = nanoClock.nanoTime();
328 }
329
330 @Override
331 public long getTimeMillis() {
332 return instant.getEpochMillisecond();
333 }
334
335 public void setTimeMillis(final long timeMillis) {
336 this.instant.initFromEpochMilli(timeMillis, 0);
337 }
338
339 @Override
340 public Instant getInstant() {
341 return instant;
342 }
343
344
345
346
347
348 @Override
349 public ThrowableProxy getThrownProxy() {
350 if (thrownProxy == null && thrown != null) {
351 thrownProxy = new ThrowableProxy(thrown);
352 }
353 return thrownProxy;
354 }
355
356 public void setSource(StackTraceElement source) {
357 this.source = source;
358 }
359
360
361
362
363
364
365 @Override
366 public StackTraceElement getSource() {
367 if (source != null) {
368 return source;
369 }
370 if (loggerFqcn == null || !includeLocation) {
371 return null;
372 }
373 source = StackLocatorUtil.calcLocation(loggerFqcn);
374 return source;
375 }
376
377 @SuppressWarnings("unchecked")
378 @Override
379 public ReadOnlyStringMap getContextData() {
380 return contextData;
381 }
382
383 @Override
384 public Map<String, String> getContextMap() {
385 return contextData.toMap();
386 }
387
388 public void setContextData(final StringMap mutableContextData) {
389 this.contextData = mutableContextData;
390 }
391
392 @Override
393 public ThreadContext.ContextStack getContextStack() {
394 return contextStack;
395 }
396
397 public void setContextStack(final ThreadContext.ContextStack contextStack) {
398 this.contextStack = contextStack;
399 }
400
401 @Override
402 public long getThreadId() {
403 return threadId;
404 }
405
406 public void setThreadId(final long threadId) {
407 this.threadId = threadId;
408 }
409
410 @Override
411 public String getThreadName() {
412 return threadName;
413 }
414
415 public void setThreadName(final String threadName) {
416 this.threadName = threadName;
417 }
418
419 @Override
420 public int getThreadPriority() {
421 return threadPriority;
422 }
423
424 public void setThreadPriority(final int threadPriority) {
425 this.threadPriority = threadPriority;
426 }
427
428 @Override
429 public boolean isIncludeLocation() {
430 return includeLocation;
431 }
432
433 @Override
434 public void setIncludeLocation(final boolean includeLocation) {
435 this.includeLocation = includeLocation;
436 }
437
438 @Override
439 public boolean isEndOfBatch() {
440 return endOfBatch;
441 }
442
443 @Override
444 public void setEndOfBatch(final boolean endOfBatch) {
445 this.endOfBatch = endOfBatch;
446 }
447
448 @Override
449 public long getNanoTime() {
450 return nanoTime;
451 }
452
453 public void setNanoTime(final long nanoTime) {
454 this.nanoTime = nanoTime;
455 }
456
457
458
459
460
461 protected Object writeReplace() {
462 return new Log4jLogEvent.LogEventProxy(this, this.includeLocation);
463 }
464
465 private void readObject(final ObjectInputStream stream) throws InvalidObjectException {
466 throw new InvalidObjectException("Proxy required");
467 }
468
469
470
471
472
473
474
475 public Log4jLogEvent createMemento() {
476 return Log4jLogEvent.deserialize(Log4jLogEvent.serialize(this, includeLocation));
477 }
478
479
480
481
482
483 public void initializeBuilder(final Log4jLogEvent.Builder builder) {
484 builder.setContextData(contextData)
485 .setContextStack(contextStack)
486 .setEndOfBatch(endOfBatch)
487 .setIncludeLocation(includeLocation)
488 .setLevel(getLevel())
489 .setLoggerFqcn(loggerFqcn)
490 .setLoggerName(loggerName)
491 .setMarker(marker)
492 .setMessage(memento())
493 .setNanoTime(nanoTime)
494 .setSource(source)
495 .setThreadId(threadId)
496 .setThreadName(threadName)
497 .setThreadPriority(threadPriority)
498 .setThrown(getThrown())
499 .setThrownProxy(thrownProxy)
500 .setInstant(instant)
501 ;
502 }
503 }