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