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