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.builder.api.ScriptComponentBuilder; 034import org.apache.logging.log4j.core.config.builder.api.ScriptFileComponentBuilder; 035import org.apache.logging.log4j.core.config.plugins.Plugin; 036import org.apache.logging.log4j.util.PropertiesUtil; 037import org.apache.logging.log4j.util.Strings; 038 039import java.io.IOException; 040import java.io.InputStream; 041import java.util.Properties; 042 043/** 044 * Creates a PropertiesConfiguration from a properties file. 045 * 046 * @since 2.4 047 */ 048@Plugin(name = "PropertiesConfigurationFactory", category = ConfigurationFactory.CATEGORY) 049@Order(8) 050public class PropertiesConfigurationFactory extends ConfigurationFactory { 051 private static final String ADVERTISER_KEY = "advertiser"; 052 private static final String STATUS_KEY = "status"; 053 private static final String SHUTDOWN_HOOK = "shutdownHook"; 054 private static final String VERBOSE = "verbose"; 055 private static final String PACKAGES = "packages"; 056 private static final String CONFIG_NAME = "name"; 057 private static final String MONITOR_INTERVAL = "monitorInterval"; 058 private static final String CONFIG_TYPE = "type"; 059 060 @Override 061 protected String[] getSupportedTypes() { 062 return new String[] {".properties"}; 063 } 064 065 @Override 066 public PropertiesConfiguration getConfiguration(ConfigurationSource source) { 067 final InputStream configStream = source.getInputStream(); 068 Properties properties = new Properties(); 069 try { 070 properties.load(configStream); 071 } catch (IOException ioe) { 072 throw new ConfigurationException("Unable to load " + source.toString(), ioe); 073 } 074 ConfigurationBuilder<PropertiesConfiguration> builder = newConfigurationBuilder(PropertiesConfiguration.class); 075 String value = properties.getProperty(STATUS_KEY); 076 if (value != null) { 077 builder.setStatusLevel(Level.toLevel(value, Level.ERROR)); 078 } else { 079 builder.setStatusLevel(Level.ERROR); 080 } 081 value = properties.getProperty(SHUTDOWN_HOOK); 082 if (value != null) { 083 builder.setShutdownHook(value); 084 } 085 value = properties.getProperty(VERBOSE); 086 if (value != null) { 087 builder.setVerbosity(value); 088 } 089 value = properties.getProperty(PACKAGES); 090 if (value != null) { 091 builder.setPackages(value); 092 } 093 value = properties.getProperty(CONFIG_NAME); 094 if (value != null) { 095 builder.setConfigurationName(value); 096 } 097 value = properties.getProperty(MONITOR_INTERVAL); 098 if (value != null) { 099 builder.setMonitorInterval(value); 100 } 101 value = properties.getProperty(ADVERTISER_KEY); 102 if (value != null) { 103 builder.setAdvertiser(value); 104 } 105 Properties props = PropertiesUtil.extractSubset(properties, "property"); 106 for (String key : props.stringPropertyNames()) { 107 builder.addProperty(key, props.getProperty(key)); 108 } 109 110 String scriptProp = properties.getProperty("scripts"); 111 if (scriptProp != null) { 112 String[] scriptNames = scriptProp.split(","); 113 for (String scriptName : scriptNames) { 114 String name = scriptName.trim(); 115 Properties scriptProps = PropertiesUtil.extractSubset(properties, "script." + name); 116 String type = scriptProps.getProperty("type"); 117 if (type == null) { 118 throw new ConfigurationException("No type provided for script - must be Script or ScriptFile"); 119 } 120 scriptProps.remove("type"); 121 if (type.equalsIgnoreCase("script")) { 122 builder.add(createScript(builder, name, scriptProps)); 123 } else { 124 builder.add(createScriptFile(builder, name, scriptProps)); 125 } 126 } 127 } 128 129 Properties levelProps = PropertiesUtil.extractSubset(properties, "customLevel"); 130 if (levelProps.size() > 0) { 131 for (String key : levelProps.stringPropertyNames()) { 132 builder.add(builder.newCustomLevel(key, Integer.parseInt(props.getProperty(key)))); 133 } 134 } 135 136 String filterProp = properties.getProperty("filters"); 137 if (filterProp != null) { 138 String[] filterNames = filterProp.split(","); 139 for (String filterName : filterNames) { 140 String name = filterName.trim(); 141 builder.add(createFilter(builder, name, PropertiesUtil.extractSubset(properties, "filter." + name))); 142 } 143 } 144 String appenderProp = properties.getProperty("appenders"); 145 if (appenderProp != null) { 146 String[] appenderNames = appenderProp.split(","); 147 for (String appenderName : appenderNames) { 148 String name = appenderName.trim(); 149 builder.add(createAppender(builder, name, PropertiesUtil.extractSubset(properties, "appender." + 150 name))); 151 } 152 } 153 String loggerProp = properties.getProperty("loggers"); 154 if (loggerProp != null) { 155 String[] loggerNames = loggerProp.split(","); 156 for (String loggerName : loggerNames) { 157 String name = loggerName.trim(); 158 if (!name.equals(LoggerConfig.ROOT)) { 159 builder.add(createLogger(builder, name, PropertiesUtil.extractSubset(properties, "logger." + 160 name))); 161 } 162 } 163 } 164 165 props = PropertiesUtil.extractSubset(properties, "rootLogger"); 166 if (props.size() > 0) { 167 builder.add(createRootLogger(builder, props)); 168 } 169 170 return builder.build(); 171 } 172 173 174 private ScriptComponentBuilder createScript(ConfigurationBuilder<PropertiesConfiguration> builder, String key, 175 Properties properties) { 176 String name = properties.getProperty("name"); 177 if (name != null) { 178 properties.remove("name"); 179 } 180 String language = properties.getProperty("language"); 181 if (language!= null) { 182 properties.remove("language"); 183 } 184 String text = properties.getProperty("text"); 185 if (text != null) { 186 properties.remove("text"); 187 } 188 ScriptComponentBuilder scriptBuilder = builder.newScript(name, language, text); 189 processRemainingProperties(scriptBuilder, key, properties); 190 return scriptBuilder; 191 } 192 193 private ScriptFileComponentBuilder createScriptFile(ConfigurationBuilder<PropertiesConfiguration> builder, String key, 194 Properties properties) { 195 String name = properties.getProperty("name"); 196 if (name != null) { 197 properties.remove("name"); 198 } 199 String path = properties.getProperty("path"); 200 if (path != null) { 201 properties.remove("path"); 202 } 203 ScriptFileComponentBuilder scriptFileBuilder = builder.newScriptFile(name, path); 204 processRemainingProperties(scriptFileBuilder, key, properties); 205 return scriptFileBuilder; 206 } 207 208 209 private AppenderComponentBuilder createAppender(ConfigurationBuilder<PropertiesConfiguration> builder, String key, 210 Properties properties) { 211 String name = properties.getProperty(CONFIG_NAME); 212 if (Strings.isEmpty(name)) { 213 throw new ConfigurationException("No name attribute provided for Appender " + key); 214 } 215 properties.remove(CONFIG_NAME); 216 String type = properties.getProperty(CONFIG_TYPE); 217 if (Strings.isEmpty(type)) { 218 throw new ConfigurationException("No type attribute provided for Appender " + key); 219 } 220 properties.remove(CONFIG_TYPE); 221 AppenderComponentBuilder appenderBuilder = builder.newAppender(name, type); 222 String filters = properties.getProperty("filters"); 223 if (filters != null) { 224 properties.remove("filters"); 225 String[] filterNames = filters.split(","); 226 for (String filterName : filterNames) { 227 filterName = filterName.trim(); 228 Properties filterProps = PropertiesUtil.extractSubset(properties, "filter." + filterName); 229 appenderBuilder.add(createFilter(builder, filterName, filterProps)); 230 } 231 } 232 Properties layoutProps = PropertiesUtil.extractSubset(properties, "layout"); 233 if (layoutProps.size() > 0) { 234 appenderBuilder.add(createLayout(builder, name, layoutProps)); 235 } 236 237 processRemainingProperties(appenderBuilder, name, properties); 238 return appenderBuilder; 239 } 240 241 private FilterComponentBuilder createFilter(ConfigurationBuilder<PropertiesConfiguration> builder, String key, 242 Properties properties) { 243 String type = properties.getProperty(CONFIG_TYPE); 244 if (Strings.isEmpty(type)) { 245 throw new ConfigurationException("No type attribute provided for Appender " + key); 246 } 247 properties.remove(CONFIG_TYPE); 248 String onMatch = properties.getProperty("onMatch"); 249 if (onMatch != null) { 250 properties.remove("onMatch"); 251 } 252 String onMisMatch = properties.getProperty("onMisMatch"); 253 if (onMisMatch != null) { 254 properties.remove("onMisMatch"); 255 } 256 FilterComponentBuilder filterBuilder = builder.newFilter(type, onMatch, onMisMatch); 257 processRemainingProperties(filterBuilder, key, properties); 258 return filterBuilder; 259 } 260 261 private AppenderRefComponentBuilder createAppenderRef(ConfigurationBuilder<PropertiesConfiguration> builder, 262 String key, Properties properties) { 263 String ref = properties.getProperty("ref"); 264 if (Strings.isEmpty(ref)) { 265 throw new ConfigurationException("No ref attribute provided for AppenderRef " + key); 266 } 267 properties.remove("ref"); 268 AppenderRefComponentBuilder appenderRefBuilder = builder.newAppenderRef(ref); 269 String level = properties.getProperty("level"); 270 if (!Strings.isEmpty(level)) { 271 appenderRefBuilder.addAttribute("level", level); 272 } 273 String filters = properties.getProperty("filters"); 274 if (filters != null) { 275 properties.remove("filters"); 276 String[] filterNames = filters.split(","); 277 for (String filterName : filterNames) { 278 filterName = filterName.trim(); 279 Properties filterProps = PropertiesUtil.extractSubset(properties, "filter." + filterName); 280 appenderRefBuilder.add(createFilter(builder, filterName, filterProps)); 281 } 282 } 283 return appenderRefBuilder; 284 } 285 286 private LoggerComponentBuilder createLogger(ConfigurationBuilder<PropertiesConfiguration> builder, String key, 287 Properties properties) { 288 String name = properties.getProperty(CONFIG_NAME); 289 if (Strings.isEmpty(name)) { 290 throw new ConfigurationException("No name attribute provided for Logger " + key); 291 } 292 properties.remove(CONFIG_NAME); 293 String level = properties.getProperty("level"); 294 if (level != null) { 295 properties.remove("level"); 296 } 297 LoggerComponentBuilder loggerBuilder; 298 String type = properties.getProperty(CONFIG_TYPE); 299 if (type != null) { 300 if (type.equalsIgnoreCase("asyncLogger")) { 301 loggerBuilder = builder.newAsyncLogger(name, level); 302 } else { 303 throw new ConfigurationException("Unknown Logger type " + type + " for Logger " + name); 304 } 305 } else { 306 loggerBuilder = builder.newLogger(name, level); 307 } 308 String appenderRefs = properties.getProperty("appenderRefs"); 309 if (appenderRefs != null) { 310 properties.remove("appenderRefs"); 311 String[] refNames = appenderRefs.split(","); 312 for (String appenderRef : refNames) { 313 appenderRef = appenderRef.trim(); 314 Properties refProps = PropertiesUtil.extractSubset(properties, "appenderRef." + appenderRef); 315 loggerBuilder.add(createAppenderRef(builder, appenderRef, refProps)); 316 } 317 } 318 String filters = properties.getProperty("filters"); 319 if (filters != null) { 320 properties.remove("filters"); 321 String[] filterNames = filters.split(","); 322 for (String filterName : filterNames) { 323 filterName = filterName.trim(); 324 Properties filterProps = PropertiesUtil.extractSubset(properties, "filter." + filterName); 325 loggerBuilder.add(createFilter(builder, filterName, filterProps)); 326 } 327 } 328 String additivity = properties.getProperty("additivity"); 329 if (!Strings.isEmpty(additivity)) { 330 loggerBuilder.addAttribute("additivity", additivity); 331 } 332 return loggerBuilder; 333 } 334 335 private RootLoggerComponentBuilder createRootLogger(ConfigurationBuilder<PropertiesConfiguration> builder, 336 Properties properties) { 337 String level = properties.getProperty("level"); 338 if (level != null) { 339 properties.remove("level"); 340 } 341 RootLoggerComponentBuilder loggerBuilder; 342 String type = properties.getProperty(CONFIG_TYPE); 343 if (type != null) { 344 if (type.equalsIgnoreCase("asyncRoot")) { 345 loggerBuilder = builder.newAsyncRootLogger(level); 346 } else { 347 throw new ConfigurationException("Unknown Logger type for root logger" + type); 348 } 349 } else { 350 loggerBuilder = builder.newRootLogger(level); 351 } 352 String appenderRefs = properties.getProperty("appenderRefs"); 353 if (appenderRefs != null) { 354 properties.remove("appenderRefs"); 355 String[] refNames = appenderRefs.split(","); 356 for (String appenderRef : refNames) { 357 appenderRef = appenderRef.trim(); 358 Properties refProps = PropertiesUtil.extractSubset(properties, "appenderRef." + appenderRef); 359 loggerBuilder.add(createAppenderRef(builder, appenderRef, refProps)); 360 } 361 } 362 String filters = properties.getProperty("filters"); 363 if (filters != null) { 364 properties.remove("filters"); 365 String[] filterNames = filters.split(","); 366 for (String filterName : filterNames) { 367 filterName = filterName.trim(); 368 Properties filterProps = PropertiesUtil.extractSubset(properties, "filter." + filterName); 369 loggerBuilder.add(createFilter(builder, filterName, filterProps)); 370 } 371 } 372 return loggerBuilder; 373 } 374 375 private LayoutComponentBuilder createLayout(ConfigurationBuilder<PropertiesConfiguration> builder, 376 String appenderName, Properties properties) { 377 String type = properties.getProperty(CONFIG_TYPE); 378 if (Strings.isEmpty(type)) { 379 throw new ConfigurationException("No type attribute provided for Layout on Appender " + appenderName); 380 } 381 properties.remove(CONFIG_TYPE); 382 LayoutComponentBuilder layoutBuilder = builder.newLayout(type); 383 processRemainingProperties(layoutBuilder, appenderName, properties); 384 return layoutBuilder; 385 } 386 387 private <B extends ComponentBuilder<B>> ComponentBuilder<B> createComponent(ComponentBuilder<?> parent, String key, 388 Properties properties) { 389 String name = properties.getProperty(CONFIG_NAME); 390 if (name != null) { 391 properties.remove(CONFIG_NAME); 392 } 393 String type = properties.getProperty(CONFIG_TYPE); 394 if (Strings.isEmpty(type)) { 395 throw new ConfigurationException("No type attribute provided for component " + key); 396 } 397 properties.remove(CONFIG_TYPE); 398 ComponentBuilder<B> componentBuilder = parent.getBuilder().newComponent(name, type); 399 processRemainingProperties(componentBuilder, name, properties); 400 return componentBuilder; 401 } 402 403 private void processRemainingProperties(ComponentBuilder<?> builder, String name, Properties properties) { 404 while (properties.size() > 0) { 405 String propertyName = properties.stringPropertyNames().iterator().next(); 406 407 int index = propertyName.indexOf('.'); 408 if (index > 0) { 409 String prefix = propertyName.substring(0, index); 410 Properties componentProperties = PropertiesUtil.extractSubset(properties, prefix); 411 builder.addComponent(createComponent(builder, prefix, componentProperties)); 412 } else { 413 builder.addAttribute(propertyName, properties.getProperty(propertyName)); 414 properties.remove(propertyName); 415 } 416 } 417 } 418}