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