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 return message;
308 }
309 final Object[] params = parameters == null ? new Object[0] : Arrays.copyOf(parameters, parameterCount);
310 return new ParameterizedMessage(messageText.toString(), params);
311 }
312
313 @Override
314 public Throwable getThrown() {
315 return thrown;
316 }
317
318 public void setThrown(final Throwable thrown) {
319 this.thrown = thrown;
320 }
321
322 void initTime(final Clock clock, final NanoClock nanoClock) {
323 if (message instanceof TimestampMessage) {
324 instant.initFromEpochMilli(((TimestampMessage) message).getTimestamp(), 0);
325 } else {
326 instant.initFrom(clock);
327 }
328 nanoTime = nanoClock.nanoTime();
329 }
330
331 @Override
332 public long getTimeMillis() {
333 return instant.getEpochMillisecond();
334 }
335
336 public void setTimeMillis(final long timeMillis) {
337 this.instant.initFromEpochMilli(timeMillis, 0);
338 }
339
340 @Override
341 public Instant getInstant() {
342 return instant;
343 }
344
345
346
347
348
349 @Override
350 public ThrowableProxy getThrownProxy() {
351 if (thrownProxy == null && thrown != null) {
352 thrownProxy = new ThrowableProxy(thrown);
353 }
354 return thrownProxy;
355 }
356
357
358
359
360
361
362 @Override
363 public StackTraceElement getSource() {
364 if (source != null) {
365 return source;
366 }
367 if (loggerFqcn == null || !includeLocation) {
368 return null;
369 }
370 source = StackLocatorUtil.calcLocation(loggerFqcn);
371 return source;
372 }
373
374 @SuppressWarnings("unchecked")
375 @Override
376 public ReadOnlyStringMap getContextData() {
377 return contextData;
378 }
379
380 @Override
381 public Map<String, String> getContextMap() {
382 return contextData.toMap();
383 }
384
385 public void setContextData(final StringMap mutableContextData) {
386 this.contextData = mutableContextData;
387 }
388
389 @Override
390 public ThreadContext.ContextStack getContextStack() {
391 return contextStack;
392 }
393
394 public void setContextStack(final ThreadContext.ContextStack contextStack) {
395 this.contextStack = contextStack;
396 }
397
398 @Override
399 public long getThreadId() {
400 return threadId;
401 }
402
403 public void setThreadId(final long threadId) {
404 this.threadId = threadId;
405 }
406
407 @Override
408 public String getThreadName() {
409 return threadName;
410 }
411
412 public void setThreadName(final String threadName) {
413 this.threadName = threadName;
414 }
415
416 @Override
417 public int getThreadPriority() {
418 return threadPriority;
419 }
420
421 public void setThreadPriority(final int threadPriority) {
422 this.threadPriority = threadPriority;
423 }
424
425 @Override
426 public boolean isIncludeLocation() {
427 return includeLocation;
428 }
429
430 @Override
431 public void setIncludeLocation(final boolean includeLocation) {
432 this.includeLocation = includeLocation;
433 }
434
435 @Override
436 public boolean isEndOfBatch() {
437 return endOfBatch;
438 }
439
440 @Override
441 public void setEndOfBatch(final boolean endOfBatch) {
442 this.endOfBatch = endOfBatch;
443 }
444
445 @Override
446 public long getNanoTime() {
447 return nanoTime;
448 }
449
450 public void setNanoTime(final long nanoTime) {
451 this.nanoTime = nanoTime;
452 }
453
454
455
456
457
458 protected Object writeReplace() {
459 return new Log4jLogEvent.LogEventProxy(this, this.includeLocation);
460 }
461
462 private void readObject(final ObjectInputStream stream) throws InvalidObjectException {
463 throw new InvalidObjectException("Proxy required");
464 }
465
466
467
468
469
470
471
472 public Log4jLogEvent createMemento() {
473 return Log4jLogEvent.deserialize(Log4jLogEvent.serialize(this, includeLocation));
474 }
475
476
477
478
479
480 public void initializeBuilder(final Log4jLogEvent.Builder builder) {
481 builder.setContextData(contextData)
482 .setContextStack(contextStack)
483 .setEndOfBatch(endOfBatch)
484 .setIncludeLocation(includeLocation)
485 .setLevel(getLevel())
486 .setLoggerFqcn(loggerFqcn)
487 .setLoggerName(loggerName)
488 .setMarker(marker)
489 .setMessage(getNonNullImmutableMessage())
490 .setNanoTime(nanoTime)
491 .setSource(source)
492 .setThreadId(threadId)
493 .setThreadName(threadName)
494 .setThreadPriority(threadPriority)
495 .setThrown(getThrown())
496 .setThrownProxy(thrownProxy)
497 .setInstant(instant)
498 ;
499 }
500
501 private Message getNonNullImmutableMessage() {
502 return message != null ? message : new SimpleMessage(String.valueOf(messageText));
503 }
504 }