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