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.util.List;
20
21 import org.apache.logging.log4j.Level;
22 import org.apache.logging.log4j.Marker;
23 import org.apache.logging.log4j.ThreadContext;
24 import org.apache.logging.log4j.ThreadContext.ContextStack;
25 import org.apache.logging.log4j.core.ContextDataInjector;
26 import org.apache.logging.log4j.core.Logger;
27 import org.apache.logging.log4j.core.LoggerContext;
28 import org.apache.logging.log4j.core.config.Configuration;
29 import org.apache.logging.log4j.core.config.LoggerConfig;
30 import org.apache.logging.log4j.core.config.Property;
31 import org.apache.logging.log4j.core.config.ReliabilityStrategy;
32 import org.apache.logging.log4j.core.impl.ContextDataFactory;
33 import org.apache.logging.log4j.core.impl.ContextDataInjectorFactory;
34 import org.apache.logging.log4j.core.util.Clock;
35 import org.apache.logging.log4j.core.util.ClockFactory;
36 import org.apache.logging.log4j.core.util.NanoClock;
37 import org.apache.logging.log4j.message.Message;
38 import org.apache.logging.log4j.message.MessageFactory;
39 import org.apache.logging.log4j.message.ReusableMessage;
40 import org.apache.logging.log4j.spi.AbstractLogger;
41 import org.apache.logging.log4j.status.StatusLogger;
42 import org.apache.logging.log4j.util.StackLocatorUtil;
43 import org.apache.logging.log4j.util.StringMap;
44
45 import com.lmax.disruptor.EventTranslatorVararg;
46 import com.lmax.disruptor.dsl.Disruptor;
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67 public class AsyncLogger extends Logger implements EventTranslatorVararg<RingBufferLogEvent> {
68
69
70
71
72
73 private static final StatusLogger LOGGER = StatusLogger.getLogger();
74 private static final Clock CLOCK = ClockFactory.getClock();
75 private static final ContextDataInjector CONTEXT_DATA_INJECTOR = ContextDataInjectorFactory.createInjector();
76
77 private static final ThreadNameCachingStrategy THREAD_NAME_CACHING_STRATEGY = ThreadNameCachingStrategy.create();
78
79 private final ThreadLocal<RingBufferLogEventTranslator> threadLocalTranslator = new ThreadLocal<>();
80 private final AsyncLoggerDisruptor loggerDisruptor;
81
82 private volatile boolean includeLocation;
83 private volatile NanoClock nanoClock;
84
85
86
87
88
89
90
91
92
93 public AsyncLogger(final LoggerContext context, final String name, final MessageFactory messageFactory,
94 final AsyncLoggerDisruptor loggerDisruptor) {
95 super(context, name, messageFactory);
96 this.loggerDisruptor = loggerDisruptor;
97 includeLocation = privateConfig.loggerConfig.isIncludeLocation();
98 nanoClock = context.getConfiguration().getNanoClock();
99 }
100
101
102
103
104
105
106 @Override
107 protected void updateConfiguration(final Configuration newConfig) {
108 nanoClock = newConfig.getNanoClock();
109 includeLocation = newConfig.getLoggerConfig(name).isIncludeLocation();
110 super.updateConfiguration(newConfig);
111 }
112
113
114 NanoClock getNanoClock() {
115 return nanoClock;
116 }
117
118 private RingBufferLogEventTranslator getCachedTranslator() {
119 RingBufferLogEventTranslator result = threadLocalTranslator.get();
120 if (result == null) {
121 result = new RingBufferLogEventTranslator();
122 threadLocalTranslator.set(result);
123 }
124 return result;
125 }
126
127 @Override
128 public void logMessage(final String fqcn, final Level level, final Marker marker, final Message message,
129 final Throwable thrown) {
130 getTranslatorType().log(fqcn, level, marker, message, thrown);
131 }
132
133 @Override
134 public void log(final Level level, final Marker marker, final String fqcn, final StackTraceElement location,
135 final Message message, final Throwable throwable) {
136 getTranslatorType().log(fqcn, location, level, marker, message, throwable);
137 }
138
139
140 abstract class TranslatorType {
141 abstract void log(final String fqcn, final StackTraceElement location, final Level level, final Marker marker,
142 final Message message, final Throwable thrown);
143
144 abstract void log(final String fqcn, final Level level, final Marker marker,
145 final Message message, final Throwable thrown);
146 }
147
148 private final TranslatorType threadLocalTranslatorType = new TranslatorType() {
149 @Override
150 void log(String fqcn, StackTraceElement location, Level level, Marker marker, Message message,
151 Throwable thrown) {
152 logWithThreadLocalTranslator(fqcn, location, level, marker, message, thrown);
153 }
154
155 @Override
156 void log(String fqcn, Level level, Marker marker, Message message, Throwable thrown) {
157 logWithThreadLocalTranslator(fqcn, level, marker, message, thrown);
158 }
159 };
160
161 private final TranslatorType varargTranslatorType = new TranslatorType() {
162 @Override
163 void log(String fqcn, StackTraceElement location, Level level, Marker marker, Message message,
164 Throwable thrown) {
165 logWithVarargTranslator(fqcn, location, level, marker, message, thrown);
166 }
167
168 @Override
169 void log(String fqcn, Level level, Marker marker, Message message, Throwable thrown) {
170
171 logWithVarargTranslator(fqcn, level, marker, message, thrown);
172 }
173 };
174
175 private TranslatorType getTranslatorType() {
176 return loggerDisruptor.isUseThreadLocals() ? threadLocalTranslatorType : varargTranslatorType;
177 }
178
179 private boolean isReused(final Message message) {
180 return message instanceof ReusableMessage;
181 }
182
183
184
185
186
187
188
189
190
191
192
193
194
195 private void logWithThreadLocalTranslator(final String fqcn, final Level level, final Marker marker,
196 final Message message, final Throwable thrown) {
197
198
199 final RingBufferLogEventTranslator translator = getCachedTranslator();
200 initTranslator(translator, fqcn, level, marker, message, thrown);
201 initTranslatorThreadValues(translator);
202 publish(translator);
203 }
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218 private void logWithThreadLocalTranslator(final String fqcn, final StackTraceElement location, final Level level,
219 final Marker marker, final Message message, final Throwable thrown) {
220
221
222 final RingBufferLogEventTranslator translator = getCachedTranslator();
223 initTranslator(translator, fqcn, location, level, marker, message, thrown);
224 initTranslatorThreadValues(translator);
225 publish(translator);
226 }
227
228 private void publish(final RingBufferLogEventTranslator translator) {
229 if (!loggerDisruptor.tryPublish(translator)) {
230 handleRingBufferFull(translator);
231 }
232 }
233
234 private void handleRingBufferFull(final RingBufferLogEventTranslator translator) {
235 if (AbstractLogger.getRecursionDepth() > 1) {
236
237 AsyncQueueFullMessageUtil.logWarningToStatusLogger();
238 logMessageInCurrentThread(translator.fqcn, translator.level, translator.marker, translator.message,
239 translator.thrown);
240 return;
241 }
242 final EventRoute eventRoute = loggerDisruptor.getEventRoute(translator.level);
243 switch (eventRoute) {
244 case ENQUEUE:
245 loggerDisruptor.enqueueLogMessageWhenQueueFull(translator);
246 break;
247 case SYNCHRONOUS:
248 logMessageInCurrentThread(translator.fqcn, translator.level, translator.marker, translator.message,
249 translator.thrown);
250 break;
251 case DISCARD:
252 break;
253 default:
254 throw new IllegalStateException("Unknown EventRoute " + eventRoute);
255 }
256 }
257
258 private void initTranslator(final RingBufferLogEventTranslator translator, final String fqcn,
259 final StackTraceElement location, final Level level, final Marker marker,
260 final Message message, final Throwable thrown) {
261
262 translator.setBasicValues(this, name, marker, fqcn, level, message,
263
264 thrown,
265
266
267 ThreadContext.getImmutableStack(),
268
269 location,
270 CLOCK,
271 nanoClock
272 );
273 }
274
275 private void initTranslator(final RingBufferLogEventTranslator translator, final String fqcn,
276 final Level level, final Marker marker, final Message message, final Throwable thrown) {
277
278 translator.setBasicValues(this, name, marker, fqcn, level, message,
279
280 thrown,
281
282
283 ThreadContext.getImmutableStack(),
284
285
286 calcLocationIfRequested(fqcn),
287 CLOCK,
288 nanoClock
289 );
290 }
291
292 private void initTranslatorThreadValues(final RingBufferLogEventTranslator translator) {
293
294 if (THREAD_NAME_CACHING_STRATEGY == ThreadNameCachingStrategy.UNCACHED) {
295 translator.updateThreadValues();
296 }
297 }
298
299
300
301
302
303
304
305 private StackTraceElement calcLocationIfRequested(final String fqcn) {
306
307
308
309 return includeLocation ? StackLocatorUtil.calcLocation(fqcn) : null;
310 }
311
312
313
314
315
316
317
318
319
320
321
322
323
324 private void logWithVarargTranslator(final String fqcn, final Level level, final Marker marker,
325 final Message message, final Throwable thrown) {
326
327
328 final Disruptor<RingBufferLogEvent> disruptor = loggerDisruptor.getDisruptor();
329 if (disruptor == null) {
330 LOGGER.error("Ignoring log event after Log4j has been shut down.");
331 return;
332 }
333
334 if (!isReused(message)) {
335 InternalAsyncUtil.makeMessageImmutable(message);
336 }
337 StackTraceElement location = null;
338
339 if (!disruptor.getRingBuffer().tryPublishEvent(this,
340 this,
341 (location = calcLocationIfRequested(fqcn)),
342 fqcn,
343 level,
344 marker,
345 message,
346 thrown)) {
347 handleRingBufferFull(location, fqcn, level, marker, message, thrown);
348 }
349 }
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364 private void logWithVarargTranslator(final String fqcn, final StackTraceElement location, final Level level,
365 final Marker marker, final Message message, final Throwable thrown) {
366
367
368 final Disruptor<RingBufferLogEvent> disruptor = loggerDisruptor.getDisruptor();
369 if (disruptor == null) {
370 LOGGER.error("Ignoring log event after Log4j has been shut down.");
371 return;
372 }
373
374 if (!isReused(message)) {
375 InternalAsyncUtil.makeMessageImmutable(message);
376 }
377
378 if (!disruptor.getRingBuffer().tryPublishEvent(this,
379 this,
380 location,
381 fqcn,
382 level,
383 marker,
384 message,
385 thrown)) {
386 handleRingBufferFull(location, fqcn, level, marker, message, thrown);
387 }
388 }
389
390
391
392
393
394
395 @Override
396 public void translateTo(final RingBufferLogEvent event, final long sequence, final Object... args) {
397
398 final AsyncLogger asyncLogger = (AsyncLogger) args[0];
399 final StackTraceElement location = (StackTraceElement) args[1];
400 final String fqcn = (String) args[2];
401 final Level level = (Level) args[3];
402 final Marker marker = (Marker) args[4];
403 final Message message = (Message) args[5];
404 final Throwable thrown = (Throwable) args[6];
405
406
407 final ContextStack contextStack = ThreadContext.getImmutableStack();
408
409 final Thread currentThread = Thread.currentThread();
410 final String threadName = THREAD_NAME_CACHING_STRATEGY.getThreadName();
411 event.setValues(asyncLogger, asyncLogger.getName(), marker, fqcn, level, message, thrown,
412
413
414 CONTEXT_DATA_INJECTOR.injectContextData(null, (StringMap) event.getContextData()),
415 contextStack, currentThread.getId(), threadName, currentThread.getPriority(), location,
416 CLOCK, nanoClock);
417 }
418
419
420
421
422
423
424
425
426
427
428
429 void logMessageInCurrentThread(final String fqcn, final Level level, final Marker marker,
430 final Message message, final Throwable thrown) {
431
432 final ReliabilityStrategy strategy = privateConfig.loggerConfig.getReliabilityStrategy();
433 strategy.log(this, getName(), fqcn, marker, level, message, thrown);
434 }
435
436 private void handleRingBufferFull(final StackTraceElement location,
437 final String fqcn,
438 final Level level,
439 final Marker marker,
440 final Message msg,
441 final Throwable thrown) {
442 if (AbstractLogger.getRecursionDepth() > 1) {
443
444 AsyncQueueFullMessageUtil.logWarningToStatusLogger();
445 logMessageInCurrentThread(fqcn, level, marker, msg, thrown);
446 return;
447 }
448 final EventRoute eventRoute = loggerDisruptor.getEventRoute(level);
449 switch (eventRoute) {
450 case ENQUEUE:
451 loggerDisruptor.enqueueLogMessageWhenQueueFull(this,
452 this,
453 location,
454 fqcn,
455 level,
456 marker,
457 msg,
458 thrown);
459 break;
460 case SYNCHRONOUS:
461 logMessageInCurrentThread(fqcn, level, marker, msg, thrown);
462 break;
463 case DISCARD:
464 break;
465 default:
466 throw new IllegalStateException("Unknown EventRoute " + eventRoute);
467 }
468 }
469
470
471
472
473
474
475
476
477 public void actualAsyncLog(final RingBufferLogEvent event) {
478 final LoggerConfig privateConfigLoggerConfig = privateConfig.loggerConfig;
479 final List<Property> properties = privateConfigLoggerConfig.getPropertyList();
480
481 if (properties != null) {
482 onPropertiesPresent(event, properties);
483 }
484
485 privateConfigLoggerConfig.getReliabilityStrategy().log(this, event);
486 }
487
488 @SuppressWarnings("ForLoopReplaceableByForEach")
489 private void onPropertiesPresent(final RingBufferLogEvent event, final List<Property> properties) {
490 StringMap contextData = getContextData(event);
491 for (int i = 0, size = properties.size(); i < size; i++) {
492 final Property prop = properties.get(i);
493 if (contextData.getValue(prop.getName()) != null) {
494 continue;
495 }
496 final String value = prop.isValueNeedsLookup()
497 ? privateConfig.config.getStrSubstitutor().replace(event, prop.getValue())
498 : prop.getValue();
499 contextData.putValue(prop.getName(), value);
500 }
501 event.setContextData(contextData);
502 }
503
504 private static StringMap getContextData(final RingBufferLogEvent event) {
505 StringMap contextData = (StringMap) event.getContextData();
506 if (contextData.isFrozen()) {
507 final StringMap temp = ContextDataFactory.createContextData();
508 temp.putAll(contextData);
509 return temp;
510 }
511 return contextData;
512 }
513 }