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