001/* 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache license, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the license for the specific language governing permissions and 015 * limitations under the license. 016 */ 017package org.apache.logging.log4j.core.config.properties; 018 019import org.apache.logging.log4j.Level; 020import org.apache.logging.log4j.core.config.ConfigurationException; 021import org.apache.logging.log4j.core.config.ConfigurationFactory; 022import org.apache.logging.log4j.core.config.ConfigurationSource; 023import org.apache.logging.log4j.core.config.Order; 024import org.apache.logging.log4j.core.config.builder.api.AppenderComponentBuilder; 025import org.apache.logging.log4j.core.config.builder.api.AppenderRefComponentBuilder; 026import org.apache.logging.log4j.core.config.builder.api.ComponentBuilder; 027import org.apache.logging.log4j.core.config.builder.api.ConfigurationBuilder; 028import org.apache.logging.log4j.core.config.builder.api.FilterComponentBuilder; 029import org.apache.logging.log4j.core.config.builder.api.LayoutComponentBuilder; 030import org.apache.logging.log4j.core.config.builder.api.LoggerComponentBuilder; 031import org.apache.logging.log4j.core.config.builder.api.RootLoggerComponentBuilder; 032import org.apache.logging.log4j.core.config.plugins.Plugin; 033import org.apache.logging.log4j.util.PropertiesUtil; 034import org.apache.logging.log4j.util.Strings; 035 036import java.io.IOException; 037import java.io.InputStream; 038import java.util.Properties; 039 040/** 041 * Creates a PropertiesConfiguration from a properties file. 042 * @since 2.4 043 */ 044@Plugin(name = "PropertiesConfigurationFactory", category = ConfigurationFactory.CATEGORY) 045@Order(8) 046public class PropertiesConfigurationFactory extends ConfigurationFactory { 047 private static final String ADVERTISER_KEY = "advertiser"; 048 private static final String STATUS_KEY = "status"; 049 private static final String SHUTDOWN_HOOK = "shutdownHook"; 050 private static final String VERBOSE = "verbose"; 051 private static final String PACKAGES = "packages"; 052 private static final String CONFIG_NAME = "name"; 053 private static final String MONITOR_INTERVAL = "monitorInterval"; 054 private static final String CONFIG_TYPE = "type"; 055 056 @Override 057 protected String[] getSupportedTypes() { 058 return new String[] {".properties"}; 059 } 060 061 @Override 062 public PropertiesConfiguration getConfiguration(ConfigurationSource source) { 063 final InputStream configStream = source.getInputStream(); 064 Properties properties = new Properties(); 065 try { 066 properties.load(configStream); 067 } catch (IOException ioe) { 068 throw new ConfigurationException("Unable to load " + source.toString(), ioe); 069 } 070 ConfigurationBuilder<PropertiesConfiguration> builder = newConfigurationBuilder(PropertiesConfiguration.class); 071 String value = properties.getProperty(STATUS_KEY); 072 if (value != null) { 073 builder.setStatusLevel(Level.toLevel(value, Level.ERROR)); 074 } else { 075 builder.setStatusLevel(Level.ERROR); 076 } 077 value = properties.getProperty(SHUTDOWN_HOOK); 078 if (value != null) { 079 builder.setShutdownHook(value); 080 } 081 value = properties.getProperty(VERBOSE); 082 if (value != null) { 083 builder.setVerbosity(value); 084 } 085 value = properties.getProperty(PACKAGES); 086 if (value != null) { 087 builder.setPackages(value); 088 } 089 value = properties.getProperty(CONFIG_NAME); 090 if (value != null) { 091 builder.setConfigurationName(value); 092 } 093 value = properties.getProperty(MONITOR_INTERVAL); 094 if (value != null) { 095 builder.setMonitorInterval(value); 096 } 097 value = properties.getProperty(ADVERTISER_KEY); 098 if (value != null) { 099 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}