This is an automated email from the ASF dual-hosted git repository.

ramanathan1504 pushed a commit to branch fix-prop-config-format
in repository https://gitbox.apache.org/repos/asf/logging-log4j2.git

commit 53edd535c2b853eedcb6f829a9cae41712681ad8
Author: Ramanathan <[email protected]>
AuthorDate: Mon Jun 8 21:09:21 2026 +0530

    Enhance properties configuration for logging, including support for custom 
levels, filters, and appenders
---
 .../properties/PropertiesConfigurationBuilder.java | 259 ++++++++++++++-------
 1 file changed, 172 insertions(+), 87 deletions(-)

diff --git 
a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/properties/PropertiesConfigurationBuilder.java
 
b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/properties/PropertiesConfigurationBuilder.java
index 41f66f977a..52e9c01b94 100644
--- 
a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/properties/PropertiesConfigurationBuilder.java
+++ 
b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/properties/PropertiesConfigurationBuilder.java
@@ -19,9 +19,13 @@ package org.apache.logging.log4j.core.config.properties;
 import java.util.List;
 import java.util.Map;
 import java.util.Properties;
+import java.util.concurrent.TimeUnit;
+import org.apache.logging.log4j.Level;
+import org.apache.logging.log4j.core.Appender;
 import org.apache.logging.log4j.core.LoggerContext;
 import org.apache.logging.log4j.core.config.ConfigurationException;
 import org.apache.logging.log4j.core.config.ConfigurationSource;
+import org.apache.logging.log4j.core.config.LoggerConfig;
 import 
org.apache.logging.log4j.core.config.builder.api.AppenderComponentBuilder;
 import 
org.apache.logging.log4j.core.config.builder.api.AppenderRefComponentBuilder;
 import org.apache.logging.log4j.core.config.builder.api.ComponentBuilder;
@@ -37,6 +41,7 @@ import 
org.apache.logging.log4j.core.config.builder.api.ScriptComponentBuilder;
 import 
org.apache.logging.log4j.core.config.builder.api.ScriptFileComponentBuilder;
 import 
org.apache.logging.log4j.core.filter.AbstractFilter.AbstractFilterBuilder;
 import org.apache.logging.log4j.core.util.Builder;
+import org.apache.logging.log4j.core.util.Integers;
 import org.apache.logging.log4j.util.PropertiesUtil;
 import org.apache.logging.log4j.util.Strings;
 
@@ -83,82 +88,134 @@ public class PropertiesConfigurationBuilder extends 
ConfigurationBuilderFactory
                 builder.addRootProperty(key, rootProperties.getProperty(key));
             }
         }
-        final Properties rootLoggerSubset = 
PropertiesUtil.extractSubset(rootProperties, "rootLogger");
-        if (rootLoggerSubset.size() > 0) {
-            builder.add(createRootLogger(rootLoggerSubset));
-        }
-        final Map<String, Properties> loggers =
-                
PropertiesUtil.partitionOnCommonPrefixes(PropertiesUtil.extractSubset(rootProperties,
 "logger"));
