1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.apache.logging.log4j.core.config;
18
19 import java.util.ArrayList;
20 import java.util.Arrays;
21 import java.util.Collections;
22 import java.util.HashMap;
23 import java.util.List;
24 import java.util.Map;
25
26 import org.apache.logging.log4j.Level;
27 import org.apache.logging.log4j.LogManager;
28 import org.apache.logging.log4j.Marker;
29 import org.apache.logging.log4j.core.Appender;
30 import org.apache.logging.log4j.core.Filter;
31 import org.apache.logging.log4j.core.LogEvent;
32 import org.apache.logging.log4j.core.async.AsyncLoggerContextSelector;
33 import org.apache.logging.log4j.core.config.plugins.Plugin;
34 import org.apache.logging.log4j.core.config.plugins.PluginAttribute;
35 import org.apache.logging.log4j.core.config.plugins.PluginConfiguration;
36 import org.apache.logging.log4j.core.config.plugins.PluginElement;
37 import org.apache.logging.log4j.core.config.plugins.PluginFactory;
38 import org.apache.logging.log4j.core.config.plugins.validation.constraints.Required;
39 import org.apache.logging.log4j.core.filter.AbstractFilterable;
40 import org.apache.logging.log4j.core.impl.DefaultLogEventFactory;
41 import org.apache.logging.log4j.core.impl.Log4jLogEvent;
42 import org.apache.logging.log4j.core.impl.LogEventFactory;
43 import org.apache.logging.log4j.core.impl.ReusableLogEventFactory;
44 import org.apache.logging.log4j.core.lookup.StrSubstitutor;
45 import org.apache.logging.log4j.core.util.Booleans;
46 import org.apache.logging.log4j.core.util.Constants;
47 import org.apache.logging.log4j.core.util.Loader;
48 import org.apache.logging.log4j.message.Message;
49 import org.apache.logging.log4j.util.PerformanceSensitive;
50 import org.apache.logging.log4j.util.PropertiesUtil;
51 import org.apache.logging.log4j.util.Strings;
52
53
54
55
56 @Plugin(name = "logger", category = Node.CATEGORY, printObject = true)
57 public class LoggerConfig extends AbstractFilterable {
58
59 public static final String ROOT = "root";
60 private static LogEventFactory LOG_EVENT_FACTORY = null;
61
62 private List<AppenderRef> appenderRefs = new ArrayList<>();
63 private final AppenderControlArraySet appenders = new AppenderControlArraySet();
64 private final String name;
65 private LogEventFactory logEventFactory;
66 private Level level;
67 private boolean additive = true;
68 private boolean includeLocation = true;
69 private LoggerConfig parent;
70 private final Map<Property, Boolean> properties;
71 private final Configuration config;
72 private final ReliabilityStrategy reliabilityStrategy;
73
74 static {
75 final String factory = PropertiesUtil.getProperties().getStringProperty(Constants.LOG4J_LOG_EVENT_FACTORY);
76 if (factory != null) {
77 try {
78 final Class<?> clazz = Loader.loadClass(factory);
79 if (clazz != null && LogEventFactory.class.isAssignableFrom(clazz)) {
80 LOG_EVENT_FACTORY = (LogEventFactory) clazz.newInstance();
81 }
82 } catch (final Exception ex) {
83 LOGGER.error("Unable to create LogEventFactory {}", factory, ex);
84 }
85 }
86 if (LOG_EVENT_FACTORY == null) {
87 LOG_EVENT_FACTORY = Constants.ENABLE_THREADLOCALS
88 ? new ReusableLogEventFactory()
89 : new DefaultLogEventFactory();
90 }
91 }
92
93
94
95
96 public LoggerConfig() {
97 this.logEventFactory = LOG_EVENT_FACTORY;
98 this.level = Level.ERROR;
99 this.name = Strings.EMPTY;
100 this.properties = null;
101 this.config = null;
102 this.reliabilityStrategy = new DefaultReliabilityStrategy(this);
103 }
104
105
106
107
108
109
110
111
112 public LoggerConfig(final String name, final Level level, final boolean additive) {
113 this.logEventFactory = LOG_EVENT_FACTORY;
114 this.name = name;
115 this.level = level;
116 this.additive = additive;
117 this.properties = null;
118 this.config = null;
119 this.reliabilityStrategy = new DefaultReliabilityStrategy(this);
120 }
121
122 protected LoggerConfig(final String name, final List<AppenderRef> appenders, final Filter filter,
123 final Level level, final boolean additive, final Property[] properties, final Configuration config,
124 final boolean includeLocation) {
125 super(filter);
126 this.logEventFactory = LOG_EVENT_FACTORY;
127 this.name = name;
128 this.appenderRefs = appenders;
129 this.level = level;
130 this.additive = additive;
131 this.includeLocation = includeLocation;
132 this.config = config;
133 if (properties != null && properties.length > 0) {
134 final Map<Property, Boolean> map = new HashMap<>(properties.length);
135 for (final Property prop : properties) {
136 final boolean interpolate = prop.getValue().contains("${");
137 map.put(prop, interpolate);
138 }
139 this.properties = Collections.unmodifiableMap(map);
140 } else {
141 this.properties = null;
142 }
143 this.reliabilityStrategy = config.getReliabilityStrategy(this);
144 }
145
146 @Override
147 public Filter getFilter() {
148 return super.getFilter();
149 }
150
151
152
153
154
155
156 public String getName() {
157 return name;
158 }
159
160
161
162
163
164
165 public void setParent(final LoggerConfig parent) {
166 this.parent = parent;
167 }
168
169
170
171
172
173
174 public LoggerConfig getParent() {
175 return this.parent;
176 }
177
178
179
180
181
182
183
184
185 public void addAppender(final Appender appender, final Level level, final Filter filter) {
186 appenders.add(new AppenderControl(appender, level, filter));
187 }
188
189
190
191
192
193
194 public void removeAppender(final String name) {
195 AppenderControl removed = null;
196 while ((removed = appenders.remove(name)) != null) {
197 cleanupFilter(removed);
198 }
199 }
200
201
202
203
204
205
206 public Map<String, Appender> getAppenders() {
207 return appenders.asMap();
208 }
209
210
211
212
213 protected void clearAppenders() {
214 do {
215 final AppenderControl[] original = appenders.clear();
216 for (final AppenderControl ctl : original) {
217 cleanupFilter(ctl);
218 }
219 } while (!appenders.isEmpty());
220 }
221
222 private void cleanupFilter(final AppenderControl ctl) {
223 final Filter filter = ctl.getFilter();
224 if (filter != null) {
225 ctl.removeFilter(filter);
226 filter.stop();
227 }
228 }
229
230
231
232
233
234
235 public List<AppenderRef> getAppenderRefs() {
236 return appenderRefs;
237 }
238
239
240
241
242
243
244 public void setLevel(final Level level) {
245 this.level = level;
246 }
247
248
249
250
251
252
253 public Level getLevel() {
254 return level == null ? parent.getLevel() : level;
255 }
256
257
258
259
260
261
262 public LogEventFactory getLogEventFactory() {
263 return logEventFactory;
264 }
265
266
267
268
269
270
271 public void setLogEventFactory(final LogEventFactory logEventFactory) {
272 this.logEventFactory = logEventFactory;
273 }
274
275
276
277
278
279
280 public boolean isAdditive() {
281 return additive;
282 }
283
284
285
286
287
288
289 public void setAdditive(final boolean additive) {
290 this.additive = additive;
291 }
292
293
294
295
296
297
298
299 public boolean isIncludeLocation() {
300 return includeLocation;
301 }
302
303
304
305
306
307
308
309
310
311
312
313
314
315 public Map<Property, Boolean> getProperties() {
316 return properties;
317 }
318
319
320
321
322
323
324
325
326
327
328
329 public void log(final String loggerName, final String fqcn, final Marker marker, final Level level,
330 final Message data, final Throwable t) {
331 List<Property> props = null;
332 if (properties != null) {
333 props = new ArrayList<>(properties.size());
334 final LogEvent event = Log4jLogEvent.newBuilder()
335 .setMessage(data)
336 .setMarker(marker)
337 .setLevel(level)
338 .setLoggerName(loggerName)
339 .setLoggerFqcn(fqcn)
340 .setThrown(t)
341 .build();
342 for (final Map.Entry<Property, Boolean> entry : properties.entrySet()) {
343 final Property prop = entry.getKey();
344 final String value = entry.getValue() ? config.getStrSubstitutor().replace(event, prop.getValue())
345 : prop.getValue();
346 props.add(Property.createProperty(prop.getName(), value));
347 }
348 }
349 log(logEventFactory.createEvent(loggerName, marker, fqcn, level, data, props, t));
350 }
351
352
353
354
355
356
357 public void log(final LogEvent event) {
358 if (!isFiltered(event)) {
359 processLogEvent(event);
360 }
361 }
362
363
364
365
366
367
368
369 public ReliabilityStrategy getReliabilityStrategy() {
370 return reliabilityStrategy;
371 }
372
373 private void processLogEvent(final LogEvent event) {
374 event.setIncludeLocation(isIncludeLocation());
375 callAppenders(event);
376 logParent(event);
377 }
378
379 private void logParent(final LogEvent event) {
380 if (additive && parent != null) {
381 parent.log(event);
382 }
383 }
384
385 @PerformanceSensitive("allocation")
386 protected void callAppenders(final LogEvent event) {
387 final AppenderControl[] controls = appenders.get();
388
389 for (int i = 0; i < controls.length; i++) {
390 controls[i].callAppender(event);
391 }
392 }
393
394 @Override
395 public String toString() {
396 return Strings.isEmpty(name) ? ROOT : name;
397 }
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413 @Deprecated
414 public static LoggerConfig createLogger(@PluginAttribute("additivity") final String additivity,
415 @PluginAttribute("level") final Level level, @PluginAttribute("name") final String loggerName,
416 @PluginAttribute("includeLocation") final String includeLocation,
417 @PluginElement("AppenderRef") final AppenderRef[] refs,
418 @PluginElement("Properties") final Property[] properties, @PluginConfiguration final Configuration config,
419 @PluginElement("Filter") final Filter filter) {
420 if (loggerName == null) {
421 LOGGER.error("Loggers cannot be configured without a name");
422 return null;
423 }
424
425 final List<AppenderRef> appenderRefs = Arrays.asList(refs);
426 final String name = loggerName.equals(ROOT) ? Strings.EMPTY : loggerName;
427 final boolean additive = Booleans.parseBoolean(additivity, true);
428
429 return new LoggerConfig(name, appenderRefs, filter, level, additive, properties, config,
430 includeLocation(includeLocation));
431 }
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447 @PluginFactory
448 public static LoggerConfig createLogger(
449 @PluginAttribute(value = "additivity", defaultBoolean = true) final boolean additivity,
450 @PluginAttribute("level") final Level level,
451 @Required(message = "Loggers cannot be configured without a name") @PluginAttribute("name") final String loggerName,
452 @PluginAttribute("includeLocation") final String includeLocation,
453 @PluginElement("AppenderRef") final AppenderRef[] refs,
454 @PluginElement("Properties") final Property[] properties,
455 @PluginConfiguration final Configuration config,
456 @PluginElement("Filter") final Filter filter
457 ) {
458 final String name = loggerName.equals(ROOT) ? Strings.EMPTY : loggerName;
459 return new LoggerConfig(name, Arrays.asList(refs), filter, level, additivity, properties, config,
460 includeLocation(includeLocation));
461 }
462
463
464
465 protected static boolean includeLocation(final String includeLocationConfigValue) {
466 if (includeLocationConfigValue == null) {
467 final boolean sync = !AsyncLoggerContextSelector.isSelected();
468 return sync;
469 }
470 return Boolean.parseBoolean(includeLocationConfigValue);
471 }
472
473
474
475
476 @Plugin(name = ROOT, category = "Core", printObject = true)
477 public static class RootLogger extends LoggerConfig {
478
479 @PluginFactory
480 public static LoggerConfig createLogger(
481
482 @PluginAttribute("additivity") final String additivity,
483 @PluginAttribute("level") final Level level,
484 @PluginAttribute("includeLocation") final String includeLocation,
485 @PluginElement("AppenderRef") final AppenderRef[] refs,
486 @PluginElement("Properties") final Property[] properties,
487 @PluginConfiguration final Configuration config,
488 @PluginElement("Filter") final Filter filter) {
489
490 final List<AppenderRef> appenderRefs = Arrays.asList(refs);
491 final Level actualLevel = level == null ? Level.ERROR : level;
492 final boolean additive = Booleans.parseBoolean(additivity, true);
493
494 return new LoggerConfig(LogManager.ROOT_LOGGER_NAME, appenderRefs, filter, actualLevel, additive,
495 properties, config, includeLocation(includeLocation));
496 }
497 }
498
499 }