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