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