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