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