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