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 translator.clear();
241 return;
242 }
243 final EventRoute eventRoute = loggerDisruptor.getEventRoute(translator.level);
244 switch (eventRoute) {
245 case ENQUEUE:
246 loggerDisruptor.enqueueLogMessageWhenQueueFull(translator);
247 break;
248 case SYNCHRONOUS:
249 logMessageInCurrentThread(translator.fqcn, translator.level, translator.marker, translator.message,
250 translator.thrown);
251 translator.clear();
252 break;
253 case DISCARD:
254 translator.clear();
255 break;
256 default:
257 throw new IllegalStateException("Unknown EventRoute " + eventRoute);
258 }
259 }
260
261 private void initTranslator(final RingBufferLogEventTranslator translator, final String fqcn,
262 final StackTraceElement location, final Level level, final Marker marker,
263 final Message message, final Throwable thrown) {
264
265 translator.setBasicValues(this, name, marker, fqcn, level, message,
266
267 thrown,
268
269
270 ThreadContext.getImmutableStack(),
271
272 location,
273 CLOCK,
274 nanoClock
275 );
276 }
277
278 private void initTranslator(final RingBufferLogEventTranslator translator, final String fqcn,
279 final Level level, final Marker marker, final Message message, final Throwable thrown) {
280
281 translator.setBasicValues(this, name, marker, fqcn, level, message,
282
283 thrown,
284
285
286 ThreadContext.getImmutableStack(),
287
288
289 calcLocationIfRequested(fqcn),
290 CLOCK,
291 nanoClock
292 );
293 }
294
295 private void initTranslatorThreadValues(final RingBufferLogEventTranslator translator) {
296
297 if (THREAD_NAME_CACHING_STRATEGY == ThreadNameCachingStrategy.UNCACHED) {
298 translator.updateThreadValues();
299 }
300 }
301
302
303
304
305
306
307
308 private StackTraceElement calcLocationIfRequested(final String fqcn) {
309
310
311
312 return includeLocation ? StackLocatorUtil.calcLocation(fqcn) : null;
313 }
314
315
316
317
318
319
320
321
322
323
324
325
326
327 private void logWithVarargTranslator(final String fqcn, final Level level, final Marker marker,
328 final Message message, final Throwable thrown) {
329
330
331 final Disruptor<RingBufferLogEvent> disruptor = loggerDisruptor.getDisruptor();
332 if (disruptor == null) {
333 LOGGER.error("Ignoring log event after Log4j has been shut down.");
334 return;
335 }
336
337 if (!isReused(message)) {
338 InternalAsyncUtil.makeMessageImmutable(message);
339 }
340 StackTraceElement location = null;
341
342 if (!disruptor.getRingBuffer().tryPublishEvent(this,
343 this,
344 (location = calcLocationIfRequested(fqcn)),
345 fqcn,
346 level,
347 marker,
348 message,
349 thrown)) {
350 handleRingBufferFull(location, fqcn, level, marker, message, thrown);
351 }
352 }
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367 private void logWithVarargTranslator(final String fqcn, final StackTraceElement location, final Level level,
368 final Marker marker, final Message message, final Throwable thrown) {
369
370
371 final Disruptor<RingBufferLogEvent> disruptor = loggerDisruptor.getDisruptor();
372 if (disruptor == null) {
373 LOGGER.error("Ignoring log event after Log4j has been shut down.");
374 return;
375 }
376
377 if (!isReused(message)) {
378 InternalAsyncUtil.makeMessageImmutable(message);
379 }
380
381 if (!disruptor.getRingBuffer().tryPublishEvent(this,
382 this,
383 location,
384 fqcn,
385 level,
386 marker,
387 message,
388 thrown)) {
389 handleRingBufferFull(location, fqcn, level, marker, message, thrown);
390 }
391 }
392
393
394
395
396
397
398 @Override
399 public void translateTo(final RingBufferLogEvent event, final long sequence, final Object... args) {
400
401 final AsyncLogger asyncLogger = (AsyncLogger) args[0];
402 final StackTraceElement location = (StackTraceElement) args[1];
403 final String fqcn = (String) args[2];
404 final Level level = (Level) args[3];
405 final Marker marker = (Marker) args[4];
406 final Message message = (Message) args[5];
407 final Throwable thrown = (Throwable) args[6];
408
409
410 final ContextStack contextStack = ThreadContext.getImmutableStack();
411
412 final Thread currentThread = Thread.currentThread();
413 final String threadName = THREAD_NAME_CACHING_STRATEGY.getThreadName();
414 event.setValues(asyncLogger, asyncLogger.getName(), marker, fqcn, level, message, thrown,
415
416
417 CONTEXT_DATA_INJECTOR.injectContextData(null, (StringMap) event.getContextData()),
418 contextStack, currentThread.getId(), threadName, currentThread.getPriority(), location,
419 CLOCK, nanoClock);
420 }
421
422
423
424
425
426
427
428
429
430
431
432 void logMessageInCurrentThread(final String fqcn, final Level level, final Marker marker,
433 final Message message, final Throwable thrown) {
434
435 final ReliabilityStrategy strategy = privateConfig.loggerConfig.getReliabilityStrategy();
436 strategy.log(this, getName(), fqcn, marker, level, message, thrown);
437 }
438
439 private void handleRingBufferFull(final StackTraceElement location,
440 final String fqcn,
441 final Level level,
442 final Marker marker,
443 final Message msg,
444 final Throwable thrown) {
445 if (AbstractLogger.getRecursionDepth() > 1) {
446
447 AsyncQueueFullMessageUtil.logWarningToStatusLogger();
448 logMessageInCurrentThread(fqcn, level, marker, msg, thrown);
449 return;
450 }
451 final EventRoute eventRoute = loggerDisruptor.getEventRoute(level);
452 switch (eventRoute) {
453 case ENQUEUE:
454 loggerDisruptor.enqueueLogMessageWhenQueueFull(this,
455 this,
456 location,
457 fqcn,
458 level,
459 marker,
460 msg,
461 thrown);
462 break;
463 case SYNCHRONOUS:
464 logMessageInCurrentThread(fqcn, level, marker, msg, thrown);
465 break;
466 case DISCARD:
467 break;
468 default:
469 throw new IllegalStateException("Unknown EventRoute " + eventRoute);
470 }
471 }
472
473
474
475
476
477
478
479
480 public void actualAsyncLog(final RingBufferLogEvent event) {
481 final LoggerConfig privateConfigLoggerConfig = privateConfig.loggerConfig;
482 final List<Property> properties = privateConfigLoggerConfig.getPropertyList();
483
484 if (properties != null) {
485 onPropertiesPresent(event, properties);
486 }
487
488 privateConfigLoggerConfig.getReliabilityStrategy().log(this, event);
489 }
490
491 @SuppressWarnings("ForLoopReplaceableByForEach")
492 private void onPropertiesPresent(final RingBufferLogEvent event, final List<Property> properties) {
493 StringMap contextData = getContextData(event);
494 for (int i = 0, size = properties.size(); i < size; i++) {
495 final Property prop = properties.get(i);
496 if (contextData.getValue(prop.getName()) != null) {
497 continue;
498 }
499 final String value = prop.isValueNeedsLookup()
500 ? privateConfig.config.getStrSubstitutor().replace(event, prop.getValue())
501 : prop.getValue();
502 contextData.putValue(prop.getName(), value);
503 }
504 event.setContextData(contextData);
505 }
506
507 private static StringMap getContextData(final RingBufferLogEvent event) {
508 StringMap contextData = (StringMap) event.getContextData();
509 if (contextData.isFrozen()) {
510 final StringMap temp = ContextDataFactory.createContextData();
511 temp.putAll(contextData);
512 return temp;
513 }
514 return contextData;
515 }
516 }