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.LoggerConfig; 024import org.apache.logging.log4j.core.config.Order; 025import org.apache.logging.log4j.core.config.builder.api.AppenderComponentBuilder; 026import org.apache.logging.log4j.core.config.builder.api.AppenderRefComponentBuilder; 027import org.apache.logging.log4j.core.config.builder.api.ComponentBuilder; 028import org.apache.logging.log4j.core.config.builder.api.ConfigurationBuilder; 029import org.apache.logging.log4j.core.config.builder.api.FilterComponentBuilder; 030import org.apache.logging.log4j.core.config.builder.api.LayoutComponentBuilder; 031import org.apache.logging.log4j.core.config.builder.api.LoggerComponentBuilder; 032import org.apache.logging.log4j.core.config.builder.api.RootLoggerComponentBuilder; 033import org.apache.logging.log4j.core.config.plugins.Plugin; 034import org.apache.logging.log4j.util.PropertiesUtil; 035import org.apache.logging.log4j.util.Strings; 036 037import java.io.IOException; 038import java.io.InputStream; 039import java.util.Properties; 040 041/** 042 * Creates a PropertiesConfiguration from a properties file. 043 * 044 * @since 2.4 045 */ 046@Plugin(name = "PropertiesConfigurationFactory", category = ConfigurationFactory.CATEGORY) 047@Order(8) 048public class PropertiesConfigurationFactory extends ConfigurationFactory { 049 private static final String ADVERTISER_KEY = "advertiser"; 050 private static final String STATUS_KEY = "status"; 051 private static final String SHUTDOWN_HOOK = "shutdownHook"; 052 private static final String VERBOSE = "verbose"; 053 private static final String PACKAGES = "packages"; 054 private static final String CONFIG_NAME = "name"; 055 private static final String MONITOR_INTERVAL = "monitorInterval"; 056 private static final String CONFIG_TYPE = "type"; 057 058 @Override 059 protected String[] getSupportedTypes() { 060 return new String[] {".properties"}; 061 } 062 063 @Override 064 public PropertiesConfiguration getConfiguration(ConfigurationSource source) { 065 final InputStream configStream = source.getInputStream(); 066 Properties properties = new Properties(); 067 try { 068 properties.load(configStream); 069 } catch (IOException ioe) { 070 throw new ConfigurationException("Unable to load " + source.toString(), ioe); 071 } 072 ConfigurationBuilder<PropertiesConfiguration> builder = newConfigurationBuilder(PropertiesConfiguration.class); 073 String value = properties.getProperty(STATUS_KEY); 074 if (value != null) { 075 builder.setStatusLevel(Level.toLevel(value, Level.ERROR)); 076 } else { 077 builder.setStatusLevel(Level.ERROR); 078 } 079 value = properties.getProperty(SHUTDOWN_HOOK); 080 if (value != null) { 081 builder.setShutdownHook(value); 082 } 083 value = properties.getProperty(VERBOSE); 084 if (value != null) { 085 builder.setVerbosity(value); 086 } 087 value = properties.getProperty(PACKAGES); 088 if (value != null) { 089 builder.setPackages(value); 090 } 091 value = properties.getProperty(CONFIG_NAME); 092 if (value != null) { 093 builder.setConfigurationName(value); 094 } 095 value = properties.getProperty(MONITOR_INTERVAL); 096 if (value != null) { 097 builder.setMonitorInterval(value); 098 } 099 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}