View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements. See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache license, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License. You may obtain a copy of the License at
8    *
9    *      http://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the license for the specific language governing permissions and
15   * limitations under the license.
16   */
17  package org.apache.logging.log4j.core.config.properties;
18  
19  import org.apache.logging.log4j.Level;
20  import org.apache.logging.log4j.core.config.ConfigurationException;
21  import org.apache.logging.log4j.core.config.ConfigurationFactory;
22  import org.apache.logging.log4j.core.config.ConfigurationSource;
23  import org.apache.logging.log4j.core.config.LoggerConfig;
24  import org.apache.logging.log4j.core.config.Order;
25  import org.apache.logging.log4j.core.config.builder.api.AppenderComponentBuilder;
26  import org.apache.logging.log4j.core.config.builder.api.AppenderRefComponentBuilder;
27  import org.apache.logging.log4j.core.config.builder.api.ComponentBuilder;
28  import org.apache.logging.log4j.core.config.builder.api.ConfigurationBuilder;
29  import org.apache.logging.log4j.core.config.builder.api.FilterComponentBuilder;
30  import org.apache.logging.log4j.core.config.builder.api.LayoutComponentBuilder;
31  import org.apache.logging.log4j.core.config.builder.api.LoggerComponentBuilder;
32  import org.apache.logging.log4j.core.config.builder.api.RootLoggerComponentBuilder;
33  import org.apache.logging.log4j.core.config.plugins.Plugin;
34  import org.apache.logging.log4j.util.PropertiesUtil;
35  import org.apache.logging.log4j.util.Strings;
36  
37  import java.io.IOException;
38  import java.io.InputStream;
39  import java.util.Properties;
40  
41  /**
42   * Creates a PropertiesConfiguration from a properties file.
43   * 
44   * @since 2.4
45   */
46  @Plugin(name = "PropertiesConfigurationFactory", category = ConfigurationFactory.CATEGORY)
47  @Order(8)
48  public class PropertiesConfigurationFactory extends ConfigurationFactory {
49      private static final String ADVERTISER_KEY = "advertiser";
50      private static final String STATUS_KEY = "status";
51      private static final String SHUTDOWN_HOOK = "shutdownHook";
52      private static final String VERBOSE = "verbose";
53      private static final String PACKAGES = "packages";
54      private static final String CONFIG_NAME = "name";
55      private static final String MONITOR_INTERVAL = "monitorInterval";
56      private static final String CONFIG_TYPE = "type";
57  
58      @Override
59      protected String[] getSupportedTypes() {
60          return new String[] {".properties"};
61      }
62  
63      @Override
64      public PropertiesConfiguration getConfiguration(ConfigurationSource source) {
65          final InputStream configStream = source.getInputStream();
66          Properties properties = new Properties();
67          try {
68              properties.load(configStream);
69          } catch (IOException ioe) {
70              throw new ConfigurationException("Unable to load " + source.toString(), ioe);
71          }
72          ConfigurationBuilder<PropertiesConfiguration> builder = newConfigurationBuilder(PropertiesConfiguration.class);
73          String value = properties.getProperty(STATUS_KEY);
74          if (value != null) {
75              builder.setStatusLevel(Level.toLevel(value, Level.ERROR));
76          } else {
77              builder.setStatusLevel(Level.ERROR);
78          }
79          value = properties.getProperty(SHUTDOWN_HOOK);
80          if (value != null) {
81              builder.setShutdownHook(value);
82          }
83          value = properties.getProperty(VERBOSE);
84          if (value != null) {
85              builder.setVerbosity(value);
86          }
87          value = properties.getProperty(PACKAGES);
88          if (value != null) {
89              builder.setPackages(value);
90          }
91          value = properties.getProperty(CONFIG_NAME);
92          if (value != null) {
93              builder.setConfigurationName(value);
94          }
95          value = properties.getProperty(MONITOR_INTERVAL);
96          if (value != null) {
97              builder.setMonitorInterval(value);
98          }
99          value = properties.getProperty(ADVERTISER_KEY);
100         if (value != null) {
101             builder.setAdvertiser(value);
102         }
103         Properties props = PropertiesUtil.extractSubset(properties, "property");
104         for (String key : props.stringPropertyNames()) {
105             builder.addProperty(key, props.getProperty(key));
106         }
107 
108         Properties levelProps = PropertiesUtil.extractSubset(properties, "customLevel");
109         if (levelProps.size() > 0) {
110             for (String key : levelProps.stringPropertyNames()) {
111                 builder.add(builder.newCustomLevel(key, Integer.parseInt(props.getProperty(key))));
112             }
113         }
114 
115         String filterProp = properties.getProperty("filters");
116         if (filterProp != null) {
117             String[] filterNames = filterProp.split(",");
118             for (String filterName : filterNames) {
119                 String name = filterName.trim();
120                 builder.add(createFilter(builder, name, PropertiesUtil.extractSubset(properties, "filter." + name)));
121             }
122         }
123         String appenderProp = properties.getProperty("appenders");
124         if (appenderProp != null) {
125             String[] appenderNames = appenderProp.split(",");
126             for (String appenderName : appenderNames) {
127                 String name = appenderName.trim();
128                 builder.add(createAppender(builder, name, PropertiesUtil.extractSubset(properties, "appender." +
129                         name)));
130             }
131         }
132         String loggerProp = properties.getProperty("loggers");
133         if (loggerProp != null) {
134             String[] loggerNames = loggerProp.split(",");
135             for (String loggerName : loggerNames) {
136                 String name = loggerName.trim();
137                 if (!name.equals(LoggerConfig.ROOT)) {
138                     builder.add(createLogger(builder, name, PropertiesUtil.extractSubset(properties, "logger." +
139                             name)));
140                 }
141             }
142         }
143 
144         props = PropertiesUtil.extractSubset(properties, "rootLogger");
145         if (props.size() > 0) {
146             builder.add(createRootLogger(builder, props));
147         }
148 
149         return builder.build();
150     }
151 
152     private AppenderComponentBuilder createAppender(ConfigurationBuilder<PropertiesConfiguration> builder, String key,
153             Properties properties) {
154         String name = properties.getProperty(CONFIG_NAME);
155         if (Strings.isEmpty(name)) {
156             throw new ConfigurationException("No name attribute provided for Appender " + key);
157         }
158         properties.remove(CONFIG_NAME);
159         String type = properties.getProperty(CONFIG_TYPE);
160         if (Strings.isEmpty(type)) {
161             throw new ConfigurationException("No type attribute provided for Appender " + key);
162         }
163         properties.remove(CONFIG_TYPE);
164         AppenderComponentBuilder appenderBuilder = builder.newAppender(name, type);
165         String filters = properties.getProperty("filters");
166         if (filters != null) {
167             properties.remove("filters");
168             String[] filterNames = filters.split(",");
169             for (String filterName : filterNames) {
170                 filterName = filterName.trim();
171                 Properties filterProps = PropertiesUtil.extractSubset(properties, "filter." + filterName);
172                 appenderBuilder.add(createFilter(builder, filterName, filterProps));
173             }
174         }
175         Properties layoutProps = PropertiesUtil.extractSubset(properties, "layout");
176         if (layoutProps.size() > 0) {
177             appenderBuilder.add(createLayout(builder, name, layoutProps));
178         }
179 
180         processRemainingProperties(appenderBuilder, name, properties);
181         return appenderBuilder;
182     }
183 
184     private FilterComponentBuilder createFilter(ConfigurationBuilder<PropertiesConfiguration> builder, String key,
185             Properties properties) {
186         String type = properties.getProperty(CONFIG_TYPE);
187         if (Strings.isEmpty(type)) {
188             throw new ConfigurationException("No type attribute provided for Appender " + key);
189         }
190         properties.remove(CONFIG_TYPE);
191         String onMatch = properties.getProperty("onMatch");
192         if (onMatch != null) {
193             properties.remove("onMatch");
194         }
195         String onMisMatch = properties.getProperty("onMisMatch");
196         if (onMisMatch != null) {
197             properties.remove("onMisMatch");
198         }
199         FilterComponentBuilder filterBuilder = builder.newFilter(type, onMatch, onMisMatch);
200         processRemainingProperties(filterBuilder, key, properties);
201         return filterBuilder;
202     }
203 
204     private AppenderRefComponentBuilder createAppenderRef(ConfigurationBuilder<PropertiesConfiguration> builder,
205             String key, Properties properties) {
206         String ref = properties.getProperty("ref");
207         if (Strings.isEmpty(ref)) {
208             throw new ConfigurationException("No ref attribute provided for AppenderRef " + key);
209         }
210         properties.remove("ref");
211         AppenderRefComponentBuilder appenderRefBuilder = builder.newAppenderRef(ref);
212         String level = properties.getProperty("level");
213         if (!Strings.isEmpty(level)) {
214             appenderRefBuilder.addAttribute("level", level);
215         }
216         String filters = properties.getProperty("filters");
217         if (filters != null) {
218             properties.remove("filters");
219             String[] filterNames = filters.split(",");
220             for (String filterName : filterNames) {
221                 filterName = filterName.trim();
222                 Properties filterProps = PropertiesUtil.extractSubset(properties, "filter." + filterName);
223                 appenderRefBuilder.add(createFilter(builder, filterName, filterProps));
224             }
225         }
226         return appenderRefBuilder;
227     }
228 
229     private LoggerComponentBuilder createLogger(ConfigurationBuilder<PropertiesConfiguration> builder, String key,
230             Properties properties) {
231         String name = properties.getProperty(CONFIG_NAME);
232         if (Strings.isEmpty(name)) {
233             throw new ConfigurationException("No name attribute provided for Logger " + key);
234         }
235         properties.remove(CONFIG_NAME);
236         String level = properties.getProperty("level");
237         if (level != null) {
238             properties.remove("level");
239         }
240         LoggerComponentBuilder loggerBuilder;
241         String type = properties.getProperty(CONFIG_TYPE);
242         if (type != null) {
243             if (type.equalsIgnoreCase("asyncLogger")) {
244                 loggerBuilder = builder.newAsyncLogger(name, level);
245             } else {
246                 throw new ConfigurationException("Unknown Logger type " + type + " for Logger " + name);
247             }
248         } else {
249             loggerBuilder = builder.newLogger(name, level);
250         }
251         String appenderRefs = properties.getProperty("appenderRefs");
252         if (appenderRefs != null) {
253             properties.remove("appenderRefs");
254             String[] refNames = appenderRefs.split(",");
255             for (String appenderRef : refNames) {
256                 appenderRef = appenderRef.trim();
257                 Properties refProps = PropertiesUtil.extractSubset(properties, "appenderRef." + appenderRef);
258                 loggerBuilder.add(createAppenderRef(builder, appenderRef, refProps));
259             }
260         }
261         String filters = properties.getProperty("filters");
262         if (filters != null) {
263             properties.remove("filters");
264             String[] filterNames = filters.split(",");
265             for (String filterName : filterNames) {
266                 filterName = filterName.trim();
267                 Properties filterProps = PropertiesUtil.extractSubset(properties, "filter." + filterName);
268                 loggerBuilder.add(createFilter(builder, filterName, filterProps));
269             }
270         }
271         String additivity = properties.getProperty("additivity");
272         if (!Strings.isEmpty(additivity)) {
273             loggerBuilder.addAttribute("additivity", additivity);
274         }
275         return loggerBuilder;
276     }
277 
278     private RootLoggerComponentBuilder createRootLogger(ConfigurationBuilder<PropertiesConfiguration> builder,
279             Properties properties) {
280         String level = properties.getProperty("level");
281         if (level != null) {
282             properties.remove("level");
283         }
284         RootLoggerComponentBuilder loggerBuilder;
285         String type = properties.getProperty(CONFIG_TYPE);
286         if (type != null) {
287             if (type.equalsIgnoreCase("asyncRoot")) {
288                 loggerBuilder = builder.newAsyncRootLogger(level);
289             } else {
290                 throw new ConfigurationException("Unknown Logger type for root logger" + type);
291             }
292         } else {
293             loggerBuilder = builder.newRootLogger(level);
294         }
295         String appenderRefs = properties.getProperty("appenderRefs");
296         if (appenderRefs != null) {
297             properties.remove("appenderRefs");
298             String[] refNames = appenderRefs.split(",");
299             for (String appenderRef : refNames) {
300                 appenderRef = appenderRef.trim();
301                 Properties refProps = PropertiesUtil.extractSubset(properties, "appenderRef." + appenderRef);
302                 loggerBuilder.add(createAppenderRef(builder, appenderRef, refProps));
303             }
304         }
305         String filters = properties.getProperty("filters");
306         if (filters != null) {
307             properties.remove("filters");
308             String[] filterNames = filters.split(",");
309             for (String filterName : filterNames) {
310                 filterName = filterName.trim();
311                 Properties filterProps = PropertiesUtil.extractSubset(properties, "filter." + filterName);
312                 loggerBuilder.add(createFilter(builder, filterName, filterProps));
313             }
314         }
315         return loggerBuilder;
316     }
317 
318     private LayoutComponentBuilder createLayout(ConfigurationBuilder<PropertiesConfiguration> builder,
319             String appenderName, Properties properties) {
320         String type = properties.getProperty(CONFIG_TYPE);
321         if (Strings.isEmpty(type)) {
322             throw new ConfigurationException("No type attribute provided for Layout on Appender " + appenderName);
323         }
324         properties.remove(CONFIG_TYPE);
325         LayoutComponentBuilder layoutBuilder = builder.newLayout(type);
326         processRemainingProperties(layoutBuilder, appenderName, properties);
327         return layoutBuilder;
328     }
329 
330     private <B extends ComponentBuilder<B>> ComponentBuilder<B> createComponent(ComponentBuilder<?> parent, String key,
331             Properties properties) {
332         String name = properties.getProperty(CONFIG_NAME);
333         if (name != null) {
334             properties.remove(CONFIG_NAME);
335         }
336         String type = properties.getProperty(CONFIG_TYPE);
337         if (Strings.isEmpty(type)) {
338             throw new ConfigurationException("No type attribute provided for component " + key);
339         }
340         properties.remove(CONFIG_TYPE);
341         ComponentBuilder<B> componentBuilder = parent.getBuilder().newComponent(name, type);
342         processRemainingProperties(componentBuilder, name, properties);
343         return componentBuilder;
344     }
345 
346     private void processRemainingProperties(ComponentBuilder<?> builder, String name, Properties properties) {
347         while (properties.size() > 0) {
348             String propertyName = properties.stringPropertyNames().iterator().next();
349 
350             int index = propertyName.indexOf('.');
351             if (index > 0) {
352                 String prefix = propertyName.substring(0, index);
353                 Properties componentProperties = PropertiesUtil.extractSubset(properties, prefix);
354                 builder.addComponent(createComponent(builder, prefix, componentProperties));
355             } else {
356                 builder.addAttribute(propertyName, properties.getProperty(propertyName));
357                 properties.remove(propertyName);
358             }
359         }
360     }
361 }