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.io.ByteArrayOutputStream;
20 import java.io.IOException;
21 import java.io.InputStream;
22 import java.io.Serializable;
23 import java.lang.ref.WeakReference;
24 import java.util.ArrayList;
25 import java.util.Arrays;
26 import java.util.Collection;
27 import java.util.Collections;
28 import java.util.HashSet;
29 import java.util.LinkedHashMap;
30 import java.util.List;
31 import java.util.Map;
32 import java.util.Objects;
33 import java.util.Set;
34 import java.util.concurrent.ConcurrentHashMap;
35 import java.util.concurrent.ConcurrentMap;
36 import java.util.concurrent.CopyOnWriteArrayList;
37 import java.util.concurrent.TimeUnit;
38
39 import org.apache.logging.log4j.Level;
40 import org.apache.logging.log4j.core.Appender;
41 import org.apache.logging.log4j.core.Filter;
42 import org.apache.logging.log4j.core.Layout;
43 import org.apache.logging.log4j.core.LifeCycle2;
44 import org.apache.logging.log4j.core.LogEvent;
45 import org.apache.logging.log4j.core.LoggerContext;
46 import org.apache.logging.log4j.core.Version;
47 import org.apache.logging.log4j.core.appender.AsyncAppender;
48 import org.apache.logging.log4j.core.appender.ConsoleAppender;
49 import org.apache.logging.log4j.core.async.AsyncLoggerConfig;
50 import org.apache.logging.log4j.core.async.AsyncLoggerConfigDelegate;
51 import org.apache.logging.log4j.core.async.AsyncLoggerConfigDisruptor;
52 import org.apache.logging.log4j.core.config.plugins.util.PluginBuilder;
53 import org.apache.logging.log4j.core.config.plugins.util.PluginManager;
54 import org.apache.logging.log4j.core.config.plugins.util.PluginType;
55 import org.apache.logging.log4j.core.filter.AbstractFilterable;
56 import org.apache.logging.log4j.core.layout.PatternLayout;
57 import org.apache.logging.log4j.core.lookup.Interpolator;
58 import org.apache.logging.log4j.core.lookup.MapLookup;
59 import org.apache.logging.log4j.core.lookup.StrLookup;
60 import org.apache.logging.log4j.core.lookup.StrSubstitutor;
61 import org.apache.logging.log4j.core.net.Advertiser;
62 import org.apache.logging.log4j.core.script.AbstractScript;
63 import org.apache.logging.log4j.core.script.ScriptManager;
64 import org.apache.logging.log4j.core.script.ScriptRef;
65 import org.apache.logging.log4j.core.util.Constants;
66 import org.apache.logging.log4j.core.util.DummyNanoClock;
67 import org.apache.logging.log4j.core.util.Loader;
68 import org.apache.logging.log4j.core.util.NameUtil;
69 import org.apache.logging.log4j.core.util.NanoClock;
70 import org.apache.logging.log4j.core.util.Source;
71 import org.apache.logging.log4j.core.util.WatchManager;
72 import org.apache.logging.log4j.core.util.Watcher;
73 import org.apache.logging.log4j.core.util.WatcherFactory;
74 import org.apache.logging.log4j.util.PropertiesUtil;
75
76
77
78
79 public abstract class AbstractConfiguration extends AbstractFilterable implements Configuration {
80
81 private static final int BUF_SIZE = 16384;
82
83
84
85
86 protected Node rootNode;
87
88
89
90
91 protected final List<ConfigurationListener> listeners = new CopyOnWriteArrayList<>();
92
93
94
95
96 protected final List<String> pluginPackages = new ArrayList<>();
97
98
99
100
101 protected PluginManager pluginManager;
102
103
104
105
106 protected boolean isShutdownHookEnabled = true;
107
108
109
110
111 protected long shutdownTimeoutMillis = 0;
112
113
114
115
116 protected ScriptManager scriptManager;
117
118
119
120
121 private Advertiser advertiser = new DefaultAdvertiser();
122 private Node advertiserNode = null;
123 private Object advertisement;
124 private String name;
125 private ConcurrentMap<String, Appender> appenders = new ConcurrentHashMap<>();
126 private ConcurrentMap<String, LoggerConfig> loggerConfigs = new ConcurrentHashMap<>();
127 private List<CustomLevelConfig> customLevels = Collections.emptyList();
128 private final ConcurrentMap<String, String> propertyMap = new ConcurrentHashMap<>();
129 private final StrLookup tempLookup = new Interpolator(propertyMap);
130 private final StrSubstitutor subst = new StrSubstitutor(tempLookup);
131 private LoggerConfig root = new LoggerConfig();
132 private final ConcurrentMap<String, Object> componentMap = new ConcurrentHashMap<>();
133 private final ConfigurationSource configurationSource;
134 private final ConfigurationScheduler configurationScheduler = new ConfigurationScheduler();
135 private final WatchManager watchManager = new WatchManager(configurationScheduler);
136 private AsyncLoggerConfigDisruptor asyncLoggerConfigDisruptor;
137 private NanoClock nanoClock = new DummyNanoClock();
138 private final WeakReference<LoggerContext> loggerContext;
139
140
141
142
143 protected AbstractConfiguration(final LoggerContext loggerContext, final ConfigurationSource configurationSource) {
144 this.loggerContext = new WeakReference<>(loggerContext);
145
146
147 this.configurationSource = Objects.requireNonNull(configurationSource, "configurationSource is null");
148 componentMap.put(Configuration.CONTEXT_PROPERTIES, propertyMap);
149 pluginManager = new PluginManager(Node.CATEGORY);
150 rootNode = new Node();
151 setState(State.INITIALIZING);
152
153 }
154
155 @Override
156 public ConfigurationSource getConfigurationSource() {
157 return configurationSource;
158 }
159
160 @Override
161 public List<String> getPluginPackages() {
162 return pluginPackages;
163 }
164
165 @Override
166 public Map<String, String> getProperties() {
167 return propertyMap;
168 }
169
170 @Override
171 public ScriptManager getScriptManager() {
172 return scriptManager;
173 }
174
175 public void setScriptManager(final ScriptManager scriptManager) {
176 this.scriptManager = scriptManager;
177 }
178
179 public PluginManager getPluginManager() {
180 return pluginManager;
181 }
182
183 public void setPluginManager(final PluginManager pluginManager) {
184 this.pluginManager = pluginManager;
185 }
186
187 @Override
188 public WatchManager getWatchManager() {
189 return watchManager;
190 }
191
192 @Override
193 public ConfigurationScheduler getScheduler() {
194 return configurationScheduler;
195 }
196
197 public Node getRootNode() {
198 return rootNode;
199 }
200
201 @Override
202 public AsyncLoggerConfigDelegate getAsyncLoggerConfigDelegate() {
203
204
205 if (asyncLoggerConfigDisruptor == null) {
206 asyncLoggerConfigDisruptor = new AsyncLoggerConfigDisruptor();
207 }
208 return asyncLoggerConfigDisruptor;
209 }
210
211
212
213
214 @Override
215 public void initialize() {
216 LOGGER.debug(Version.getProductString() + " initializing configuration {}", this);
217 subst.setConfiguration(this);
218 try {
219 scriptManager = new ScriptManager(this, watchManager);
220 } catch (final LinkageError | Exception e) {
221
222 LOGGER.info("Cannot initialize scripting support because this JRE does not support it.", e);
223 }
224 pluginManager.collectPlugins(pluginPackages);
225 final PluginManager levelPlugins = new PluginManager(Level.CATEGORY);
226 levelPlugins.collectPlugins(pluginPackages);
227 final Map<String, PluginType<?>> plugins = levelPlugins.getPlugins();
228 if (plugins != null) {
229 for (final PluginType<?> type : plugins.values()) {
230 try {
231
232 Loader.initializeClass(type.getPluginClass().getName(), type.getPluginClass().getClassLoader());
233 } catch (final Exception e) {
234 LOGGER.error("Unable to initialize {} due to {}", type.getPluginClass().getName(), e.getClass()
235 .getSimpleName(), e);
236 }
237 }
238 }
239 setup();
240 setupAdvertisement();
241 doConfigure();
242 setState(State.INITIALIZED);
243 LOGGER.debug("Configuration {} initialized", this);
244 }
245
246 protected void initializeWatchers(Reconfigurable reconfigurable, ConfigurationSource configSource,
247 int monitorIntervalSeconds) {
248 if (configSource.getFile() != null || configSource.getURL() != null) {
249 if (monitorIntervalSeconds > 0) {
250 watchManager.setIntervalSeconds(monitorIntervalSeconds);
251 if (configSource.getFile() != null) {
252 final Source cfgSource = new Source(configSource);
253 final long lastModifeid = configSource.getFile().lastModified();
254 final ConfigurationFileWatcher watcher = new ConfigurationFileWatcher(this, reconfigurable,
255 listeners, lastModifeid);
256 watchManager.watch(cfgSource, watcher);
257 } else {
258 if (configSource.getURL() != null) {
259 monitorSource(reconfigurable, configSource);
260 }
261 }
262 } else if (watchManager.hasEventListeners() && configSource.getURL() != null && monitorIntervalSeconds >= 0) {
263 monitorSource(reconfigurable, configSource);
264 }
265 }
266 }
267
268 private void monitorSource(Reconfigurable reconfigurable, ConfigurationSource configSource) {
269 if (configSource.getLastModified() > 0) {
270 final Source cfgSource = new Source(configSource);
271 final Watcher watcher = WatcherFactory.getInstance(pluginPackages)
272 .newWatcher(cfgSource, this, reconfigurable, listeners, configSource.getLastModified());
273 if (watcher != null) {
274 watchManager.watch(cfgSource, watcher);
275 }
276 } else {
277 LOGGER.info("{} does not support dynamic reconfiguration", configSource.getURI());
278 }
279 }
280
281
282
283
284 @Override
285 public void start() {
286
287 if (getState().equals(State.INITIALIZING)) {
288 initialize();
289 }
290 LOGGER.debug("Starting configuration {}", this);
291 this.setStarting();
292 if (watchManager.getIntervalSeconds() >= 0) {
293 watchManager.start();
294 }
295 if (hasAsyncLoggers()) {
296 asyncLoggerConfigDisruptor.start();
297 }
298 final Set<LoggerConfig> alreadyStarted = new HashSet<>();
299 for (final LoggerConfig logger : loggerConfigs.values()) {
300 logger.start();
301 alreadyStarted.add(logger);
302 }
303 for (final Appender appender : appenders.values()) {
304 appender.start();
305 }
306 if (!alreadyStarted.contains(root)) {
307 root.start();
308 }
309 super.start();
310 LOGGER.debug("Started configuration {} OK.", this);
311 }
312
313 private boolean hasAsyncLoggers() {
314 if (root instanceof AsyncLoggerConfig) {
315 return true;
316 }
317 for (final LoggerConfig logger : loggerConfigs.values()) {
318 if (logger instanceof AsyncLoggerConfig) {
319 return true;
320 }
321 }
322 return false;
323 }
324
325
326
327
328 @Override
329 public boolean stop(final long timeout, final TimeUnit timeUnit) {
330 this.setStopping();
331 super.stop(timeout, timeUnit, false);
332 LOGGER.trace("Stopping {}...", this);
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347 for (final LoggerConfig loggerConfig : loggerConfigs.values()) {
348 loggerConfig.getReliabilityStrategy().beforeStopConfiguration(this);
349 }
350 root.getReliabilityStrategy().beforeStopConfiguration(this);
351
352 final String cls = getClass().getSimpleName();
353 LOGGER.trace("{} notified {} ReliabilityStrategies that config will be stopped.", cls, loggerConfigs.size()
354 + 1);
355
356 if (!loggerConfigs.isEmpty()) {
357 LOGGER.trace("{} stopping {} LoggerConfigs.", cls, loggerConfigs.size());
358 for (final LoggerConfig logger : loggerConfigs.values()) {
359 logger.stop(timeout, timeUnit);
360 }
361 }
362 LOGGER.trace("{} stopping root LoggerConfig.", cls);
363 if (!root.isStopped()) {
364 root.stop(timeout, timeUnit);
365 }
366
367 if (hasAsyncLoggers()) {
368 LOGGER.trace("{} stopping AsyncLoggerConfigDisruptor.", cls);
369 asyncLoggerConfigDisruptor.stop(timeout, timeUnit);
370 }
371
372
373 final Appender[] array = appenders.values().toArray(new Appender[appenders.size()]);
374 final List<Appender> async = getAsyncAppenders(array);
375 if (!async.isEmpty()) {
376
377 LOGGER.trace("{} stopping {} AsyncAppenders.", cls, async.size());
378 for (final Appender appender : async) {
379 if (appender instanceof LifeCycle2) {
380 ((LifeCycle2) appender).stop(timeout, timeUnit);
381 } else {
382 appender.stop();
383 }
384 }
385 }
386
387 LOGGER.trace("{} notifying ReliabilityStrategies that appenders will be stopped.", cls);
388 for (final LoggerConfig loggerConfig : loggerConfigs.values()) {
389 loggerConfig.getReliabilityStrategy().beforeStopAppenders();
390 }
391 root.getReliabilityStrategy().beforeStopAppenders();
392
393 LOGGER.trace("{} stopping remaining Appenders.", cls);
394 int appenderCount = 0;
395 for (int i = array.length - 1; i >= 0; --i) {
396 if (array[i].isStarted()) {
397 if (array[i] instanceof LifeCycle2) {
398 ((LifeCycle2) array[i]).stop(timeout, timeUnit);
399 } else {
400 array[i].stop();
401 }
402 appenderCount++;
403 }
404 }
405 LOGGER.trace("{} stopped {} remaining Appenders.", cls, appenderCount);
406
407 LOGGER.trace("{} cleaning Appenders from {} LoggerConfigs.", cls, loggerConfigs.size() + 1);
408 for (final LoggerConfig loggerConfig : loggerConfigs.values()) {
409
410
411
412
413
414
415 loggerConfig.clearAppenders();
416 }
417 root.clearAppenders();
418
419 if (watchManager.isStarted()) {
420 watchManager.stop(timeout, timeUnit);
421 }
422 configurationScheduler.stop(timeout, timeUnit);
423
424 if (advertiser != null && advertisement != null) {
425 advertiser.unadvertise(advertisement);
426 }
427 setStopped();
428 LOGGER.debug("Stopped {} OK", this);
429 return true;
430 }
431
432 private List<Appender> getAsyncAppenders(final Appender[] all) {
433 final List<Appender> result = new ArrayList<>();
434 for (int i = all.length - 1; i >= 0; --i) {
435 if (all[i] instanceof AsyncAppender) {
436 result.add(all[i]);
437 }
438 }
439 return result;
440 }
441
442 @Override
443 public boolean isShutdownHookEnabled() {
444 return isShutdownHookEnabled;
445 }
446
447 @Override
448 public long getShutdownTimeoutMillis() {
449 return shutdownTimeoutMillis;
450 }
451
452 public void setup() {
453
454 }
455
456 protected Level getDefaultStatus() {
457 final String statusLevel = PropertiesUtil.getProperties().getStringProperty(
458 Constants.LOG4J_DEFAULT_STATUS_LEVEL, Level.ERROR.name());
459 try {
460 return Level.toLevel(statusLevel);
461 } catch (final Exception ex) {
462 return Level.ERROR;
463 }
464 }
465
466 protected void createAdvertiser(final String advertiserString, final ConfigurationSource configSource,
467 final byte[] buffer, final String contentType) {
468 if (advertiserString != null) {
469 final Node node = new Node(null, advertiserString, null);
470 final Map<String, String> attributes = node.getAttributes();
471 attributes.put("content", new String(buffer));
472 attributes.put("contentType", contentType);
473 attributes.put("name", "configuration");
474 if (configSource.getLocation() != null) {
475 attributes.put("location", configSource.getLocation());
476 }
477 advertiserNode = node;
478 }
479 }
480
481 private void setupAdvertisement() {
482 if (advertiserNode != null) {
483 final String nodeName = advertiserNode.getName();
484 final PluginType<?> type = pluginManager.getPluginType(nodeName);
485 if (type != null) {
486 final Class<? extends Advertiser> clazz = type.getPluginClass().asSubclass(Advertiser.class);
487 try {
488 advertiser = clazz.newInstance();
489 advertisement = advertiser.advertise(advertiserNode.getAttributes());
490 } catch (final InstantiationException e) {
491 LOGGER.error("InstantiationException attempting to instantiate advertiser: {}", nodeName, e);
492 } catch (final IllegalAccessException e) {
493 LOGGER.error("IllegalAccessException attempting to instantiate advertiser: {}", nodeName, e);
494 }
495 }
496 }
497 }
498
499 @SuppressWarnings("unchecked")
500 @Override
501 public <T> T getComponent(final String componentName) {
502 return (T) componentMap.get(componentName);
503 }
504
505 @Override
506 public void addComponent(final String componentName, final Object obj) {
507 componentMap.putIfAbsent(componentName, obj);
508 }
509
510 protected void preConfigure(final Node node) {
511 try {
512 for (final Node child : node.getChildren()) {
513 if (child.getType() == null) {
514 LOGGER.error("Unable to locate plugin type for " + child.getName());
515 continue;
516 }
517 final Class<?> clazz = child.getType().getPluginClass();
518 if (clazz.isAnnotationPresent(Scheduled.class)) {
519 configurationScheduler.incrementScheduledItems();
520 }
521 preConfigure(child);
522 }
523 } catch (final Exception ex) {
524 LOGGER.error("Error capturing node data for node " + node.getName(), ex);
525 }
526 }
527
528 protected void doConfigure() {
529 preConfigure(rootNode);
530 configurationScheduler.start();
531 if (rootNode.hasChildren() && rootNode.getChildren().get(0).getName().equalsIgnoreCase("Properties")) {
532 final Node first = rootNode.getChildren().get(0);
533 createConfiguration(first, null);
534 if (first.getObject() != null) {
535 subst.setVariableResolver((StrLookup) first.getObject());
536 }
537 } else {
538 final Map<String, String> map = this.getComponent(CONTEXT_PROPERTIES);
539 final StrLookup lookup = map == null ? null : new MapLookup(map);
540 subst.setVariableResolver(new Interpolator(lookup, pluginPackages));
541 }
542
543 boolean setLoggers = false;
544 boolean setRoot = false;
545 for (final Node child : rootNode.getChildren()) {
546 if (child.getName().equalsIgnoreCase("Properties")) {
547 if (tempLookup == subst.getVariableResolver()) {
548 LOGGER.error("Properties declaration must be the first element in the configuration");
549 }
550 continue;
551 }
552 createConfiguration(child, null);
553 if (child.getObject() == null) {
554 continue;
555 }
556 if (child.getName().equalsIgnoreCase("Scripts")) {
557 for (final AbstractScript script : child.getObject(AbstractScript[].class)) {
558 if (script instanceof ScriptRef) {
559 LOGGER.error("Script reference to {} not added. Scripts definition cannot contain script references",
560 script.getName());
561 } else {
562 if (scriptManager != null) {
563 scriptManager.addScript(script);
564 }}
565 }
566 } else if (child.getName().equalsIgnoreCase("Appenders")) {
567 appenders = child.getObject();
568 } else if (child.isInstanceOf(Filter.class)) {
569 addFilter(child.getObject(Filter.class));
570 } else if (child.getName().equalsIgnoreCase("Loggers")) {
571 final Loggers l = child.getObject();
572 loggerConfigs = l.getMap();
573 setLoggers = true;
574 if (l.getRoot() != null) {
575 root = l.getRoot();
576 setRoot = true;
577 }
578 } else if (child.getName().equalsIgnoreCase("CustomLevels")) {
579 customLevels = child.getObject(CustomLevels.class).getCustomLevels();
580 } else if (child.isInstanceOf(CustomLevelConfig.class)) {
581 final List<CustomLevelConfig> copy = new ArrayList<>(customLevels);
582 copy.add(child.getObject(CustomLevelConfig.class));
583 customLevels = copy;
584 } else {
585 final List<String> expected = Arrays.asList("\"Appenders\"", "\"Loggers\"", "\"Properties\"",
586 "\"Scripts\"", "\"CustomLevels\"");
587 LOGGER.error("Unknown object \"{}\" of type {} is ignored: try nesting it inside one of: {}.",
588 child.getName(), child.getObject().getClass().getName(), expected);
589 }
590 }
591
592 if (!setLoggers) {
593 LOGGER.warn("No Loggers were configured, using default. Is the Loggers element missing?");
594 setToDefault();
595 return;
596 } else if (!setRoot) {
597 LOGGER.warn("No Root logger was configured, creating default ERROR-level Root logger with Console appender");
598 setToDefault();
599
600 }
601
602 for (final Map.Entry<String, LoggerConfig> entry : loggerConfigs.entrySet()) {
603 final LoggerConfig loggerConfig = entry.getValue();
604 for (final AppenderRef ref : loggerConfig.getAppenderRefs()) {
605 final Appender app = appenders.get(ref.getRef());
606 if (app != null) {
607 loggerConfig.addAppender(app, ref.getLevel(), ref.getFilter());
608 } else {
609 LOGGER.error("Unable to locate appender \"{}\" for logger config \"{}\"", ref.getRef(),
610 loggerConfig);
611 }
612 }
613
614 }
615
616 setParents();
617 }
618
619 protected void setToDefault() {
620
621 setName(DefaultConfiguration.DEFAULT_NAME + "@" + Integer.toHexString(hashCode()));
622 final Layout<? extends Serializable> layout = PatternLayout.newBuilder()
623 .withPattern(DefaultConfiguration.DEFAULT_PATTERN)
624 .withConfiguration(this)
625 .build();
626 final Appender appender = ConsoleAppender.createDefaultAppenderForLayout(layout);
627 appender.start();
628 addAppender(appender);
629 final LoggerConfig rootLoggerConfig = getRootLogger();
630 rootLoggerConfig.addAppender(appender, null, null);
631
632 final Level defaultLevel = Level.ERROR;
633 final String levelName = PropertiesUtil.getProperties().getStringProperty(DefaultConfiguration.DEFAULT_LEVEL,
634 defaultLevel.name());
635 final Level level = Level.valueOf(levelName);
636 rootLoggerConfig.setLevel(level != null ? level : defaultLevel);
637 }
638
639
640
641
642
643
644 public void setName(final String name) {
645 this.name = name;
646 }
647
648
649
650
651
652
653 @Override
654 public String getName() {
655 return name;
656 }
657
658
659
660
661
662
663 @Override
664 public void addListener(final ConfigurationListener listener) {
665 listeners.add(listener);
666 }
667
668
669
670
671
672
673 @Override
674 public void removeListener(final ConfigurationListener listener) {
675 listeners.remove(listener);
676 }
677
678
679
680
681
682
683
684 @Override
685 @SuppressWarnings("unchecked")
686 public <T extends Appender> T getAppender(final String appenderName) {
687 return appenderName != null ? (T) appenders.get(appenderName) : null;
688 }
689
690
691
692
693
694
695 @Override
696 public Map<String, Appender> getAppenders() {
697 return appenders;
698 }
699
700
701
702
703
704
705 @Override
706 public void addAppender(final Appender appender) {
707 if (appender != null) {
708 appenders.putIfAbsent(appender.getName(), appender);
709 }
710 }
711
712 @Override
713 public StrSubstitutor getStrSubstitutor() {
714 return subst;
715 }
716
717 @Override
718 public void setAdvertiser(final Advertiser advertiser) {
719 this.advertiser = advertiser;
720 }
721
722 @Override
723 public Advertiser getAdvertiser() {
724 return advertiser;
725 }
726
727
728
729
730
731
732
733 @Override
734 public ReliabilityStrategy getReliabilityStrategy(final LoggerConfig loggerConfig) {
735 return ReliabilityStrategyFactory.getReliabilityStrategy(loggerConfig);
736 }
737
738
739
740
741
742
743
744
745
746
747 @Override
748 public synchronized void addLoggerAppender(final org.apache.logging.log4j.core.Logger logger,
749 final Appender appender) {
750 if (appender == null || logger == null) {
751 return;
752 }
753 final String loggerName = logger.getName();
754 appenders.putIfAbsent(appender.getName(), appender);
755 final LoggerConfig lc = getLoggerConfig(loggerName);
756 if (lc.getName().equals(loggerName)) {
757 lc.addAppender(appender, null, null);
758 } else {
759 final LoggerConfig nlc = new LoggerConfig(loggerName, lc.getLevel(), lc.isAdditive());
760 nlc.addAppender(appender, null, null);
761 nlc.setParent(lc);
762 loggerConfigs.putIfAbsent(loggerName, nlc);
763 setParents();
764 logger.getContext().updateLoggers();
765 }
766 }
767
768
769
770
771
772
773
774
775
776
777 @Override
778 public synchronized void addLoggerFilter(final org.apache.logging.log4j.core.Logger logger, final Filter filter) {
779 final String loggerName = logger.getName();
780 final LoggerConfig lc = getLoggerConfig(loggerName);
781 if (lc.getName().equals(loggerName)) {
782 lc.addFilter(filter);
783 } else {
784 final LoggerConfig nlc = new LoggerConfig(loggerName, lc.getLevel(), lc.isAdditive());
785 nlc.addFilter(filter);
786 nlc.setParent(lc);
787 loggerConfigs.putIfAbsent(loggerName, nlc);
788 setParents();
789 logger.getContext().updateLoggers();
790 }
791 }
792
793
794
795
796
797
798
799
800
801
802 @Override
803 public synchronized void setLoggerAdditive(final org.apache.logging.log4j.core.Logger logger, final boolean additive) {
804 final String loggerName = logger.getName();
805 final LoggerConfig lc = getLoggerConfig(loggerName);
806 if (lc.getName().equals(loggerName)) {
807 lc.setAdditive(additive);
808 } else {
809 final LoggerConfig nlc = new LoggerConfig(loggerName, lc.getLevel(), additive);
810 nlc.setParent(lc);
811 loggerConfigs.putIfAbsent(loggerName, nlc);
812 setParents();
813 logger.getContext().updateLoggers();
814 }
815 }
816
817
818
819
820
821
822
823
824 public synchronized void removeAppender(final String appenderName) {
825 for (final LoggerConfig logger : loggerConfigs.values()) {
826 logger.removeAppender(appenderName);
827 }
828 final Appender app = appenderName != null ? appenders.remove(appenderName) : null;
829
830 if (app != null) {
831 app.stop();
832 }
833 }
834
835
836
837
838
839
840 @Override
841 public List<CustomLevelConfig> getCustomLevels() {
842 return Collections.unmodifiableList(customLevels);
843 }
844
845
846
847
848
849
850
851
852 @Override
853 public LoggerConfig getLoggerConfig(final String loggerName) {
854 LoggerConfig loggerConfig = loggerConfigs.get(loggerName);
855 if (loggerConfig != null) {
856 return loggerConfig;
857 }
858 String substr = loggerName;
859 while ((substr = NameUtil.getSubName(substr)) != null) {
860 loggerConfig = loggerConfigs.get(substr);
861 if (loggerConfig != null) {
862 return loggerConfig;
863 }
864 }
865 return root;
866 }
867
868 @Override
869 public LoggerContext getLoggerContext() {
870 return loggerContext.get();
871 }
872
873
874
875
876
877
878 @Override
879 public LoggerConfig getRootLogger() {
880 return root;
881 }
882
883
884
885
886
887
888 @Override
889 public Map<String, LoggerConfig> getLoggers() {
890 return Collections.unmodifiableMap(loggerConfigs);
891 }
892
893
894
895
896
897
898
899 public LoggerConfig getLogger(final String loggerName) {
900 return loggerConfigs.get(loggerName);
901 }
902
903
904
905
906
907
908
909
910 @Override
911 public synchronized void addLogger(final String loggerName, final LoggerConfig loggerConfig) {
912 loggerConfigs.putIfAbsent(loggerName, loggerConfig);
913 setParents();
914 }
915
916
917
918
919
920
921 @Override
922 public synchronized void removeLogger(final String loggerName) {
923 loggerConfigs.remove(loggerName);
924 setParents();
925 }
926
927 @Override
928 public void createConfiguration(final Node node, final LogEvent event) {
929 final PluginType<?> type = node.getType();
930 if (type != null && type.isDeferChildren()) {
931 node.setObject(createPluginObject(type, node, event));
932 } else {
933 for (final Node child : node.getChildren()) {
934 createConfiguration(child, event);
935 }
936
937 if (type == null) {
938 if (node.getParent() != null) {
939 LOGGER.error("Unable to locate plugin for {}", node.getName());
940 }
941 } else {
942 node.setObject(createPluginObject(type, node, event));
943 }
944 }
945 }
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983 private Object createPluginObject(final PluginType<?> type, final Node node, final LogEvent event) {
984 final Class<?> clazz = type.getPluginClass();
985
986 if (Map.class.isAssignableFrom(clazz)) {
987 try {
988 return createPluginMap(node);
989 } catch (final Exception e) {
990 LOGGER.warn("Unable to create Map for {} of class {}", type.getElementName(), clazz, e);
991 }
992 }
993
994 if (Collection.class.isAssignableFrom(clazz)) {
995 try {
996 return createPluginCollection(node);
997 } catch (final Exception e) {
998 LOGGER.warn("Unable to create List for {} of class {}", type.getElementName(), clazz, e);
999 }
1000 }
1001
1002 return new PluginBuilder(type).withConfiguration(this).withConfigurationNode(node).forLogEvent(event).build();
1003 }
1004
1005 private static Map<String, ?> createPluginMap(final Node node) {
1006 final Map<String, Object> map = new LinkedHashMap<>();
1007 for (final Node child : node.getChildren()) {
1008 final Object object = child.getObject();
1009 map.put(child.getName(), object);
1010 }
1011 return map;
1012 }
1013
1014 private static Collection<?> createPluginCollection(final Node node) {
1015 final List<Node> children = node.getChildren();
1016 final Collection<Object> list = new ArrayList<>(children.size());
1017 for (final Node child : children) {
1018 final Object object = child.getObject();
1019 list.add(object);
1020 }
1021 return list;
1022 }
1023
1024 private void setParents() {
1025 for (final Map.Entry<String, LoggerConfig> entry : loggerConfigs.entrySet()) {
1026 final LoggerConfig logger = entry.getValue();
1027 String key = entry.getKey();
1028 if (!key.isEmpty()) {
1029 final int i = key.lastIndexOf('.');
1030 if (i > 0) {
1031 key = key.substring(0, i);
1032 LoggerConfig parent = getLoggerConfig(key);
1033 if (parent == null) {
1034 parent = root;
1035 }
1036 logger.setParent(parent);
1037 } else {
1038 logger.setParent(root);
1039 }
1040 }
1041 }
1042 }
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052 protected static byte[] toByteArray(final InputStream is) throws IOException {
1053 final ByteArrayOutputStream buffer = new ByteArrayOutputStream();
1054
1055 int nRead;
1056 final byte[] data = new byte[BUF_SIZE];
1057
1058 while ((nRead = is.read(data, 0, data.length)) != -1) {
1059 buffer.write(data, 0, nRead);
1060 }
1061
1062 return buffer.toByteArray();
1063 }
1064
1065 @Override
1066 public NanoClock getNanoClock() {
1067 return nanoClock;
1068 }
1069
1070 @Override
1071 public void setNanoClock(final NanoClock nanoClock) {
1072 this.nanoClock = Objects.requireNonNull(nanoClock, "nanoClock");
1073 }
1074 }