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