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.Map;
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.Log4jLogEvent;
31 import org.apache.logging.log4j.core.util.Clock;
32 import org.apache.logging.log4j.core.util.ClockFactory;
33 import org.apache.logging.log4j.core.util.Constants;
34 import org.apache.logging.log4j.core.util.NanoClock;
35 import org.apache.logging.log4j.core.util.NanoClockFactory;
36 import org.apache.logging.log4j.message.Message;
37 import org.apache.logging.log4j.message.MessageFactory;
38 import org.apache.logging.log4j.message.TimestampMessage;
39 import org.apache.logging.log4j.status.StatusLogger;
40
41 import com.lmax.disruptor.EventTranslatorVararg;
42 import com.lmax.disruptor.dsl.Disruptor;
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63 public class AsyncLogger extends Logger implements EventTranslatorVararg<RingBufferLogEvent> {
64
65
66
67
68
69 private static final long serialVersionUID = 1L;
70 private static final StatusLogger LOGGER = StatusLogger.getLogger();
71 private static final Clock CLOCK = ClockFactory.getClock();
72
73 private static final ThreadNameCachingStrategy THREAD_NAME_CACHING_STRATEGY = ThreadNameCachingStrategy.create();
74
75 private final ThreadLocal<RingBufferLogEventTranslator> threadLocalTranslator = new ThreadLocal<>();
76 private final AsyncLoggerDisruptor loggerDisruptor;
77
78 private volatile NanoClock nanoClock;
79
80
81
82
83
84
85
86
87
88 public AsyncLogger(final LoggerContext context, final String name, final MessageFactory messageFactory,
89 final AsyncLoggerDisruptor loggerDisruptor) {
90 super(context, name, messageFactory);
91 this.loggerDisruptor = loggerDisruptor;
92 nanoClock = NanoClockFactory.createNanoClock();
93 }
94
95
96
97
98
99
100 @Override
101 protected void updateConfiguration(Configuration newConfig) {
102 super.updateConfiguration(newConfig);
103 nanoClock = NanoClockFactory.createNanoClock();
104 LOGGER.trace("[{}] AsyncLogger {} uses {}.", getContext().getName(), getName(), nanoClock);
105 }
106
107
108 NanoClock getNanoClock() {
109 return nanoClock;
110 }
111
112 private RingBufferLogEventTranslator getCachedTranslator() {
113 RingBufferLogEventTranslator result = threadLocalTranslator.get();
114 if (result == null) {
115 result = new RingBufferLogEventTranslator();
116 threadLocalTranslator.set(result);
117 }
118 return result;
119 }
120
121 @Override
122 public void logMessage(final String fqcn, final Level level, final Marker marker, final Message message,
123 final Throwable thrown) {
124
125
126
127 if (loggerDisruptor.shouldLogInCurrentThread()) {
128 logMessageInCurrentThread(fqcn, level, marker, message, thrown);
129 } else {
130 logMessageInBackgroundThread(fqcn, level, marker, message, thrown);
131 }
132 }
133
134
135
136
137
138
139
140
141
142
143
144
145
146 private void logMessageInCurrentThread(final String fqcn, final Level level, final Marker marker,
147 final Message message, final Throwable thrown) {
148
149 final ReliabilityStrategy strategy = privateConfig.loggerConfig.getReliabilityStrategy();
150 strategy.log(this, getName(), fqcn, marker, level, message, thrown);
151 }
152
153
154
155
156
157
158
159
160
161
162
163 private void logMessageInBackgroundThread(final String fqcn, final Level level, final Marker marker,
164 final Message message, final Throwable thrown) {
165
166
167
168 if (!Constants.FORMAT_MESSAGES_IN_BACKGROUND) {
169 message.getFormattedMessage();
170 }
171 logInBackground(fqcn, level, marker, message, thrown);
172 }
173
174
175
176
177
178
179
180
181
182
183
184
185 private void logInBackground(final String fqcn, final Level level, final Marker marker, final Message message,
186 final Throwable thrown) {
187
188
189 if (loggerDisruptor.isUseThreadLocals()) {
190 logWithThreadLocalTranslator(fqcn, level, marker, message, thrown);
191 } else {
192
193 logWithVarargTranslator(fqcn, level, marker, message, thrown);
194 }
195 }
196
197
198
199
200
201
202
203
204
205
206
207
208
209 private void logWithThreadLocalTranslator(final String fqcn, final Level level, final Marker marker,
210 final Message message, final Throwable thrown) {
211
212
213 final RingBufferLogEventTranslator translator = getCachedTranslator();
214 initTranslator(translator, fqcn, level, marker, message, thrown);
215 loggerDisruptor.enqueueLogMessageInfo(translator);
216 }
217
218 private void initTranslator(final RingBufferLogEventTranslator translator, final String fqcn,
219 final Level level, final Marker marker, final Message message, final Throwable thrown) {
220
221
222
223 initTranslatorPart1(translator, fqcn, level, marker, message, thrown);
224 initTranslatorPart2(translator, fqcn, message);
225 }
226
227 private void initTranslatorPart1(final RingBufferLogEventTranslator translator, final String fqcn,
228 final Level level, final Marker marker, final Message message, final Throwable thrown) {
229
230
231
232 translator.setValuesPart1(this, getName(), marker, fqcn, level, message,
233
234 thrown);
235 }
236
237 private void initTranslatorPart2(final RingBufferLogEventTranslator translator, final String fqcn,
238 final Message message) {
239
240
241
242 translator.setValuesPart2(
243
244
245
246
247 ThreadContext.getImmutableContext(),
248
249
250 ThreadContext.getImmutableStack(),
251
252
253 THREAD_NAME_CACHING_STRATEGY.getThreadName(),
254
255
256 calcLocationIfRequested(fqcn),
257
258 eventTimeMillis(message),
259 nanoClock.nanoTime()
260 );
261 }
262
263 private long eventTimeMillis(final Message message) {
264
265
266
267
268
269
270 return message instanceof TimestampMessage ? ((TimestampMessage) message).getTimestamp() : CLOCK
271 .currentTimeMillis();
272 }
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288 private void logWithVarargTranslator(final String fqcn, final Level level, final Marker marker,
289 final Message message, final Throwable thrown) {
290
291
292 final Disruptor<RingBufferLogEvent> disruptor = loggerDisruptor.getDisruptor();
293 if (disruptor == null) {
294 LOGGER.error("Ignoring log event after Log4j has been shut down.");
295 return;
296 }
297
298 disruptor.getRingBuffer().publishEvent(this, this, calcLocationIfRequested(fqcn), fqcn, level, marker, message,
299 thrown);
300 }
301
302
303
304
305
306
307 @Override
308 public void translateTo(final RingBufferLogEvent event, final long sequence, final Object... args) {
309
310 final AsyncLogger asyncLogger = (AsyncLogger) args[0];
311 final StackTraceElement location = (StackTraceElement) args[1];
312 final String fqcn = (String) args[2];
313 final Level level = (Level) args[3];
314 final Marker marker = (Marker) args[4];
315 final Message message = (Message) args[5];
316 final Throwable thrown = (Throwable) args[6];
317
318
319 final Map<String, String> contextMap = ThreadContext.getImmutableContext();
320
321
322 final ContextStack contextStack = ThreadContext.getImmutableStack();
323
324 final String threadName = THREAD_NAME_CACHING_STRATEGY.getThreadName();
325
326 event.setValues(asyncLogger, asyncLogger.getName(), marker, fqcn, level, message, thrown, contextMap,
327 contextStack, threadName, location, eventTimeMillis(message), nanoClock.nanoTime());
328 }
329
330
331
332
333
334
335
336 private StackTraceElement calcLocationIfRequested(String fqcn) {
337
338
339
340 final boolean includeLocation = privateConfig.loggerConfig.isIncludeLocation();
341 return includeLocation ? Log4jLogEvent.calcLocation(fqcn) : null;
342 }
343
344
345
346
347
348
349 public void actualAsyncLog(final RingBufferLogEvent event) {
350 final Map<Property, Boolean> properties = privateConfig.loggerConfig.getProperties();
351 event.mergePropertiesIntoContextMap(properties, privateConfig.config.getStrSubstitutor());
352 final ReliabilityStrategy strategy = privateConfig.loggerConfig.getReliabilityStrategy();
353 strategy.log(this, event);
354 }
355 }