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 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(ParameterConsumer<S> action, 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
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 }