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.Logger;
26 import org.apache.logging.log4j.core.LoggerContext;
27 import org.apache.logging.log4j.core.config.Configuration;
28 import org.apache.logging.log4j.core.config.Property;
29 import org.apache.logging.log4j.core.config.ReliabilityStrategy;
30 import org.apache.logging.log4j.core.impl.ContextDataFactory;
31 import org.apache.logging.log4j.core.ContextDataInjector;
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.Constants;
36 import org.apache.logging.log4j.core.util.NanoClock;
37 import org.apache.logging.log4j.message.AsynchronouslyFormattable;
38 import org.apache.logging.log4j.message.Message;
39 import org.apache.logging.log4j.message.MessageFactory;
40 import org.apache.logging.log4j.message.ReusableMessage;
41 import org.apache.logging.log4j.util.StackLocatorUtil;
42 import org.apache.logging.log4j.util.StringMap;
43 import org.apache.logging.log4j.status.StatusLogger;
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
131 if (loggerDisruptor.isUseThreadLocals()) {
132 logWithThreadLocalTranslator(fqcn, level, marker, message, thrown);
133 } else {
134
135 logWithVarargTranslator(fqcn, level, marker, message, thrown);
136 }
137 }
138
139 private boolean isReused(final Message message) {
140 return message instanceof ReusableMessage;
141 }
142
143
144
145
146
147
148
149
150
151
152
153
154
155 private void logWithThreadLocalTranslator(final String fqcn, final Level level, final Marker marker,
156 final Message message, final Throwable thrown) {
157
158
159 final RingBufferLogEventTranslator translator = getCachedTranslator();
160 initTranslator(translator, fqcn, level, marker, message, thrown);
161 initTranslatorThreadValues(translator);
162 publish(translator);
163 }
164
165 private void publish(final RingBufferLogEventTranslator translator) {
166 if (!loggerDisruptor.tryPublish(translator)) {
167 handleRingBufferFull(translator);
168 }
169 }
170
171 private void handleRingBufferFull(final RingBufferLogEventTranslator translator) {
172 final EventRoute eventRoute = loggerDisruptor.getEventRoute(translator.level);
173 switch (eventRoute) {
174 case ENQUEUE:
175 loggerDisruptor.enqueueLogMessageInfo(translator);
176 break;
177 case SYNCHRONOUS:
178 logMessageInCurrentThread(translator.fqcn, translator.level, translator.marker, translator.message,
179 translator.thrown);
180 break;
181 case DISCARD:
182 break;
183 default:
184 throw new IllegalStateException("Unknown EventRoute " + eventRoute);
185 }
186 }
187
188 private void initTranslator(final RingBufferLogEventTranslator translator, final String fqcn,
189 final Level level, final Marker marker, final Message message, final Throwable thrown) {
190
191 translator.setBasicValues(this, name, marker, fqcn, level, message,
192
193 thrown,
194
195
196 ThreadContext.getImmutableStack(),
197
198
199 calcLocationIfRequested(fqcn),
200 CLOCK.currentTimeMillis(),
201 nanoClock.nanoTime()
202 );
203 }
204
205 private void initTranslatorThreadValues(final RingBufferLogEventTranslator translator) {
206
207 if (THREAD_NAME_CACHING_STRATEGY == ThreadNameCachingStrategy.UNCACHED) {
208 translator.updateThreadValues();
209 }
210 }
211
212
213
214
215
216
217
218 private StackTraceElement calcLocationIfRequested(final String fqcn) {
219
220
221
222 return includeLocation ? StackLocatorUtil.calcLocation(fqcn) : null;
223 }
224
225
226
227
228
229
230
231
232
233
234
235
236
237 private void logWithVarargTranslator(final String fqcn, final Level level, final Marker marker,
238 final Message message, final Throwable thrown) {
239
240
241 final Disruptor<RingBufferLogEvent> disruptor = loggerDisruptor.getDisruptor();
242 if (disruptor == null) {
243 LOGGER.error("Ignoring log event after Log4j has been shut down.");
244 return;
245 }
246
247 if (!canFormatMessageInBackground(message) && !isReused(message)) {
248 message.getFormattedMessage();
249 }
250
251 disruptor.getRingBuffer().publishEvent(this, this, calcLocationIfRequested(fqcn), fqcn, level, marker, message,
252 thrown);
253 }
254
255 private boolean canFormatMessageInBackground(final Message message) {
256 return Constants.FORMAT_MESSAGES_IN_BACKGROUND
257 || message.getClass().isAnnotationPresent(AsynchronouslyFormattable.class);
258 }
259
260
261
262
263
264
265 @Override
266 public void translateTo(final RingBufferLogEvent event, final long sequence, final Object... args) {
267
268 final AsyncLogger asyncLogger = (AsyncLogger) args[0];
269 final StackTraceElement location = (StackTraceElement) args[1];
270 final String fqcn = (String) args[2];
271 final Level level = (Level) args[3];
272 final Marker marker = (Marker) args[4];
273 final Message message = (Message) args[5];
274 final Throwable thrown = (Throwable) args[6];
275
276
277 final ContextStack contextStack = ThreadContext.getImmutableStack();
278
279 final Thread currentThread = Thread.currentThread();
280 final String threadName = THREAD_NAME_CACHING_STRATEGY.getThreadName();
281 event.setValues(asyncLogger, asyncLogger.getName(), marker, fqcn, level, message, thrown,
282
283
284 CONTEXT_DATA_INJECTOR.injectContextData(null, (StringMap) event.getContextData()),
285 contextStack, currentThread.getId(), threadName, currentThread.getPriority(), location,
286 CLOCK.currentTimeMillis(), nanoClock.nanoTime());
287 }
288
289
290
291
292
293
294
295
296
297
298
299 void logMessageInCurrentThread(final String fqcn, final Level level, final Marker marker,
300 final Message message, final Throwable thrown) {
301
302 final ReliabilityStrategy strategy = privateConfig.loggerConfig.getReliabilityStrategy();
303 strategy.log(this, getName(), fqcn, marker, level, message, thrown);
304 }
305
306
307
308
309
310
311
312
313 public void actualAsyncLog(final RingBufferLogEvent event) {
314 final List<Property> properties = privateConfig.loggerConfig.getPropertyList();
315
316 if (properties != null) {
317 StringMap contextData = (StringMap) event.getContextData();
318 if (contextData.isFrozen()) {
319 final StringMap temp = ContextDataFactory.createContextData();
320 temp.putAll(contextData);
321 contextData = temp;
322 }
323 for (int i = 0; i < properties.size(); i++) {
324 final Property prop = properties.get(i);
325 if (contextData.getValue(prop.getName()) != null) {
326 continue;
327 }
328 final String value = prop.isValueNeedsLookup()
329 ? privateConfig.config.getStrSubstitutor().replace(event, prop.getValue())
330 : prop.getValue();
331 contextData.putValue(prop.getName(), value);
332 }
333 event.setContextData(contextData);
334 }
335
336 final ReliabilityStrategy strategy = privateConfig.loggerConfig.getReliabilityStrategy();
337 strategy.log(this, event);
338 }
339 }