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.Property;
30 import org.apache.logging.log4j.core.config.ReliabilityStrategy;
31 import org.apache.logging.log4j.core.impl.ContextDataFactory;
32 import org.apache.logging.log4j.core.impl.ContextDataInjectorFactory;
33 import org.apache.logging.log4j.core.util.Clock;
34 import org.apache.logging.log4j.core.util.ClockFactory;
35 import org.apache.logging.log4j.core.util.NanoClock;
36 import org.apache.logging.log4j.message.Message;
37 import org.apache.logging.log4j.message.MessageFactory;
38 import org.apache.logging.log4j.message.ReusableMessage;
39 import org.apache.logging.log4j.spi.AbstractLogger;
40 import org.apache.logging.log4j.status.StatusLogger;
41 import org.apache.logging.log4j.util.StackLocatorUtil;
42 import org.apache.logging.log4j.util.StringMap;
43
44 import com.lmax.disruptor.EventTranslatorVararg;
45 import com.lmax.disruptor.dsl.Disruptor;
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66 public class AsyncLogger extends Logger implements EventTranslatorVararg<RingBufferLogEvent> {
67
68
69
70
71
72 private static final StatusLogger LOGGER = StatusLogger.getLogger();
73 private static final Clock CLOCK = ClockFactory.getClock();
74 private static final ContextDataInjector CONTEXT_DATA_INJECTOR = ContextDataInjectorFactory.createInjector();
75
76 private static final ThreadNameCachingStrategy THREAD_NAME_CACHING_STRATEGY = ThreadNameCachingStrategy.create();
77
78 private final ThreadLocal<RingBufferLogEventTranslator> threadLocalTranslator = new ThreadLocal<>();
79 private final AsyncLoggerDisruptor loggerDisruptor;
80
81 private volatile boolean includeLocation;
82 private volatile NanoClock nanoClock;
83
84
85
86
87
88
89
90
91
92 public AsyncLogger(final LoggerContext context, final String name, final MessageFactory messageFactory,
93 final AsyncLoggerDisruptor loggerDisruptor) {
94 super(context, name, messageFactory);
95 this.loggerDisruptor = loggerDisruptor;
96 includeLocation = privateConfig.loggerConfig.isIncludeLocation();
97 nanoClock = context.getConfiguration().getNanoClock();
98 }
99
100
101
102
103
104
105 @Override
106 protected void updateConfiguration(final Configuration newConfig) {
107 nanoClock = newConfig.getNanoClock();
108 includeLocation = newConfig.getLoggerConfig(name).isIncludeLocation();
109 super.updateConfiguration(newConfig);
110 }
111
112
113 NanoClock getNanoClock() {
114 return nanoClock;
115 }
116
117 private RingBufferLogEventTranslator getCachedTranslator() {
118 RingBufferLogEventTranslator result = threadLocalTranslator.get();
119 if (result == null) {
120 result = new RingBufferLogEventTranslator();
121 threadLocalTranslator.set(result);
122 }
123 return result;
124 }
125
126 @Override
127 public void logMessage(final String fqcn, final Level level, final Marker marker, final Message message,
128 final Throwable thrown) {
129
130 if (loggerDisruptor.isUseThreadLocals()) {
131 logWithThreadLocalTranslator(fqcn, level, marker, message, thrown);
132 } else {
133
134 logWithVarargTranslator(fqcn, level, marker, message, thrown);
135 }
136 }
137
138 private boolean isReused(final Message message) {
139 return message instanceof ReusableMessage;
140 }
141
142
143
144
145
146
147
148
149
150
151
152
153
154 private void logWithThreadLocalTranslator(final String fqcn, final Level level, final Marker marker,
155 final Message message, final Throwable thrown) {
156
157
158 final RingBufferLogEventTranslator translator = getCachedTranslator();
159 initTranslator(translator, fqcn, level, marker, message, thrown);
160 initTranslatorThreadValues(translator);
161 publish(translator);
162 }
163
164 private void publish(final RingBufferLogEventTranslator translator) {
165 if (!loggerDisruptor.tryPublish(translator)) {
166 handleRingBufferFull(translator);
167 }
168 }
169
170 private void handleRingBufferFull(final RingBufferLogEventTranslator translator) {
171 if (AbstractLogger.getRecursionDepth() > 1) {
172
173 AsyncQueueFullMessageUtil.logWarningToStatusLogger();
174 logMessageInCurrentThread(translator.fqcn, translator.level, translator.marker, translator.message,
175 translator.thrown);
176 return;
177 }
178 final EventRoute eventRoute = loggerDisruptor.getEventRoute(translator.level);
179 switch (eventRoute) {
180 case ENQUEUE:
181 loggerDisruptor.enqueueLogMessageInfo(translator);
182 break;
183 case SYNCHRONOUS:
184 logMessageInCurrentThread(translator.fqcn, translator.level, translator.marker, translator.message,
185 translator.thrown);
186 break;
187 case DISCARD:
188 break;
189 default:
190 throw new IllegalStateException("Unknown EventRoute " + eventRoute);
191 }
192 }
193
194 private void initTranslator(final RingBufferLogEventTranslator translator, final String fqcn,
195 final Level level, final Marker marker, final Message message, final Throwable thrown) {
196
197 translator.setBasicValues(this, name, marker, fqcn, level, message,
198
199 thrown,
200
201
202 ThreadContext.getImmutableStack(),
203
204
205 calcLocationIfRequested(fqcn),
206 CLOCK,
207 nanoClock
208 );
209 }
210
211 private void initTranslatorThreadValues(final RingBufferLogEventTranslator translator) {
212
213 if (THREAD_NAME_CACHING_STRATEGY == ThreadNameCachingStrategy.UNCACHED) {
214 translator.updateThreadValues();
215 }
216 }
217
218
219
220
221
222
223
224 private StackTraceElement calcLocationIfRequested(final String fqcn) {
225
226
227
228 return includeLocation ? StackLocatorUtil.calcLocation(fqcn) : null;
229 }
230
231
232
233
234
235
236
237
238
239
240
241
242
243 private void logWithVarargTranslator(final String fqcn, final Level level, final Marker marker,
244 final Message message, final Throwable thrown) {
245
246
247 final Disruptor<RingBufferLogEvent> disruptor = loggerDisruptor.getDisruptor();
248 if (disruptor == null) {
249 LOGGER.error("Ignoring log event after Log4j has been shut down.");
250 return;
251 }
252
253 if (!isReused(message)) {
254 InternalAsyncUtil.makeMessageImmutable(message);
255 }
256 StackTraceElement location = null;
257
258 if (!disruptor.getRingBuffer().tryPublishEvent(this,
259 this,
260 (location = calcLocationIfRequested(fqcn)),
261 fqcn,
262 level,
263 marker,
264 message,
265 thrown)) {
266 handleRingBufferFull(location, fqcn, level, marker, message, thrown);
267 }
268 }
269
270
271
272
273
274
275 @Override
276 public void translateTo(final RingBufferLogEvent event, final long sequence, final Object... args) {
277
278 final AsyncLogger asyncLogger = (AsyncLogger) args[0];
279 final StackTraceElement location = (StackTraceElement) args[1];
280 final String fqcn = (String) args[2];
281 final Level level = (Level) args[3];
282 final Marker marker = (Marker) args[4];
283 final Message message = (Message) args[5];
284 final Throwable thrown = (Throwable) args[6];
285
286
287 final ContextStack contextStack = ThreadContext.getImmutableStack();
288
289 final Thread currentThread = Thread.currentThread();
290 final String threadName = THREAD_NAME_CACHING_STRATEGY.getThreadName();
291 event.setValues(asyncLogger, asyncLogger.getName(), marker, fqcn, level, message, thrown,
292
293
294 CONTEXT_DATA_INJECTOR.injectContextData(null, (StringMap) event.getContextData()),
295 contextStack, currentThread.getId(), threadName, currentThread.getPriority(), location,
296 CLOCK, nanoClock);
297 }
298
299
300
301
302
303
304
305
306
307
308
309 void logMessageInCurrentThread(final String fqcn, final Level level, final Marker marker,
310 final Message message, final Throwable thrown) {
311
312 final ReliabilityStrategy strategy = privateConfig.loggerConfig.getReliabilityStrategy();
313 strategy.log(this, getName(), fqcn, marker, level, message, thrown);
314 }
315
316 private void handleRingBufferFull(final StackTraceElement location,
317 final String fqcn,
318 final Level level,
319 final Marker marker,
320 final Message msg,
321 final Throwable thrown) {
322 if (AbstractLogger.getRecursionDepth() > 1) {
323
324 AsyncQueueFullMessageUtil.logWarningToStatusLogger();
325 logMessageInCurrentThread(fqcn, level, marker, msg, thrown);
326 return;
327 }
328 final EventRoute eventRoute = loggerDisruptor.getEventRoute(level);
329 switch (eventRoute) {
330 case ENQUEUE:
331 loggerDisruptor.getDisruptor().getRingBuffer().publishEvent(this,
332 this,
333 location,
334 fqcn,
335 level,
336 marker,
337 msg,
338 thrown);
339 break;
340 case SYNCHRONOUS:
341 logMessageInCurrentThread(fqcn, level, marker, msg, thrown);
342 break;
343 case DISCARD:
344 break;
345 default:
346 throw new IllegalStateException("Unknown EventRoute " + eventRoute);
347 }
348 }
349
350
351
352
353
354
355
356
357 public void actualAsyncLog(final RingBufferLogEvent event) {
358 final List<Property> properties = privateConfig.loggerConfig.getPropertyList();
359
360 if (properties != null) {
361 StringMap contextData = (StringMap) event.getContextData();
362 if (contextData.isFrozen()) {
363 final StringMap temp = ContextDataFactory.createContextData();
364 temp.putAll(contextData);
365 contextData = temp;
366 }
367 for (int i = 0; i < properties.size(); i++) {
368 final Property prop = properties.get(i);
369 if (contextData.getValue(prop.getName()) != null) {
370 continue;
371 }
372 final String value = prop.isValueNeedsLookup()
373 ? privateConfig.config.getStrSubstitutor().replace(event, prop.getValue())
374 : prop.getValue();
375 contextData.putValue(prop.getName(), value);
376 }
377 event.setContextData(contextData);
378 }
379
380 final ReliabilityStrategy strategy = privateConfig.loggerConfig.getReliabilityStrategy();
381 strategy.log(this, event);
382 }
383 }