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