1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.apache.logging.log4j.core.config.composite;
18
19 import java.lang.reflect.InvocationTargetException;
20 import java.net.URI;
21 import java.util.ArrayList;
22 import java.util.Arrays;
23 import java.util.List;
24 import java.util.Map;
25
26 import org.apache.logging.log4j.Level;
27 import org.apache.logging.log4j.core.config.AbstractConfiguration;
28 import org.apache.logging.log4j.core.config.Configuration;
29 import org.apache.logging.log4j.core.config.ConfigurationFactory;
30 import org.apache.logging.log4j.core.config.ConfigurationSource;
31 import org.apache.logging.log4j.core.config.Node;
32 import org.apache.logging.log4j.core.config.Reconfigurable;
33 import org.apache.logging.log4j.core.config.plugins.util.ResolverUtil;
34 import org.apache.logging.log4j.core.config.status.StatusConfiguration;
35 import org.apache.logging.log4j.core.util.Loader;
36 import org.apache.logging.log4j.core.util.Patterns;
37 import org.apache.logging.log4j.core.util.Source;
38 import org.apache.logging.log4j.core.util.WatchManager;
39 import org.apache.logging.log4j.core.util.Watcher;
40 import org.apache.logging.log4j.util.PropertiesUtil;
41
42
43
44
45 public class CompositeConfiguration extends AbstractConfiguration implements Reconfigurable {
46
47
48
49
50 public static final String MERGE_STRATEGY_PROPERTY = "log4j.mergeStrategy";
51
52 private static final String[] VERBOSE_CLASSES = new String[] {ResolverUtil.class.getName()};
53
54 private final List<? extends AbstractConfiguration> configurations;
55
56 private MergeStrategy mergeStrategy;
57
58
59
60
61
62
63 public CompositeConfiguration(final List<? extends AbstractConfiguration> configurations) {
64 super(configurations.get(0).getLoggerContext(), ConfigurationSource.NULL_SOURCE);
65 rootNode = configurations.get(0).getRootNode();
66 this.configurations = configurations;
67 final String mergeStrategyClassName = PropertiesUtil.getProperties().getStringProperty(MERGE_STRATEGY_PROPERTY,
68 DefaultMergeStrategy.class.getName());
69 try {
70 mergeStrategy = Loader.newInstanceOf(mergeStrategyClassName);
71 } catch (ClassNotFoundException | IllegalAccessException | NoSuchMethodException | InvocationTargetException |
72 InstantiationException ex) {
73 mergeStrategy = new DefaultMergeStrategy();
74 }
75 for (final AbstractConfiguration config : configurations) {
76 mergeStrategy.mergeRootProperties(rootNode, config);
77 }
78 final StatusConfiguration statusConfig = new StatusConfiguration().withVerboseClasses(VERBOSE_CLASSES)
79 .withStatus(getDefaultStatus());
80 for (final Map.Entry<String, String> entry : rootNode.getAttributes().entrySet()) {
81 final String key = entry.getKey();
82 final String value = getConfigurationStrSubstitutor().replace(entry.getValue());
83 if ("status".equalsIgnoreCase(key)) {
84 statusConfig.withStatus(value.toUpperCase());
85 } else if ("dest".equalsIgnoreCase(key)) {
86 statusConfig.withDestination(value);
87 } else if ("shutdownHook".equalsIgnoreCase(key)) {
88 isShutdownHookEnabled = !"disable".equalsIgnoreCase(value);
89 } else if ("shutdownTimeout".equalsIgnoreCase(key)) {
90 shutdownTimeoutMillis = Long.parseLong(value);
91 } else if ("verbose".equalsIgnoreCase(key)) {
92 statusConfig.withVerbosity(value);
93 } else if ("packages".equalsIgnoreCase(key)) {
94 pluginPackages.addAll(Arrays.asList(value.split(Patterns.COMMA_SEPARATOR)));
95 } else if ("name".equalsIgnoreCase(key)) {
96 setName(value);
97 }
98 }
99 statusConfig.initialize();
100 }
101
102 @Override
103 public void setup() {
104 final AbstractConfiguration targetConfiguration = configurations.get(0);
105 staffChildConfiguration(targetConfiguration);
106 final WatchManager watchManager = getWatchManager();
107 final WatchManager targetWatchManager = targetConfiguration.getWatchManager();
108 if (targetWatchManager.getIntervalSeconds() > 0) {
109 watchManager.setIntervalSeconds(targetWatchManager.getIntervalSeconds());
110 final Map<Source, Watcher> watchers = targetWatchManager.getConfigurationWatchers();
111 for (final Map.Entry<Source, Watcher> entry : watchers.entrySet()) {
112 watchManager.watch(entry.getKey(), entry.getValue().newWatcher(this, listeners,
113 entry.getValue().getLastModified()));
114 }
115 }
116 for (final AbstractConfiguration sourceConfiguration : configurations.subList(1, configurations.size())) {
117 staffChildConfiguration(sourceConfiguration);
118 final Node sourceRoot = sourceConfiguration.getRootNode();
119 mergeStrategy.mergConfigurations(rootNode, sourceRoot, getPluginManager());
120 if (LOGGER.isEnabled(Level.ALL)) {
121 final StringBuilder sb = new StringBuilder();
122 printNodes("", rootNode, sb);
123 System.out.println(sb.toString());
124 }
125 final int monitorInterval = sourceConfiguration.getWatchManager().getIntervalSeconds();
126 if (monitorInterval > 0) {
127 final int currentInterval = watchManager.getIntervalSeconds();
128 if (currentInterval <= 0 || monitorInterval < currentInterval) {
129 watchManager.setIntervalSeconds(monitorInterval);
130 }
131 final WatchManager sourceWatchManager = sourceConfiguration.getWatchManager();
132 final Map<Source, Watcher> watchers = sourceWatchManager.getConfigurationWatchers();
133 for (final Map.Entry<Source, Watcher> entry : watchers.entrySet()) {
134 watchManager.watch(entry.getKey(), entry.getValue().newWatcher(this, listeners,
135 entry.getValue().getLastModified()));
136 }
137 }
138 }
139 }
140
141 @Override
142 public Configuration reconfigure() {
143 LOGGER.debug("Reconfiguring composite configuration");
144 final List<AbstractConfiguration> configs = new ArrayList<>();
145 final ConfigurationFactory factory = ConfigurationFactory.getInstance();
146 for (final AbstractConfiguration config : configurations) {
147 final ConfigurationSource source = config.getConfigurationSource();
148 final URI sourceURI = source.getURI();
149 Configuration currentConfig = config;
150 if (sourceURI == null) {
151 LOGGER.warn("Unable to determine URI for configuration {}, changes to it will be ignored",
152 config.getName());
153 } else {
154 currentConfig = factory.getConfiguration(getLoggerContext(), config.getName(), sourceURI);
155 if (currentConfig == null) {
156 LOGGER.warn("Unable to reload configuration {}, changes to it will be ignored", config.getName());
157 }
158 }
159 configs.add((AbstractConfiguration) currentConfig);
160
161 }
162
163 return new CompositeConfiguration(configs);
164 }
165
166 private void staffChildConfiguration(final AbstractConfiguration childConfiguration) {
167 childConfiguration.setPluginManager(pluginManager);
168 childConfiguration.setScriptManager(scriptManager);
169 childConfiguration.setup();
170 }
171
172 private void printNodes(final String indent, final Node node, final StringBuilder sb) {
173 sb.append(indent).append(node.getName()).append(" type: ").append(node.getType()).append("\n");
174 sb.append(indent).append(node.getAttributes().toString()).append("\n");
175 for (final Node child : node.getChildren()) {
176 printNodes(indent + " ", child, sb);
177 }
178 }
179
180 @Override
181 public String toString() {
182 return getClass().getName() + "@" + Integer.toHexString(hashCode()) + " [configurations=" + configurations
183 + ", mergeStrategy=" + mergeStrategy + ", rootNode=" + rootNode + ", listeners=" + listeners
184 + ", pluginPackages=" + pluginPackages + ", pluginManager=" + pluginManager + ", isShutdownHookEnabled="
185 + isShutdownHookEnabled + ", shutdownTimeoutMillis=" + shutdownTimeoutMillis + ", scriptManager="
186 + scriptManager + "]";
187 }
188 }