-        for (final Map.Entry<String, Properties> entry : loggers.entrySet()) {
-            final LoggerComponentBuilder loggerBuilder = 
createLogger(entry.getKey(), entry.getValue());
-            if (loggerBuilder != null) {
-                builder.add(loggerBuilder);
+        
builder.setStatusLevel(Level.toLevel(rootProperties.getProperty(STATUS_KEY), 
Level.ERROR))
+                .setShutdownHook(rootProperties.getProperty(SHUTDOWN_HOOK))
+                .setShutdownTimeout(
+                        
Long.parseLong(rootProperties.getProperty(SHUTDOWN_TIMEOUT, "0")), 
TimeUnit.MILLISECONDS)
+                .setDestination(rootProperties.getProperty(DEST))
+                .setPackages(rootProperties.getProperty(PACKAGES))
+                .setConfigurationName(rootProperties.getProperty(CONFIG_NAME))
+                
.setMonitorInterval(rootProperties.getProperty(MONITOR_INTERVAL, "0"))
+                .setAdvertiser(rootProperties.getProperty(ADVERTISER_KEY));
+
+        final Properties propertyPlaceholders = 
PropertiesUtil.extractSubset(rootProperties, "property");
+        for (final String key : propertyPlaceholders.stringPropertyNames()) {
+            builder.addProperty(key, propertyPlaceholders.getProperty(key));
+        }
+
+        final Map<String, Properties> scripts =
+                
PropertiesUtil.partitionOnCommonPrefixes(PropertiesUtil.extractSubset(rootProperties,
 "script"));
+        for (final Map.Entry<String, Properties> entry : scripts.entrySet()) {
+            final Properties scriptProps = entry.getValue();
+            final String type = (String) scriptProps.remove("type");
+            if (type == null) {
+                throw new ConfigurationException("No type provided for script 
- must be Script or ScriptFile");
             }
-        }
-        final Map<String, Properties> appenders =
-                
PropertiesUtil.partitionOnCommonPrefixes(PropertiesUtil.extractSubset(rootProperties,
 "appender"));
-        for (final Map.Entry<String, Properties> entry : appenders.entrySet()) 
{
-            final AppenderComponentBuilder appenderBuilder = 
createAppender(entry.getKey(), entry.getValue());
-            if (appenderBuilder != null) {
-                builder.add(appenderBuilder);
+            if (type.equalsIgnoreCase("script")) {
+                builder.add(createScript(scriptProps));
+            } else {
+                builder.add(createScriptFile(scriptProps));
             }
         }
-        final Map<String, Properties> filters =
-                
PropertiesUtil.partitionOnCommonPrefixes(PropertiesUtil.extractSubset(rootProperties,
 "filter"));
-        for (final Map.Entry<String, Properties> entry : filters.entrySet()) {
-            builder.add(createFilter(entry.getKey(), entry.getValue()));
+
+        final Properties levelProps = 
PropertiesUtil.extractSubset(rootProperties, "customLevel");
+        if (levelProps.size() > 0) {
+            for (final String key : levelProps.stringPropertyNames()) {
+                builder.add(builder.newCustomLevel(key, 
Integers.parseInt(levelProps.getProperty(key))));
+            }
         }
-        final String loggerProp = rootProperties.getProperty("loggers");
-        if (loggerProp != null) {
-            final String[] parts = loggerProp.split(",");
-            for (final String logger : parts) {
-                final String name = logger.trim();
-                final Properties sub = 
PropertiesUtil.extractSubset(rootProperties, "logger." + name);
-                final String levelAndRefs = sub.getProperty("");
-                if (levelAndRefs != null) {
-                    sub.remove("");
-                    final String[] refParts = levelAndRefs.split(",");
-                    final String level = refParts[0].trim();
-                    final LoggerComponentBuilder loggerBuilder = 
builder.newLogger(name, level);
-                    for (int i = 1; i < refParts.length; i++) {
-                        
loggerBuilder.add(builder.newAppenderRef(refParts[i].trim()));
-                    }
-                    addLoggersToComponent(loggerBuilder, sub);
-                    addFiltersToComponent(loggerBuilder, sub);
-                    builder.add(loggerBuilder);
-                } else {
-                    final LoggerComponentBuilder loggerBuilder = 
createLogger(name, sub);
-                    if (loggerBuilder != null) {
-                        builder.add(loggerBuilder);
-                    }
+
+        final String filterProp = rootProperties.getProperty("filters");
+        if (filterProp != null) {
+            final String[] filterNames = filterProp.split(",");
+            for (final String filterName : filterNames) {
+                final String name = filterName.trim();
+                final FilterComponentBuilder filterBuilder =
+                        createFilter(name, 
PropertiesUtil.extractSubset(rootProperties, "filter." + name));
+                if (filterBuilder != null) {
+                    builder.add(filterBuilder);
+                }
+            }
+            removeDefinedButUnusedProperties("filter");
+        } else {
+            final Map<String, Properties> filters =
+                    
PropertiesUtil.partitionOnCommonPrefixes(PropertiesUtil.extractSubset(rootProperties,
 "filter"));
+            for (final Map.Entry<String, Properties> entry : 
filters.entrySet()) {
+                final FilterComponentBuilder filterBuilder =
+                        createFilter(entry.getKey().trim(), entry.getValue());
+                if (filterBuilder != null) {
+                    builder.add(filterBuilder);
                 }
             }
         }
+
         final String appenderProp = rootProperties.getProperty("appenders");
         if (appenderProp != null) {
-            final String[] parts = appenderProp.split(",");
-            for (final String appender : parts) {
-                final String name = appender.trim();
-                final Properties sub = 
PropertiesUtil.extractSubset(rootProperties, "appender." + name);
-                final AppenderComponentBuilder appenderBuilder = 
createAppender(name, sub);
+            final String[] appenderNames = appenderProp.split(",");
+            for (final String appenderName : appenderNames) {
+                final String name = appenderName.trim();
+                final AppenderComponentBuilder appenderBuilder = 
createAppender(
+                        appenderName.trim(), 
PropertiesUtil.extractSubset(rootProperties, "appender." + name));
+                if (appenderBuilder != null) {
+                    builder.add(appenderBuilder);
+                }
+            }
+            removeDefinedButUnusedProperties(Appender.ELEMENT_TYPE);
+        } else {
+            final Map<String, Properties> appenders = 
PropertiesUtil.partitionOnCommonPrefixes(
+                    PropertiesUtil.extractSubset(rootProperties, 
Appender.ELEMENT_TYPE));
+            for (final Map.Entry<String, Properties> entry : 
appenders.entrySet()) {
+                final AppenderComponentBuilder appenderBuilder =
+                        createAppender(entry.getKey().trim(), 
entry.getValue());
                 if (appenderBuilder != null) {
                     builder.add(appenderBuilder);
                 }
             }
         }
-        final String filterProp = rootProperties.getProperty("filters");
-        if (filterProp != null) {
-            final String[] parts = filterProp.split(",");
-            for (final String filter : parts) {
-                final String name = filter.trim();
-                final Properties sub = 
PropertiesUtil.extractSubset(rootProperties, "filter." + name);
-                final FilterComponentBuilder filterBuilder = 
createFilter(name, sub);
-                if (filterBuilder != null) {
-                    builder.add(filterBuilder);
+
+        final String loggerProp = rootProperties.getProperty("loggers");
+        if (loggerProp != null) {
+            final String[] loggerNames = loggerProp.split(",");
+            for (final String loggerName : loggerNames) {
+                final String name = loggerName.trim();
+                if (!name.equals(LoggerConfig.ROOT)) {
+                    final LoggerComponentBuilder loggerBuilder =
+                            createLogger(name, 
PropertiesUtil.extractSubset(rootProperties, "logger." + name));
+                    if (loggerBuilder != null) {
+                        builder.add(loggerBuilder);
+                    }
+                }
+            }
+            removeDefinedButUnusedProperties("logger");
+        } else {
+            final Map<String, Properties> loggers = 
PropertiesUtil.partitionOnCommonPrefixes(
+                    PropertiesUtil.extractSubset(rootProperties, "logger"), 
true);
+            for (final Map.Entry<String, Properties> entry : 
loggers.entrySet()) {
+                final String name = entry.getKey().trim();
+                if (!name.equals(LoggerConfig.ROOT)) {
+                    final LoggerComponentBuilder loggerBuilder = 
createLogger(name, entry.getValue());
+                    if (loggerBuilder != null) {
+                        builder.add(loggerBuilder);
+                    }
                 }
             }
         }
-        return builder.build();
+
+        final String rootProp = rootProperties.getProperty("rootLogger");
+        final Properties props = PropertiesUtil.extractSubset(rootProperties, 
"rootLogger");
+        if (rootProp != null) {
+            props.setProperty("", rootProp);
+            rootProperties.remove("rootLogger");
+        }
+        if (props.size() > 0) {
+            builder.add(createRootLogger(props));
+        }
+
+        processRemainingProperties(builder, rootProperties);
+
+        builder.setLoggerContext(loggerContext);
+
+        return builder.build(false);
     }
 
     private void removeDefinedButUnusedProperties(final String prefix) {
@@ -174,8 +231,10 @@ public class PropertiesConfigurationBuilder extends 
ConfigurationBuilderFactory
             if (index > 0) {
                 final String prefix = propertyName.substring(0, index);
                 final Properties componentProperties = 
PropertiesUtil.extractSubset(properties, prefix);
-                ComponentBuilder<?> componentBuilder = 
createComponent(builder, prefix, componentProperties);
-                builder.addComponent(componentBuilder);
+                if (componentProperties.containsKey("type")) {
+                    ComponentBuilder<?> componentBuilder = 
createComponent(builder, prefix, componentProperties);
+                    builder.addComponent(componentBuilder);
+                }
             } else {
                 properties.remove(propertyName);
             }
@@ -230,7 +289,7 @@ public class PropertiesConfigurationBuilder extends 
ConfigurationBuilderFactory
                 }
                 properties.clear();
                 properties.putAll(flatProperties);
-                properties.remove(CONFIG_NAME);
+                properties.remove(CONFIG_NAME); // Remove the flattened "name" 
key
             }
         }
 
@@ -242,7 +301,13 @@ public class PropertiesConfigurationBuilder extends 
ConfigurationBuilderFactory
             return null;
         }
         final AppenderComponentBuilder appenderBuilder = 
builder.newAppender(name, type);
+        addFiltersToComponent(appenderBuilder, properties);
+        final Properties layoutProps = 
PropertiesUtil.extractSubset(properties, "layout");
+        if (layoutProps.size() > 0) {
+            appenderBuilder.add(createLayout(name, layoutProps));
+        }
 
+        // Clean up keys processed by addLoggersToComponent and 
addFiltersToComponent
         final java.util.List<String> keysToRemove = new 
java.util.ArrayList<>();
         for (final String propName : properties.stringPropertyNames()) {
             if (propName.startsWith("appenderRef") || 
propName.startsWith("filter")) {
@@ -259,7 +324,7 @@ public class PropertiesConfigurationBuilder extends 
ConfigurationBuilderFactory
     private FilterComponentBuilder createFilter(final String key, final 
Properties properties) {
         final String type = (String) properties.remove(CONFIG_TYPE);
         if (Strings.isEmpty(type)) {
-            return null;
+            return null; // Safely ignore duplicate filters with missing types
         }
         final String onMatch = (String) 
properties.remove(AbstractFilterBuilder.ATTR_ON_MATCH);
         final String onMismatch = (String) 
properties.remove(AbstractFilterBuilder.ATTR_ON_MISMATCH);
@@ -281,6 +346,7 @@ public class PropertiesConfigurationBuilder extends 
ConfigurationBuilderFactory
     }
 
     private LoggerComponentBuilder createLogger(final String key, final 
Properties properties) {
+        final String levelAndRefs = properties.getProperty("");
         String name = (String) properties.remove(CONFIG_NAME);
         if (name == null) {
             String prefix = null;
@@ -321,14 +387,25 @@ public class PropertiesConfigurationBuilder extends 
ConfigurationBuilderFactory
         }
         final String location = (String) properties.remove("includeLocation");
         final String level = (String) properties.remove("level");
-        final String type = (String) properties.remove("type");
-        final LoggerComponentBuilder loggerBuilder =
-                type != null ? builder.newLogger(name, type) : 
builder.newLogger(name);
-        if (location != null) {
-            loggerBuilder.addAttribute("includeLocation", location);
-        }
-        if (level != null) {
-            loggerBuilder.addAttribute("level", level);
+        final String type = (String) properties.remove(CONFIG_TYPE);
+        final LoggerComponentBuilder loggerBuilder;
+        boolean includeLocation;
+        if (type != null) {
+            if (type.equalsIgnoreCase("asyncLogger")) {
+                if (location != null) {
+                    includeLocation = Boolean.parseBoolean(location);
+                    loggerBuilder = builder.newAsyncLogger(name, level, 
includeLocation);
+                } else {
+                    loggerBuilder = builder.newAsyncLogger(name, level);
+                }
+            } else {
+                throw new ConfigurationException("Unknown Logger type " + type 
+ " for Logger " + name);
+            }
+        } else if (location != null) {
+            includeLocation = Boolean.parseBoolean(location);
+            loggerBuilder = builder.newLogger(name, level, includeLocation);
+        } else {
+            loggerBuilder = builder.newLogger(name, level);
         }
         addLoggersToComponent(loggerBuilder, properties);
         addFiltersToComponent(loggerBuilder, properties);
@@ -336,6 +413,9 @@ public class PropertiesConfigurationBuilder extends 
ConfigurationBuilderFactory
         if (!Strings.isEmpty(additivity)) {
             loggerBuilder.addAttribute("additivity", additivity);
         }
+        if (levelAndRefs != null) {
+            loggerBuilder.addAttribute("levelAndRefs", levelAndRefs);
+        }
 
         // Clean up keys processed by addLoggersToComponent and 
addFiltersToComponent
         final java.util.List<String> keysToRemove = new 
java.util.ArrayList<>();
@@ -353,27 +433,32 @@ public class PropertiesConfigurationBuilder extends 
ConfigurationBuilderFactory
 
     private RootLoggerComponentBuilder createRootLogger(final Properties 
properties) {
         final String levelAndRefs = properties.getProperty("");
+        final String level = Strings.trimToNull((String) 
properties.remove("level"));
+        final String type = (String) properties.remove(CONFIG_TYPE);
+        final String location = (String) properties.remove("includeLocation");
+        final boolean includeLocation;
         final RootLoggerComponentBuilder loggerBuilder;
-        if (levelAndRefs != null) {
-            properties.remove("");
-            final String[] parts = levelAndRefs.split(",");
-            final String level = parts[0].trim();
-            loggerBuilder = builder.newRootLogger(level);
-            for (int i = 1; i < parts.length; i++) {
-                loggerBuilder.add(builder.newAppenderRef(parts[i].trim()));
+        if (type != null) {
+            if (type.equalsIgnoreCase("asyncRoot")) {
+                if (location != null) {
+                    includeLocation = Boolean.parseBoolean(location);
+                    loggerBuilder = builder.newAsyncRootLogger(level, 
includeLocation);
+                } else {
+                    loggerBuilder = builder.newAsyncRootLogger(level);
+                }
+            } else {
+                throw new ConfigurationException("Unknown Logger type for root 
logger" + type);
             }
+        } else if (location != null) {
+            includeLocation = Boolean.parseBoolean(location);
+            loggerBuilder = builder.newRootLogger(level, includeLocation);
         } else {
-            loggerBuilder = builder.newRootLogger();
-            final String level = (String) properties.remove("level");
-            if (level != null) {
-                loggerBuilder.addAttribute("level", level);
-            }
-            final String includeLocation = (String) 
properties.remove("includeLocation");
-            if (includeLocation != null) {
-                loggerBuilder.addAttribute("includeLocation", includeLocation);
-            }
+            loggerBuilder = builder.newRootLogger(level);
         }
         addLoggersToComponent(loggerBuilder, properties);
+        if (levelAndRefs != null) {
+            loggerBuilder.addAttribute("levelAndRefs", levelAndRefs);
+        }
         addFiltersToComponent(loggerBuilder, properties);
 
         final List<String> keysToRemove = new java.util.ArrayList<>();

Reply via email to