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.message.Message;
36 import org.apache.logging.log4j.message.MessageFactory;
37 import org.apache.logging.log4j.message.ReusableMessage;
38 import org.apache.logging.log4j.status.StatusLogger;
39
40 import com.lmax.disruptor.EventTranslatorVararg;
41 import com.lmax.disruptor.dsl.Disruptor;
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62 public class AsyncLogger extends Logger implements EventTranslatorVararg<RingBufferLogEvent> {
63
64
65
66
67
68 private static final StatusLogger LOGGER = StatusLogger.getLogger();
69 private static final Clock CLOCK = ClockFactory.getClock();
70
71 private static final ThreadNameCachingStrategy THREAD_NAME_CACHING_STRATEGY = ThreadNameCachingStrategy.create();
72
73 private final ThreadLocal<RingBufferLogEventTranslator> threadLocalTranslator = new ThreadLocal<>();
74 private final AsyncLoggerDisruptor loggerDisruptor;
75
76 private volatile boolean includeLocation;
77 private volatile NanoClock nanoClock;
78
79
80
81
82
83
84
85
86
87 public AsyncLogger(final LoggerContext context, final String name, final MessageFactory messageFactory,
88 final AsyncLoggerDisruptor loggerDisruptor) {
89 super(context, name, messageFactory);
90 this.loggerDisruptor = loggerDisruptor;
91 includeLocation = privateConfig.loggerConfig.isIncludeLocation();
92 nanoClock = context.getConfiguration().getNanoClock();
93 }
94
95
96
97
98
99
100 @Override
101 protected void updateConfiguration(Configuration newConfig) {
102 nanoClock = newConfig.getNanoClock();
103 includeLocation = newConfig.getLoggerConfig(name).isIncludeLocation();
104 super.updateConfiguration(newConfig);
105 LOGGER.trace("[{}] AsyncLogger {} uses {}.", getContext().getName(), getName(), nanoClock);
106 }
107
108
109 NanoClock getNanoClock() {
110 return nanoClock;
111 }
112
113 private RingBufferLogEventTranslator getCachedTranslator() {
114 RingBufferLogEventTranslator result = threadLocalTranslator.get();
115 if (result == null) {
116 result = new RingBufferLogEventTranslator();
117 threadLocalTranslator.set(result);
118 }
119 return result;
120 }
121
122 @Override
123 public void logMessage(final String fqcn, final Level level, final Marker marker, final Message message,
124 final Throwable thrown) {
125
126 if (loggerDisruptor.isUseThreadLocals()) {
127 logWithThreadLocalTranslator(fqcn, level, marker, message, thrown);
128 } else {
129
130 logWithVarargTranslator(fqcn, level, marker, message, thrown);
131 }
132 }
133
134 private boolean isReused(final Message message) {
135 return message instanceof ReusableMessage;
136 }
137
138
139
140
141
142
143
144
145
146
147
148
149
150 private void logWithThreadLocalTranslator(final String fqcn, final Level level, final Marker marker,
151 final Message message, final Throwable thrown) {
152
153
154 final RingBufferLogEventTranslator translator = getCachedTranslator();
155 initTranslator(translator, fqcn, level, marker, message, thrown);
156 initTranslatorThreadValues(translator);
157 publish(translator);
158 }
159
160 private void publish(final RingBufferLogEventTranslator translator) {
161 if (!loggerDisruptor.tryPublish(translator)) {
162 handleRingBufferFull(translator);
163 }
164 }
165
166 private void handleRingBufferFull(final RingBufferLogEventTranslator translator) {
167 final EventRoute eventRoute = loggerDisruptor.getEventRoute(translator.level);
168 switch (eventRoute) {
169 case ENQUEUE:
170 loggerDisruptor.enqueueLogMessageInfo(translator);
171 break;
172 case SYNCHRONOUS:
173 logMessageInCurrentThread(translator.fqcn, translator.level, translator.marker, translator.message,
174 translator.thrown);
175 break;
176 case DISCARD:
177 break;
178 default:
179 throw new IllegalStateException("Unknown EventRoute " + eventRoute);
180 }
181 }
182
183 private void initTranslator(final RingBufferLogEventTranslator translator, final String fqcn,
184 final Level level, final Marker marker, final Message message, final Throwable thrown) {
185
186 translator.setBasicValues(this, name, marker, fqcn, level, message,
187
188 thrown,
189
190
191
192
193
194 ThreadContext.getImmutableContext(),
195
196
197 ThreadContext.getImmutableStack(),
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(String fqcn) {
219
220
221
222 return includeLocation ? Log4jLogEvent.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 (!Constants.FORMAT_MESSAGES_IN_BACKGROUND && !isReused(message)) {
248 message.getFormattedMessage();
249 }
250
251 disruptor.getRingBuffer().publishEvent(this, this, calcLocationIfRequested(fqcn), fqcn, level, marker, message,
252 thrown);
253 }
254
255
256
257
258
259
260 @Override
261 public void translateTo(final RingBufferLogEvent event, final long sequence, final Object... args) {
262
263 final AsyncLogger asyncLogger = (AsyncLogger) args[0];
264 final StackTraceElement location = (StackTraceElement) args[1];
265 final String fqcn = (String) args[2];
266 final Level level = (Level) args[3];
267 final Marker marker = (Marker) args[4];
268 final Message message = (Message) args[5];
269 final Throwable thrown = (Throwable) args[6];
270
271
272 final Map<String, String> contextMap = ThreadContext.getImmutableContext();
273
274
275 final ContextStack contextStack = ThreadContext.getImmutableStack();
276
277 final Thread currentThread = Thread.currentThread();
278 final String threadName = THREAD_NAME_CACHING_STRATEGY.getThreadName();
279 event.setValues(asyncLogger, asyncLogger.getName(), marker, fqcn, level, message, thrown, contextMap,
280 contextStack, currentThread.getId(), threadName, currentThread.getPriority(), location,
281 CLOCK.currentTimeMillis(), nanoClock.nanoTime());
282 }
283
284
285
286
287
288
289
290
291
292
293
294 void logMessageInCurrentThread(final String fqcn, final Level level, final Marker marker,
295 final Message message, final Throwable thrown) {
296
297 final ReliabilityStrategy strategy = privateConfig.loggerConfig.getReliabilityStrategy();
298 strategy.log(this, getName(), fqcn, marker, level, message, thrown);
299 }
300
301
302
303
304
305
306 public void actualAsyncLog(final RingBufferLogEvent event) {
307 final Map<Property, Boolean> properties = privateConfig.loggerConfig.getProperties();
308 event.mergePropertiesIntoContextMap(properties, privateConfig.config.getStrSubstitutor());
309 final ReliabilityStrategy strategy = privateConfig.loggerConfig.getReliabilityStrategy();
310 strategy.log(this, event);
311 }
312 }