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