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.Core;
31 import org.apache.logging.log4j.core.Filter;
32 import org.apache.logging.log4j.core.LogEvent;
33 import org.apache.logging.log4j.core.LoggerContext;
34 import org.apache.logging.log4j.core.async.AsyncLoggerConfig;
35 import org.apache.logging.log4j.core.async.AsyncLoggerContext;
36 import org.apache.logging.log4j.core.async.AsyncLoggerContextSelector;
37 import org.apache.logging.log4j.core.config.plugins.Plugin;
38 import org.apache.logging.log4j.core.config.plugins.PluginAttribute;
39 import org.apache.logging.log4j.core.config.plugins.PluginConfiguration;
40 import org.apache.logging.log4j.core.config.plugins.PluginElement;
41 import org.apache.logging.log4j.core.config.plugins.PluginFactory;
42 import org.apache.logging.log4j.core.config.plugins.validation.constraints.Required;
43 import org.apache.logging.log4j.core.filter.AbstractFilterable;
44 import org.apache.logging.log4j.core.impl.DefaultLogEventFactory;
45 import org.apache.logging.log4j.core.impl.Log4jLogEvent;
46 import org.apache.logging.log4j.core.impl.LogEventFactory;
47 import org.apache.logging.log4j.core.impl.ReusableLogEventFactory;
48 import org.apache.logging.log4j.core.lookup.StrSubstitutor;
49 import org.apache.logging.log4j.core.util.Booleans;
50 import org.apache.logging.log4j.core.util.Constants;
51 import org.apache.logging.log4j.core.util.Loader;
52 import org.apache.logging.log4j.message.Message;
53 import org.apache.logging.log4j.util.PerformanceSensitive;
54 import org.apache.logging.log4j.util.PropertiesUtil;
55 import org.apache.logging.log4j.util.Strings;
56
57
58
59
60 @Plugin(name = "logger", category = Node.CATEGORY, printObject = true)
61 public class LoggerConfig extends AbstractFilterable {
62
63 public static final String ROOT = "root";
64 private static LogEventFactory LOG_EVENT_FACTORY = null;
65
66 private List<AppenderRef> appenderRefs = new ArrayList<>();
67 private final AppenderControlArraySet appenders = new AppenderControlArraySet();
68 private final String name;
69 private LogEventFactory logEventFactory;
70 private Level level;
71 private boolean additive = true;
72 private boolean includeLocation = true;
73 private LoggerConfig parent;
74 private Map<Property, Boolean> propertiesMap;
75 private final List<Property> properties;
76 private final boolean propertiesRequireLookup;
77 private final Configuration config;
78 private final ReliabilityStrategy reliabilityStrategy;
79
80 static {
81 final String factory = PropertiesUtil.getProperties().getStringProperty(Constants.LOG4J_LOG_EVENT_FACTORY);
82 if (factory != null) {
83 try {
84 final Class<?> clazz = Loader.loadClass(factory);
85 if (clazz != null && LogEventFactory.class.isAssignableFrom(clazz)) {
86 LOG_EVENT_FACTORY = (LogEventFactory) clazz.newInstance();
87 }
88 } catch (final Exception ex) {
89 LOGGER.error("Unable to create LogEventFactory {}", factory, ex);
90 }
91 }
92 if (LOG_EVENT_FACTORY == null) {
93 LOG_EVENT_FACTORY = Constants.ENABLE_THREADLOCALS
94 ? new ReusableLogEventFactory()
95 : new DefaultLogEventFactory();
96 }
97 }
98
99
100
101
102 public LoggerConfig() {
103 this.logEventFactory = LOG_EVENT_FACTORY;
104 this.level = Level.ERROR;
105 this.name = Strings.EMPTY;
106 this.properties = null;
107 this.propertiesRequireLookup = false;
108 this.config = null;
109 this.reliabilityStrategy = new DefaultReliabilityStrategy(this);
110 }
111
112
113
114
115
116
117
118
119 public LoggerConfig(final String name, final Level level, final boolean additive) {
120 this.logEventFactory = LOG_EVENT_FACTORY;
121 this.name = name;
122 this.level = level;
123 this.additive = additive;
124 this.properties = null;
125 this.propertiesRequireLookup = false;
126 this.config = null;
127 this.reliabilityStrategy = new DefaultReliabilityStrategy(this);
128 }
129
130 protected LoggerConfig(final String name, final List<AppenderRef> appenders, final Filter filter,
131 final Level level, final boolean additive, final Property[] properties, final Configuration config,
132 final boolean includeLocation) {
133 super(filter);
134 this.logEventFactory = LOG_EVENT_FACTORY;
135 this.name = name;
136 this.appenderRefs = appenders;
137 this.level = level;
138 this.additive = additive;
139 this.includeLocation = includeLocation;
140 this.config = config;
141 if (properties != null && properties.length > 0) {
142 this.properties = Collections.unmodifiableList(Arrays.asList(Arrays.copyOf(
143 properties, properties.length)));
144 } else {
145 this.properties = null;
146 }
147 this.propertiesRequireLookup = containsPropertyRequiringLookup(properties);
148 this.reliabilityStrategy = config.getReliabilityStrategy(this);
149 }
150
151 private static boolean containsPropertyRequiringLookup(final Property[] properties) {
152 if (properties == null) {
153 return false;
154 }
155 for (int i = 0; i < properties.length; i++) {
156 if (properties[i].isValueNeedsLookup()) {
157 return true;
158 }
159 }
160 return false;
161 }
162
163 @Override
164 public Filter getFilter() {
165 return super.getFilter();
166 }
167
168
169
170
171
172
173 public String getName() {
174 return name;
175 }
176
177
178
179
180
181
182 public void setParent(final LoggerConfig parent) {
183 this.parent = parent;
184 }
185
186
187
188
189
190
191 public LoggerConfig getParent() {
192 return this.parent;
193 }
194
195
196
197
198
199
200
201
202 public void addAppender(final Appender appender, final Level level, final Filter filter) {
203 appenders.add(new AppenderControl(appender, level, filter));
204 }
205
206
207
208
209
210
211 public void removeAppender(final String name) {
212 AppenderControl removed = null;
213 while ((removed = appenders.remove(name)) != null) {
214 cleanupFilter(removed);
215 }
216 }
217
218
219
220
221
222
223 public Map<String, Appender> getAppenders() {
224 return appenders.asMap();
225 }
226
227
228
229
230 protected void clearAppenders() {
231 do {
232 final AppenderControl[] original = appenders.clear();
233 for (final AppenderControl ctl : original) {
234 cleanupFilter(ctl);
235 }
236 } while (!appenders.isEmpty());
237 }
238
239 private void cleanupFilter(final AppenderControl ctl) {
240 final Filter filter = ctl.getFilter();
241 if (filter != null) {
242 ctl.removeFilter(filter);
243 filter.stop();
244 }
245 }
246
247
248
249
250
251
252 public List<AppenderRef> getAppenderRefs() {
253 return appenderRefs;
254 }
255
256
257
258
259
260
261 public void setLevel(final Level level) {
262 this.level = level;
263 }
264
265
266
267
268
269
270 public Level getLevel() {
271 return level == null ? parent == null ? Level.ERROR : parent.getLevel() : level;
272 }
273
274
275
276
277
278
279 public LogEventFactory getLogEventFactory() {
280 return logEventFactory;
281 }
282
283
284
285
286
287
288 public void setLogEventFactory(final LogEventFactory logEventFactory) {
289 this.logEventFactory = logEventFactory;
290 }
291
292
293
294
295
296
297 public boolean isAdditive() {
298 return additive;
299 }
300
301
302
303
304
305
306 public void setAdditive(final boolean additive) {
307 this.additive = additive;
308 }
309
310
311
312
313
314
315
316 public boolean isIncludeLocation() {
317 return includeLocation;
318 }
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333 @Deprecated
334 public Map<Property, Boolean> getProperties() {
335 if (properties == null) {
336 return null;
337 }
338 if (propertiesMap == null) {
339 final Map<Property, Boolean> result = new HashMap<>(properties.size() * 2);
340 for (int i = 0; i < properties.size(); i++) {
341 result.put(properties.get(i), Boolean.valueOf(properties.get(i).isValueNeedsLookup()));
342 }
343 propertiesMap = Collections.unmodifiableMap(result);
344 }
345 return propertiesMap;
346 }
347
348
349
350
351
352
353
354
355
356
357
358
359
360 public List<Property> getPropertyList() {
361 return properties;
362 }
363
364 public boolean isPropertiesRequireLookup() {
365 return propertiesRequireLookup;
366 }
367
368
369
370
371
372
373
374
375
376
377
378 @PerformanceSensitive("allocation")
379 public void log(final String loggerName, final String fqcn, final Marker marker, final Level level,
380 final Message data, final Throwable t) {
381 List<Property> props = null;
382 if (!propertiesRequireLookup) {
383 props = properties;
384 } else {
385 if (properties != null) {
386 props = new ArrayList<>(properties.size());
387 final LogEvent event = Log4jLogEvent.newBuilder()
388 .setMessage(data)
389 .setMarker(marker)
390 .setLevel(level)
391 .setLoggerName(loggerName)
392 .setLoggerFqcn(fqcn)
393 .setThrown(t)
394 .build();
395 for (int i = 0; i < properties.size(); i++) {
396 final Property prop = properties.get(i);
397 final String value = prop.isValueNeedsLookup()
398 ? config.getStrSubstitutor().replace(event, prop.getValue())
399 : prop.getValue();
400 props.add(Property.createProperty(prop.getName(), value));
401 }
402 }
403 }
404 final LogEvent logEvent = logEventFactory.createEvent(loggerName, marker, fqcn, level, data, props, t);
405 try {
406 log(logEvent, LoggerConfigPredicate.ALL);
407 } finally {
408
409 ReusableLogEventFactory.release(logEvent);
410 }
411 }
412
413
414
415
416
417
418 public void log(final LogEvent event) {
419 log(event, LoggerConfigPredicate.ALL);
420 }
421
422
423
424
425
426
427
428
429 protected void log(final LogEvent event, final LoggerConfigPredicate predicate) {
430 if (!isFiltered(event)) {
431 processLogEvent(event, predicate);
432 }
433 }
434
435
436
437
438
439
440
441 public ReliabilityStrategy getReliabilityStrategy() {
442 return reliabilityStrategy;
443 }
444
445 private void processLogEvent(final LogEvent event, final LoggerConfigPredicate predicate) {
446 event.setIncludeLocation(isIncludeLocation());
447 if (predicate.allow(this)) {
448 callAppenders(event);
449 }
450 logParent(event, predicate);
451 }
452
453 private void logParent(final LogEvent event, final LoggerConfigPredicate predicate) {
454 if (additive && parent != null) {
455 parent.log(event, predicate);
456 }
457 }
458
459 @PerformanceSensitive("allocation")
460 protected void callAppenders(final LogEvent event) {
461 final AppenderControl[] controls = appenders.get();
462
463 for (int i = 0; i < controls.length; i++) {
464 controls[i].callAppender(event);
465 }
466 }
467
468 @Override
469 public String toString() {
470 return Strings.isEmpty(name) ? ROOT : name;
471 }
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487 @Deprecated
488 public static LoggerConfig createLogger(final String additivity,
489
490 final Level level,
491 @PluginAttribute("name") final String loggerName,
492 final String includeLocation,
493 final AppenderRef[] refs,
494 final Property[] properties,
495 @PluginConfiguration final Configuration config,
496 final Filter filter) {
497
498 if (loggerName == null) {
499 LOGGER.error("Loggers cannot be configured without a name");
500 return null;
501 }
502
503 final List<AppenderRef> appenderRefs = Arrays.asList(refs);
504 final String name = loggerName.equals(ROOT) ? Strings.EMPTY : loggerName;
505 final boolean additive = Booleans.parseBoolean(additivity, true);
506
507 return new LoggerConfig(name, appenderRefs, filter, level, additive, properties, config,
508 includeLocation(includeLocation, config));
509 }
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525 @PluginFactory
526 public static LoggerConfig createLogger(
527
528 @PluginAttribute(value = "additivity", defaultBoolean = true) final boolean additivity,
529 @PluginAttribute("level") final Level level,
530 @Required(message = "Loggers cannot be configured without a name") @PluginAttribute("name") final String loggerName,
531 @PluginAttribute("includeLocation") final String includeLocation,
532 @PluginElement("AppenderRef") final AppenderRef[] refs,
533 @PluginElement("Properties") final Property[] properties,
534 @PluginConfiguration final Configuration config,
535 @PluginElement("Filter") final Filter filter
536
537 ) {
538 final String name = loggerName.equals(ROOT) ? Strings.EMPTY : loggerName;
539 return new LoggerConfig(name, Arrays.asList(refs), filter, level, additivity, properties, config,
540 includeLocation(includeLocation, config));
541 }
542
543
544
545
546 @Deprecated
547 protected static boolean includeLocation(final String includeLocationConfigValue) {
548 return includeLocation(includeLocationConfigValue, null);
549 }
550
551
552
553 protected static boolean includeLocation(final String includeLocationConfigValue, final Configuration configuration) {
554 if (includeLocationConfigValue == null) {
555 LoggerContext context = null;
556 if (configuration != null) {
557 context = configuration.getLoggerContext();
558 }
559 if (context != null) {
560 return !(context instanceof AsyncLoggerContext);
561 } else {
562 return !AsyncLoggerContextSelector.isSelected();
563 }
564 }
565 return Boolean.parseBoolean(includeLocationConfigValue);
566 }
567
568 protected final boolean hasAppenders() {
569 return !appenders.isEmpty();
570 }
571
572
573
574
575 @Plugin(name = ROOT, category = Core.CATEGORY_NAME, printObject = true)
576 public static class RootLogger extends LoggerConfig {
577
578 @PluginFactory
579 public static LoggerConfig createLogger(
580
581 @PluginAttribute("additivity") final String additivity,
582 @PluginAttribute("level") final Level level,
583 @PluginAttribute("includeLocation") final String includeLocation,
584 @PluginElement("AppenderRef") final AppenderRef[] refs,
585 @PluginElement("Properties") final Property[] properties,
586 @PluginConfiguration final Configuration config,
587 @PluginElement("Filter") final Filter filter) {
588
589 final List<AppenderRef> appenderRefs = Arrays.asList(refs);
590 final Level actualLevel = level == null ? Level.ERROR : level;
591 final boolean additive = Booleans.parseBoolean(additivity, true);
592
593 return new LoggerConfig(LogManager.ROOT_LOGGER_NAME, appenderRefs, filter, actualLevel, additive,
594 properties, config, includeLocation(includeLocation, config));
595 }
596 }
597
598 protected enum LoggerConfigPredicate {
599 ALL() {
600 @Override
601 boolean allow(final LoggerConfig config) {
602 return true;
603 }
604 },
605 ASYNCHRONOUS_ONLY() {
606 @Override
607 boolean allow(final LoggerConfig config) {
608 return config instanceof AsyncLoggerConfig;
609 }
610 },
611 SYNCHRONOUS_ONLY() {
612 @Override
613 boolean allow(final LoggerConfig config) {
614 return !ASYNCHRONOUS_ONLY.allow(config);
615 }
616 };
617
618 abstract boolean allow(LoggerConfig config);
619 }
620 }