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 abstract class TranslatorType {
134
135 abstract void log(final String fqcn, final Level level, final Marker marker,
136 final Message message, final Throwable thrown);
137 }
138
139 private final TranslatorType threadLocalTranslatorType = new TranslatorType() {
140 @Override
141 void log(String fqcn, Level level, Marker marker, Message message, Throwable thrown) {
142 logWithThreadLocalTranslator(fqcn, level, marker, message, thrown);
143 }
144 };
145
146 private final TranslatorType varargTranslatorType = new TranslatorType() {
147 @Override
148 void log(String fqcn, Level level, Marker marker, Message message, Throwable thrown) {
149
150 logWithVarargTranslator(fqcn, level, marker, message, thrown);
151 }
152 };
153
154 private TranslatorType getTranslatorType() {
155 return loggerDisruptor.isUseThreadLocals() ? threadLocalTranslatorType : varargTranslatorType;
156 }
157
158 private boolean isReused(final Message message) {
159 return message instanceof ReusableMessage;
160 }
161
162
163
164
165
166
167
168
169
170
171
172
173
174 private void logWithThreadLocalTranslator(final String fqcn, final Level level, final Marker marker,
175 final Message message, final Throwable thrown) {
176
177
178 final RingBufferLogEventTranslator translator = getCachedTranslator();
179 initTranslator(translator, fqcn, level, marker, message, thrown);
180 initTranslatorThreadValues(translator);
181 publish(translator);
182 }
183
184 private void publish(final RingBufferLogEventTranslator translator) {
185 if (!loggerDisruptor.tryPublish(translator)) {
186 handleRingBufferFull(translator);
187 }
188 }
189
190 private void handleRingBufferFull(final RingBufferLogEventTranslator translator) {
191 if (AbstractLogger.getRecursionDepth() > 1) {
192
193 AsyncQueueFullMessageUtil.logWarningToStatusLogger();
194 logMessageInCurrentThread(translator.fqcn, translator.level, translator.marker, translator.message,
195 translator.thrown);
196 return;
197 }
198 final EventRoute eventRoute = loggerDisruptor.getEventRoute(translator.level);
199 switch (eventRoute) {
200 case ENQUEUE:
201 loggerDisruptor.enqueueLogMessageWhenQueueFull(translator);
202 break;
203 case SYNCHRONOUS:
204 logMessageInCurrentThread(translator.fqcn, translator.level, translator.marker, translator.message,
205 translator.thrown);
206 break;
207 case DISCARD:
208 break;
209 default:
210 throw new IllegalStateException("Unknown EventRoute " + eventRoute);
211 }
212 }
213
214 private void initTranslator(final RingBufferLogEventTranslator translator, final String fqcn,
215 final Level level, final Marker marker, final Message message, final Throwable thrown) {
216
217 translator.setBasicValues(this, name, marker, fqcn, level, message,
218
219 thrown,
220
221
222 ThreadContext.getImmutableStack(),
223
224
225 calcLocationIfRequested(fqcn),
226 CLOCK,
227 nanoClock
228 );
229 }
230
231 private void initTranslatorThreadValues(final RingBufferLogEventTranslator translator) {
232
233 if (THREAD_NAME_CACHING_STRATEGY == ThreadNameCachingStrategy.UNCACHED) {
234 translator.updateThreadValues();
235 }
236 }
237
238
239
240
241
242
243
244 private StackTraceElement calcLocationIfRequested(final String fqcn) {
245
246
247
248 return includeLocation ? StackLocatorUtil.calcLocation(fqcn) : null;
249 }
250
251
252
253
254
255
256
257
258
259
260
261
262
263 private void logWithVarargTranslator(final String fqcn, final Level level, final Marker marker,
264 final Message message, final Throwable thrown) {
265
266
267 final Disruptor<RingBufferLogEvent> disruptor = loggerDisruptor.getDisruptor();
268 if (disruptor == null) {
269 LOGGER.error("Ignoring log event after Log4j has been shut down.");
270 return;
271 }
272
273 if (!isReused(message)) {
274 InternalAsyncUtil.makeMessageImmutable(message);
275 }
276 StackTraceElement location = null;
277
278 if (!disruptor.getRingBuffer().tryPublishEvent(this,
279 this,
280 (location = calcLocationIfRequested(fqcn)),
281 fqcn,
282 level,
283 marker,
284 message,
285 thrown)) {
286 handleRingBufferFull(location, fqcn, level, marker, message, thrown);
287 }
288 }
289
290
291
292
293
294
295 @Override
296 public void translateTo(final RingBufferLogEvent event, final long sequence, final Object... args) {
297
298 final AsyncLogger asyncLogger = (AsyncLogger) args[0];
299 final StackTraceElement location = (StackTraceElement) args[1];
300 final String fqcn = (String) args[2];
301 final Level level = (Level) args[3];
302 final Marker marker = (Marker) args[4];
303 final Message message = (Message) args[5];
304 final Throwable thrown = (Throwable) args[6];
305
306
307 final ContextStack contextStack = ThreadContext.getImmutableStack();
308
309 final Thread currentThread = Thread.currentThread();
310 final String threadName = THREAD_NAME_CACHING_STRATEGY.getThreadName();
311 event.setValues(asyncLogger, asyncLogger.getName(), marker, fqcn, level, message, thrown,
312
313
314 CONTEXT_DATA_INJECTOR.injectContextData(null, (StringMap) event.getContextData()),
315 contextStack, currentThread.getId(), threadName, currentThread.getPriority(), location,
316 CLOCK, nanoClock);
317 }
318
319
320
321
322
323
324
325
326
327
328
329 void logMessageInCurrentThread(final String fqcn, final Level level, final Marker marker,
330 final Message message, final Throwable thrown) {
331
332 final ReliabilityStrategy strategy = privateConfig.loggerConfig.getReliabilityStrategy();
333 strategy.log(this, getName(), fqcn, marker, level, message, thrown);
334 }
335
336 private void handleRingBufferFull(final StackTraceElement location,
337 final String fqcn,
338 final Level level,
339 final Marker marker,
340 final Message msg,
341 final Throwable thrown) {
342 if (AbstractLogger.getRecursionDepth() > 1) {
343
344 AsyncQueueFullMessageUtil.logWarningToStatusLogger();
345 logMessageInCurrentThread(fqcn, level, marker, msg, thrown);
346 return;
347 }
348 final EventRoute eventRoute = loggerDisruptor.getEventRoute(level);
349 switch (eventRoute) {
350 case ENQUEUE:
351 loggerDisruptor.enqueueLogMessageWhenQueueFull(this,
352 this,
353 location,
354 fqcn,
355 level,
356 marker,
357 msg,
358 thrown);
359 break;
360 case SYNCHRONOUS:
361 logMessageInCurrentThread(fqcn, level, marker, msg, thrown);
362 break;
363 case DISCARD:
364 break;
365 default:
366 throw new IllegalStateException("Unknown EventRoute " + eventRoute);
367 }
368 }
369
370
371
372
373
374
375
376
377 public void actualAsyncLog(final RingBufferLogEvent event) {
378 final LoggerConfig privateConfigLoggerConfig = privateConfig.loggerConfig;
379 final List<Property> properties = privateConfigLoggerConfig.getPropertyList();
380
381 if (properties != null) {
382 onPropertiesPresent(event, properties);
383 }
384
385 privateConfigLoggerConfig.getReliabilityStrategy().log(this, event);
386 }
387
388 @SuppressWarnings("ForLoopReplaceableByForEach")
389 private void onPropertiesPresent(final RingBufferLogEvent event, final List<Property> properties) {
390 StringMap contextData = getContextData(event);
391 for (int i = 0, size = properties.size(); i < size; i++) {
392 final Property prop = properties.get(i);
393 if (contextData.getValue(prop.getName()) != null) {
394 continue;
395 }
396 final String value = prop.isValueNeedsLookup()
397 ? privateConfig.config.getStrSubstitutor().replace(event, prop.getValue())
398 : prop.getValue();
399 contextData.putValue(prop.getName(), value);
400 }
401 event.setContextData(contextData);
402 }
403
404 private static StringMap getContextData(final RingBufferLogEvent event) {
405 StringMap contextData = (StringMap) event.getContextData();
406 if (contextData.isFrozen()) {
407 final StringMap temp = ContextDataFactory.createContextData();
408 temp.putAll(contextData);
409 return temp;
410 }
411 return contextData;
412 }
413 }