diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/ConfigurationFactory.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/ConfigurationFactory.java index 14ea97b..5b9feea 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/ConfigurationFactory.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/ConfigurationFactory.java @@ -35,6 +35,9 @@ import java.util.concurrent.locks.ReentrantLock; import org.apache.logging.log4j.Level; import org.apache.logging.log4j.Logger; +import org.apache.logging.log4j.core.config.assembler.api.ConfigurationAssembler; +import org.apache.logging.log4j.core.config.assembler.impl.AssembledConfiguration; +import org.apache.logging.log4j.core.config.assembler.impl.DefaultConfigurationAssembler; import org.apache.logging.log4j.core.config.plugins.util.PluginManager; import org.apache.logging.log4j.core.config.plugins.util.PluginType; import org.apache.logging.log4j.core.lookup.Interpolator; @@ -123,6 +126,18 @@ public abstract class ConfigurationFactory { private static final Lock LOCK = new ReentrantLock(); /** + * Returns the default ConfigurationAssembler to construct Log4j configurations. + * @return The ConfigurationAssembler. + */ + public static ConfigurationAssembler getConfigurationAssembler() { + return new DefaultConfigurationAssembler<>(); + } + + public static ConfigurationAssembler getConfigurationAssembler(Class clazz) { + return new DefaultConfigurationAssembler(clazz); + } + + /** * Returns the ConfigurationFactory. * @return the ConfigurationFactory. */ diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/assembler/api/AppenderAssembler.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/assembler/api/AppenderAssembler.java new file mode 100644 index 0000000..f3c1b1d --- /dev/null +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/assembler/api/AppenderAssembler.java @@ -0,0 +1,43 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache license, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the license for the specific language governing permissions and + * limitations under the license. + */ +package org.apache.logging.log4j.core.config.assembler.api; + +/** + * Assembler for constructing Appenders. + */ +public interface AppenderAssembler extends ComponentAssembler { + + /** + * Add a Layout to the Appender component. + * @param layout The Layout component to add. + * @return this Assembler. + */ + AppenderAssembler addLayout(Component layout); + + /** + * Add a Filter to the Appender component. + * @param filter The Filter to add. + * @return this Assembler. + */ + AppenderAssembler addFilter(Component filter); + + /** + * Return the name of the Appender. + * @return the name of the Appender. + */ + String getName(); +} diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/assembler/api/AppenderRefAssembler.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/assembler/api/AppenderRefAssembler.java new file mode 100644 index 0000000..e4ca7cd --- /dev/null +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/assembler/api/AppenderRefAssembler.java @@ -0,0 +1,30 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache license, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the license for the specific language governing permissions and + * limitations under the license. + */ +package org.apache.logging.log4j.core.config.assembler.api; + +/** + * Assembler for constructing AppenderRefs. + */ +public interface AppenderRefAssembler extends ComponentAssembler { + + /** + * Add a Filter to the Appender component. + * @param filter The Filter to add. + * @return this Assembler. + */ + AppenderRefAssembler addFilter(Component filter); +} diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/assembler/api/Assembler.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/assembler/api/Assembler.java new file mode 100644 index 0000000..7cb9e39 --- /dev/null +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/assembler/api/Assembler.java @@ -0,0 +1,37 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.logging.log4j.core.config.assembler.api; + +/** + * Gathers information in preparation for creating components. These assemblers are primarily useful for + * aggregating the information that will be used to create a Configuration. + * + * @param the Component class this is a builder for. + */ +public interface Assembler { + + /** + * Builds the plugin object after all configuration has been set. This will use default values for any + * unspecified attributes for the plugin. + * + * @return the configured plugin instance. + * @throws org.apache.logging.log4j.core.config.ConfigurationException if there was an error building the plugin + * object. + */ + T assemble(); +} diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/assembler/api/Component.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/assembler/api/Component.java new file mode 100644 index 0000000..cd12b39 --- /dev/null +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/assembler/api/Component.java @@ -0,0 +1,80 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache license, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the license for the specific language governing permissions and + * limitations under the license. + */ +package org.apache.logging.log4j.core.config.assembler.api; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * Container for assembling Configurations. This class is not normally directly manipulated by users + * of the Assembler API. + */ +public class Component { + + private final Map attributes = new HashMap<>(); + private final List components = new ArrayList<>(); + private final String pluginType; + private final String value; + + public Component(String pluginType) { + this(pluginType, null, null); + } + + public Component(String pluginType, String name) { + this(pluginType, name, null); + } + + public Component(String pluginType, String name, String value) { + this.pluginType = pluginType; + this.value = value; + if (name != null && name.length() > 0) { + attributes.put("name", name); + } + } + + public Component() { + this.pluginType = null; + this.value = null; + } + + + public String addAttribute(String key, String value) { + return attributes.put(key, value); + } + + public void addComponent(Component component) { + components.add(component); + } + + public Map getAttributes() { + return attributes; + } + + public List getComponents() { + return components; + } + + public String getPluginType() { + return pluginType; + } + + public String getValue() { + return value; + } + } diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/assembler/api/ComponentAssembler.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/assembler/api/ComponentAssembler.java new file mode 100644 index 0000000..87b4782 --- /dev/null +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/assembler/api/ComponentAssembler.java @@ -0,0 +1,53 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache license, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the license for the specific language governing permissions and + * limitations under the license. + */ +package org.apache.logging.log4j.core.config.assembler.api; + +import org.apache.logging.log4j.core.config.Configuration; + +/** + * Assembler for arbitrary components and the base class for the provided components. + */ +@SuppressWarnings("rawtypes") +public interface ComponentAssembler extends Assembler { + + /** + * Add an attribute to the component. + * @param key The attribute key. + * @param value The value of the attribute. + * @return The ComponentAssembler. + */ + T addAttribute(String key, String value); + + /** + * Add a sub component. + * @param component The sub component to add. + * @return The ComponentAssembler. + */ + T addSubComponent(Component component); + + /** + * Return the name of the component, if any. + * @return The components name or null if it doesn't have one. + */ + String getName(); + + /** + * Retrieve the ConfigurationAssembler. + * @return The ConfiguratonAssembler. + */ + ConfigurationAssembler getAssembler(); +} diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/assembler/api/CompositeFilterAssembler.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/assembler/api/CompositeFilterAssembler.java new file mode 100644 index 0000000..f495a08 --- /dev/null +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/assembler/api/CompositeFilterAssembler.java @@ -0,0 +1,30 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache license, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the license for the specific language governing permissions and + * limitations under the license. + */ +package org.apache.logging.log4j.core.config.assembler.api; + +/** + * Wraps multiple filter assemblers. + */ +public interface CompositeFilterAssembler extends ComponentAssembler { + + /** + * Add a FilterComponent. + * @param filter The FilterComponent to add. + * @return The CompositeFilterAssembler. + */ + CompositeFilterAssembler addFilter(Component filter); +} diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/assembler/api/ConfigurationAssembler.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/assembler/api/ConfigurationAssembler.java new file mode 100644 index 0000000..7c704d5 --- /dev/null +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/assembler/api/ConfigurationAssembler.java @@ -0,0 +1,209 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache license, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the license for the specific language governing permissions and + * limitations under the license. + */ +package org.apache.logging.log4j.core.config.assembler.api; + +import org.apache.logging.log4j.Level; +import org.apache.logging.log4j.core.config.Configuration; +import org.apache.logging.log4j.core.config.ConfigurationSource; + +/** + * Interface for assembling logging configurations. + */ +public interface ConfigurationAssembler extends Assembler { + + /** + * Set the name of the configuration. + * + * @param name the name of the {@link Configuration}. By default is {@code "Constructed"}. + * @return this Assembler instance. + */ + ConfigurationAssembler setConfigurationName(String name); + + /** + * Set the configuration source, if one exists. + * @param configurationSource the ConfigurationSource. + * @return this Assembler instance. + */ + ConfigurationAssembler setConfigurationSource(ConfigurationSource configurationSource); + + /** + * Set the level of the StatusLogger. + * @param level The logging level. + * @return this Assembler instance. + */ + ConfigurationAssembler setStatusLevel(Level level); + + /** + * Set whether the logging should include constructing Plugins. + * @param verbosity "disable" will hide messages from plugin construction. + * @return this Assembler instance. + */ + ConfigurationAssembler setVerbosity(String verbosity); + + /** + * Set the list of packages to search for plugins. + * @param packages The comma separated list of packages. + * @return this Assembler instance. + */ + ConfigurationAssembler setPackages(String packages); + + /** + * Set whether the shutdown hook should be disabled. + * @param flag "disable" will prevent the shutdown hook from being set. + * @return this Assembler instance. + */ + ConfigurationAssembler setShutdownHook(String flag); + + /** + * Sets the interval at which the configuration file should be checked for changes. + * @param intervalSeconds The number of seconds that should pass between checks of the configuration file. + * @return this Assembler instance. + */ + ConfigurationAssembler setMonitorInterval(String intervalSeconds); + + /** + * Adds an AppenderComponent. + * @param component The component to add. + * @return this Assembler instance. + */ + ConfigurationAssembler addAppender(Component component); + + /** + * Adds a CustomLevel component. + * @param component The component to add. + * @return this Assembler instance. + */ + ConfigurationAssembler addCustomLevel(Component component); + + /** + * Add a Logger component. + * @param component The Logger component. + * @return this Assembler instance. + */ + ConfigurationAssembler addLogger(Component component); + + /** + * Add the root Logger component. + * @param component The root Logger component. + * @return this Assembler instance. + */ + ConfigurationAssembler addRootLogger(Component component); + + /** + * Add a Filter component. + * @param component The Filter component. + * @return this Assembler instance. + */ + ConfigurationAssembler addFilter(Component component); + + /** + * Add a Property key and value. + * @param key The property key. + * @param value The property value. + * @return this Assembler instance. + */ + ConfigurationAssembler addProperty(String key, String value); + + /** + * Returns an Assembler for creating Appenders. + * @param name The name of the Appender. + * @param type The Plugin type of the Appender. + * @return the AppenderAssembler. + */ + AppenderAssembler getAppenderAssembler(String name, String type); + + + /** + * Returns an Assembler for creating AppenderRefs. + * @param ref The name of the Appender being referenced. + * @return the AppenderRefAssembler. + */ + AppenderRefAssembler getAppenderRefAssembler(String ref); + + /** + * Returns an Assembler for creating generic components. + * @param name The name of the component (may be null). + * @param type The Plugin type of the component. + * @return The ComponentAssembler. + */ + @SuppressWarnings("rawtypes") + ComponentAssembler getComponentAssembler(String name, String type); + + /** + * Returns an Assembler for creating generic components. + * @param name The name of the component (may be null). + * @param type The Plugin type of the component. + * @param value The value of the component. + * @return The ComponentAssembler. + */ + @SuppressWarnings("rawtypes") + ComponentAssembler getComponentAssembler(String name, String type, String value); + + /** + * Returns an Asssembler for creating CustomLevels + * @param name The name of the custom level. + * @param level The String representation of the integer value of the level. + * @return The CustomLevelAssembler. + */ + CustomLevelAssembler getCustomLevelAssembler(String name, String level); + /** + * Returns an Asssembler for creating Filters. + * @param type The Plugin type of the Filter. + * @param onMatch "ACCEPT", "DENY", or "NEUTRAL" + * @param onMisMatch "ACCEPT", "DENY", or "NEUTRAL" + * @return The FilterAssembler. + */ + FilterAssembler getFilterAssembler(String type, String onMatch, String onMisMatch); + + /** + * Returns an Assembler for creating Layouts. + * @param type The Plugin type of the Layout. + * @return The LayoutAssembler. + */ + LayoutAssembler getLayoutAssembler(String type); + + /** + * Returns an Assembler for creating Loggers. + * @param name The name of the Logger. + * @param level The logging Level to be assigned to the Logger. + * @return The LoggerAssembler. + */ + LoggerAssembler getLoggerAssembler(String name, String level); + + /** + * Returns an Assembler for creating Async Loggers. + * @param name The name of the Logger. + * @param level The logging Level to be assigned to the Logger. + * @return The LoggerAssembler. + */ + LoggerAssembler getAsyncLoggerAssembler(String name, String level); + + /** + * Returns an Assembler for creating the root Logger. + * @param level The logging Level to be assigned to the root Logger. + * @return The RootLoggerAssembler. + */ + RootLoggerAssembler getRootLoggerAssembler(String level); + + + /** + * Returns an Assembler for creating the async root Logger. + * @param level The logging Level to be assigned to the root Logger. + * @return The RootLoggerAssembler. + */ + RootLoggerAssembler getAsyncRootLoggerAssembler(String level); +} diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/assembler/api/CustomLevelAssembler.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/assembler/api/CustomLevelAssembler.java new file mode 100644 index 0000000..c37ab9e --- /dev/null +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/assembler/api/CustomLevelAssembler.java @@ -0,0 +1,24 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache license, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the license for the specific language governing permissions and + * limitations under the license. + */ +package org.apache.logging.log4j.core.config.assembler.api; + +/** + * Assembler for constructing Filters + */ +public interface CustomLevelAssembler extends ComponentAssembler { + +} diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/assembler/api/FilterAssembler.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/assembler/api/FilterAssembler.java new file mode 100644 index 0000000..cf95228 --- /dev/null +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/assembler/api/FilterAssembler.java @@ -0,0 +1,24 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache license, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the license for the specific language governing permissions and + * limitations under the license. + */ +package org.apache.logging.log4j.core.config.assembler.api; + +/** + * Assembler for constructing Filters + */ +public interface FilterAssembler extends ComponentAssembler { + +} diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/assembler/api/LayoutAssembler.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/assembler/api/LayoutAssembler.java new file mode 100644 index 0000000..954ea51 --- /dev/null +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/assembler/api/LayoutAssembler.java @@ -0,0 +1,24 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache license, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the license for the specific language governing permissions and + * limitations under the license. + */ +package org.apache.logging.log4j.core.config.assembler.api; + +/** + * Assembler for constructing Layouts + */ +public interface LayoutAssembler extends ComponentAssembler { + +} diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/assembler/api/LoggerAssembler.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/assembler/api/LoggerAssembler.java new file mode 100644 index 0000000..9657222 --- /dev/null +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/assembler/api/LoggerAssembler.java @@ -0,0 +1,37 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache license, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the license for the specific language governing permissions and + * limitations under the license. + */ +package org.apache.logging.log4j.core.config.assembler.api; + +/** + * Assembler for constructing Loggers. + */ +public interface LoggerAssembler extends ComponentAssembler { + + /** + * Add an Appender reference to the Logger component. + * @param ref The name of the Appender. + * @return this Assembler. + */ + LoggerAssembler addAppenderRef(Component ref); + + /** + * Add a Filter to the Logger component. + * @param filter The Filter component to add. + * @return this Assembler. + */ + LoggerAssembler addFilter(Component filter); +} diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/assembler/api/RootLoggerAssembler.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/assembler/api/RootLoggerAssembler.java new file mode 100644 index 0000000..3f880bb --- /dev/null +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/assembler/api/RootLoggerAssembler.java @@ -0,0 +1,37 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache license, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the license for the specific language governing permissions and + * limitations under the license. + */ +package org.apache.logging.log4j.core.config.assembler.api; + +/** + * Assembler for constructing the root Logger. + */ +public interface RootLoggerAssembler extends ComponentAssembler { + + /** + * Add an Appender reference to the Logger component. + * @param ref The name of the Appender. + * @return this Assembler. + */ + RootLoggerAssembler addAppenderRef(Component ref); + + /** + * Add a Filter to the Logger component. + * @param filter The Filter component to add. + * @return this Assembler. + */ + RootLoggerAssembler addFilter(Component filter); +} diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/assembler/impl/AssembledConfiguration.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/assembler/impl/AssembledConfiguration.java new file mode 100644 index 0000000..afdb259 --- /dev/null +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/assembler/impl/AssembledConfiguration.java @@ -0,0 +1,141 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache license, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the license for the specific language governing permissions and + * limitations under the license. + */ +package org.apache.logging.log4j.core.config.assembler.impl; + +import org.apache.logging.log4j.core.config.AbstractConfiguration; +import org.apache.logging.log4j.core.config.ConfigurationSource; +import org.apache.logging.log4j.core.config.FileConfigurationMonitor; +import org.apache.logging.log4j.core.config.Node; +import org.apache.logging.log4j.core.config.Reconfigurable; +import org.apache.logging.log4j.core.config.assembler.api.Component; +import org.apache.logging.log4j.core.config.plugins.util.PluginManager; +import org.apache.logging.log4j.core.config.plugins.util.PluginType; +import org.apache.logging.log4j.core.config.plugins.util.ResolverUtil; +import org.apache.logging.log4j.core.config.status.StatusConfiguration; +import org.apache.logging.log4j.core.util.Patterns; + +import java.io.File; +import java.util.Arrays; +import java.util.List; + +/** + * This is the general version of the Configuration created by the Assembler. It may be extended to + * enhance its functionality. + */ +public class AssembledConfiguration extends AbstractConfiguration { + private static final long serialVersionUID = -3071897330997405132L; + private static final String[] VERBOSE_CLASSES = new String[] { ResolverUtil.class.getName() }; + private final StatusConfiguration statusConfig; + protected Component root; + private Component loggersComponent; + private Component appendersComponent; + private Component filtersComponent; + private Component propertiesComponent; + private Component customLevelsComponent; + + public AssembledConfiguration(ConfigurationSource source, Component rootComponent) { + super(source); + statusConfig = new StatusConfiguration().withVerboseClasses(VERBOSE_CLASSES).withStatus(getDefaultStatus()); + for (Component component : rootComponent.getComponents()) { + switch (component.getPluginType()) { + case "Loggers": { + loggersComponent = component; + break; + } + case "Appenders": { + appendersComponent = component; + break; + } + case "Filters": { + filtersComponent = component; + break; + } + case "Properties": { + propertiesComponent = component; + break; + } + case "CustomLevels": { + customLevelsComponent = component; + break; + } + } + } + root = rootComponent; + } + + @Override + public void setup() { + List children = rootNode.getChildren(); + if (propertiesComponent.getComponents().size() > 0) { + children.add(convertToNode(rootNode, propertiesComponent)); + } + if (customLevelsComponent.getComponents().size() > 0) { + children.add(convertToNode(rootNode, customLevelsComponent)); + } + children.add(convertToNode(rootNode, loggersComponent)); + children.add(convertToNode(rootNode, appendersComponent)); + if (filtersComponent.getComponents().size() > 0) { + if (filtersComponent.getComponents().size() == 1) { + children.add(convertToNode(rootNode, filtersComponent.getComponents().get(0))); + } else { + children.add(convertToNode(rootNode, filtersComponent)); + } + } + root = null; + } + + public StatusConfiguration getStatusConfiguration() { + return statusConfig; + } + + public void setPluginPackages(String packages) { + pluginPackages.addAll(Arrays.asList(packages.split(Patterns.COMMA_SEPARATOR))); + } + + public void setShutdownHook(String flag) { + isShutdownHookEnabled = !"disable".equalsIgnoreCase(flag); + } + + public void setMonitorInterval(int intervalSeconds) { + if (this instanceof Reconfigurable && intervalSeconds > 0) { + ConfigurationSource configSource = getConfigurationSource(); + if (configSource != null) { + final File configFile = configSource.getFile(); + if (intervalSeconds > 0 && configFile != null) { + monitor = new FileConfigurationMonitor((Reconfigurable)this, configFile, listeners, intervalSeconds); + } + } + } + } + + public PluginManager getPluginManager() { + return pluginManager; + } + + protected Node convertToNode(Node parent, Component component) { + String name = component.getPluginType(); + PluginType pluginType = pluginManager.getPluginType(name); + Node node = new Node(parent, name, pluginType); + node.getAttributes().putAll(component.getAttributes()); + node.setValue(component.getValue()); + List children = node.getChildren(); + for (Component child : component.getComponents()) { + children.add(convertToNode(node, child)); + } + return node; + } +} diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/assembler/impl/DefaultAppenderAssembler.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/assembler/impl/DefaultAppenderAssembler.java new file mode 100644 index 0000000..afc6fbb --- /dev/null +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/assembler/impl/DefaultAppenderAssembler.java @@ -0,0 +1,43 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache license, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the license for the specific language governing permissions and + * limitations under the license. + */ +package org.apache.logging.log4j.core.config.assembler.impl; + +import org.apache.logging.log4j.core.config.Configuration; +import org.apache.logging.log4j.core.config.assembler.api.AppenderAssembler; +import org.apache.logging.log4j.core.config.assembler.api.Component; + +/** + * Holds the Appender Component attributes and subcomponents. + */ +public class DefaultAppenderAssembler extends DefaultComponentAssembler implements AppenderAssembler { + + public DefaultAppenderAssembler(DefaultConfigurationAssembler assembler, String name, String type) { + super(assembler, name, type); + } + + @Override + public AppenderAssembler addLayout(Component layout) { + addSubComponent(layout); + return this; + } + + @Override + public AppenderAssembler addFilter(Component filter) { + addSubComponent(filter); + return this; + } +} diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/assembler/impl/DefaultAppenderRefAssembler.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/assembler/impl/DefaultAppenderRefAssembler.java new file mode 100644 index 0000000..a1ed765 --- /dev/null +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/assembler/impl/DefaultAppenderRefAssembler.java @@ -0,0 +1,40 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache license, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the license for the specific language governing permissions and + * limitations under the license. + */ +package org.apache.logging.log4j.core.config.assembler.impl; + +import org.apache.logging.log4j.core.config.Configuration; +import org.apache.logging.log4j.core.config.assembler.api.AppenderAssembler; +import org.apache.logging.log4j.core.config.assembler.api.AppenderRefAssembler; +import org.apache.logging.log4j.core.config.assembler.api.Component; + +/** + * Holds the Appender Component attributes and subcomponents. + */ +public class DefaultAppenderRefAssembler extends DefaultComponentAssembler implements AppenderRefAssembler { + + public DefaultAppenderRefAssembler(DefaultConfigurationAssembler assembler, String ref) { + super(assembler, "AppenderRef"); + addAttribute("ref", ref); + } + + + @Override + public AppenderRefAssembler addFilter(Component filter) { + addSubComponent(filter); + return this; + } +} diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/assembler/impl/DefaultComponentAssembler.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/assembler/impl/DefaultComponentAssembler.java new file mode 100644 index 0000000..5bce5ca --- /dev/null +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/assembler/impl/DefaultComponentAssembler.java @@ -0,0 +1,89 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache license, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the license for the specific language governing permissions and + * limitations under the license. + */ +package org.apache.logging.log4j.core.config.assembler.impl; + +import org.apache.logging.log4j.core.config.Configuration; +import org.apache.logging.log4j.core.config.assembler.api.Component; +import org.apache.logging.log4j.core.config.assembler.api.ComponentAssembler; +import org.apache.logging.log4j.core.config.assembler.api.ConfigurationAssembler; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * Generic component that captures attributes and Components in preparation for assembling the Appender's + * Component. + */ +@SuppressWarnings("rawtypes") +public class DefaultComponentAssembler implements ComponentAssembler { + + private ConfigurationAssembler assembler; + private String type; + private Map attributes = new HashMap<>(); + private List components = new ArrayList<>(); + private String name; + private String value; + + public DefaultComponentAssembler(ConfigurationAssembler assembler, String type) { + this(assembler, null, type, null); + } + + public DefaultComponentAssembler(ConfigurationAssembler assembler, String name, String type) { + this(assembler, name, type, null); + } + + public DefaultComponentAssembler(ConfigurationAssembler assembler, String name, String type, String value) { + this.type = type; + this.assembler = assembler; + this.name = name; + this.value = value; + } + + @Override + @SuppressWarnings("unchecked") + public T addAttribute(String key, String value) { + attributes.put(key, value); + return (T) this; + } + + @Override + @SuppressWarnings("unchecked") + public T addSubComponent(Component component) { + components.add(component); + return (T) this; + } + + @Override + public String getName() { + return name; + } + + @Override + public ConfigurationAssembler getAssembler() { + return assembler; + } + + @Override + public Component assemble() { + Component component = new Component(type, name, value); + component.getAttributes().putAll(attributes); + component.getComponents().addAll(components); + return component; + } +} diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/assembler/impl/DefaultCompositeFilterAssembler.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/assembler/impl/DefaultCompositeFilterAssembler.java new file mode 100644 index 0000000..b9c051b --- /dev/null +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/assembler/impl/DefaultCompositeFilterAssembler.java @@ -0,0 +1,40 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache license, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the license for the specific language governing permissions and + * limitations under the license. + */ +package org.apache.logging.log4j.core.config.assembler.impl; + +import org.apache.logging.log4j.core.config.Configuration; +import org.apache.logging.log4j.core.config.assembler.api.Component; +import org.apache.logging.log4j.core.config.assembler.api.CompositeFilterAssembler; + +/** + * + */ +public class DefaultCompositeFilterAssembler extends DefaultComponentAssembler implements CompositeFilterAssembler { + + public DefaultCompositeFilterAssembler(DefaultConfigurationAssembler assembler, String onMatch, String onMisMatch) { + super(assembler, "Filters"); + addAttribute("onMatch", onMatch); + addAttribute("onMisMatch", onMisMatch); + } + + @Override + public CompositeFilterAssembler addFilter(Component filter) { + addSubComponent(filter); + return this; + } + +} diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/assembler/impl/DefaultConfigurationAssembler.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/assembler/impl/DefaultConfigurationAssembler.java new file mode 100644 index 0000000..92c2aa3 --- /dev/null +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/assembler/impl/DefaultConfigurationAssembler.java @@ -0,0 +1,287 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache license, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the license for the specific language governing permissions and + * limitations under the license. + */ +package org.apache.logging.log4j.core.config.assembler.impl; + +import org.apache.logging.log4j.Level; +import org.apache.logging.log4j.core.config.Configuration; +import org.apache.logging.log4j.core.config.ConfigurationException; +import org.apache.logging.log4j.core.config.ConfigurationSource; +import org.apache.logging.log4j.core.config.assembler.api.AppenderAssembler; +import org.apache.logging.log4j.core.config.assembler.api.AppenderRefAssembler; +import org.apache.logging.log4j.core.config.assembler.api.Component; +import org.apache.logging.log4j.core.config.assembler.api.ComponentAssembler; +import org.apache.logging.log4j.core.config.assembler.api.ConfigurationAssembler; +import org.apache.logging.log4j.core.config.assembler.api.CustomLevelAssembler; +import org.apache.logging.log4j.core.config.assembler.api.FilterAssembler; +import org.apache.logging.log4j.core.config.assembler.api.LayoutAssembler; +import org.apache.logging.log4j.core.config.assembler.api.LoggerAssembler; +import org.apache.logging.log4j.core.config.assembler.api.RootLoggerAssembler; + +import java.lang.reflect.Constructor; +import java.util.List; + +/** + * + */ +public class DefaultConfigurationAssembler implements ConfigurationAssembler { + + private AssembledConfiguration configuration; + + private final Component root = new Component(); + private Component loggers; + private Component appenders; + private Component filters; + private Component properties; + private Component customLevels; + private final Class clazz; + private ConfigurationSource source; + private int monitorInterval = 0; + private Level level = null; + private String verbosity = null; + private String packages = null; + private String shutdownFlag = null; + + /** + * The key with which Apache Log4j loads the selector class. + * + * @see + * Async Loggers + */ + private static final String LOG4J_ASYNC_LOGGERS = "Log4jContextSelector"; + + public DefaultConfigurationAssembler() { + this(AssembledConfiguration.class); + root.addAttribute("name", "Assembled"); + } + + public DefaultConfigurationAssembler(Class clazz) { + if (clazz == null) { + throw new IllegalArgumentException("A Configuration class must be provided"); + } + this.clazz = clazz; + List components = root.getComponents(); + properties = new Component("Properties"); + components.add(properties); + customLevels = new Component("CustomLevels"); + components.add(customLevels); + filters = new Component("Filters"); + components.add(filters); + appenders = new Component("Appenders"); + components.add(appenders); + loggers = new Component("Loggers"); + components.add(loggers); + } + + /** + * Set the name of the configuration. + * + * @param name the name of the {@link Configuration}. By default is {@code "Assembled"}. + * @return this builder instance + */ + @Override + @SuppressWarnings("unchecked") + public ConfigurationAssembler setConfigurationName(String name) { + root.getAttributes().put("name", name); + return this; + } + + /** + * Set the ConfigurationSource. + * + * @param configurationSource the {@link ConfigurationSource).} + * @return this builder instance + */ + @Override + @SuppressWarnings("unchecked") + public ConfigurationAssembler setConfigurationSource(ConfigurationSource configurationSource) { + source = configurationSource; + return this; + } + + @Override + @SuppressWarnings("unchecked") + public ConfigurationAssembler setMonitorInterval(String intervalSeconds) { + monitorInterval = Integer.parseInt(intervalSeconds); + return this; + } + + @Override + @SuppressWarnings("unchecked") + public ConfigurationAssembler setStatusLevel(Level level) { + this.level = level; + return this; + } + + @Override + @SuppressWarnings("unchecked") + public ConfigurationAssembler setVerbosity(String verbosity) { + this.verbosity = verbosity; + return this; + } + + @Override + @SuppressWarnings("unchecked") + public ConfigurationAssembler setPackages(String packages) { + this.packages = packages; + return this; + } + + @Override + @SuppressWarnings("unchecked") + public ConfigurationAssembler setShutdownHook(String flag) { + this.shutdownFlag = flag; + return this; + } + + @Override + @SuppressWarnings("unchecked") + public ConfigurationAssembler addAppender(Component component) { + appenders.getComponents().add(component); + return this; + } + + @Override + public ConfigurationAssembler addCustomLevel(Component component) { + customLevels.getComponents().add(component); + return this; + } + + @Override + @SuppressWarnings("unchecked") + public ConfigurationAssembler addLogger(Component component) { + for (Component c : loggers.getComponents()) { + if (c.getPluginType().equals("root")) { + throw new ConfigurationException("root Logger was previously defined"); + } + } + loggers.getComponents().add(component); + return this; + } + + @Override + @SuppressWarnings("unchecked") + public ConfigurationAssembler addRootLogger(Component component) { + loggers.getComponents().add(component); + return this; + } + + @Override + @SuppressWarnings("unchecked") + public ConfigurationAssembler addFilter(Component component) { + filters.getComponents().add(component); + return this; + } + + @Override + @SuppressWarnings("unchecked") + public ConfigurationAssembler addProperty(String key, String value) { + properties.addComponent(getComponentAssembler(key, "Property", value).assemble()); + return this; + } + + @Override + public AppenderAssembler getAppenderAssembler(String name, String type) { + return new DefaultAppenderAssembler(this, name, type); + } + + + @Override + public AppenderRefAssembler getAppenderRefAssembler(String ref) { + return new DefaultAppenderRefAssembler(this, ref); + } + + + @Override + @SuppressWarnings({"unchecked", "rawtypes"}) + public ComponentAssembler getComponentAssembler(String name, String type) { + return new DefaultComponentAssembler(this, name, type); + } + + @Override + @SuppressWarnings({"unchecked", "rawtypes"}) + public ComponentAssembler getComponentAssembler(String name, String type, String value) { + return new DefaultComponentAssembler(this, name, type, value); + } + + @Override + public CustomLevelAssembler getCustomLevelAssembler(String name, String level) { + return new DefaultCustomLevelAssembler(this, name, level); + } + + @Override + @SuppressWarnings("rawtypes") + public FilterAssembler getFilterAssembler(String type, String onMatch, String onMisMatch) { + return new DefaultFilterAssembler(this, type, onMatch, onMisMatch); + } + + @Override + public LayoutAssembler getLayoutAssembler(String type) { + return new DefaultLayoutAssembler(this, type); + } + + @Override + public LoggerAssembler getLoggerAssembler(String name, String level) { + return new DefaultLoggerAssembler(this, name, level); + } + + + @Override + public LoggerAssembler getAsyncLoggerAssembler(String name, String level) { + return new DefaultLoggerAssembler(this, name, level, "AsyncLogger"); + } + + @Override + public RootLoggerAssembler getRootLoggerAssembler(String level) { + return new DefaultRootLoggerAssembler(this, level); + } + + @Override + public RootLoggerAssembler getAsyncRootLoggerAssembler(String level) { + return new DefaultRootLoggerAssembler(this, level, "AsyncRoot"); + } + + @Override + @SuppressWarnings({"unchecked", "rawtypes"}) + public T assemble() { + AssembledConfiguration configuration; + try { + if (source == null) { + source = ConfigurationSource.NULL_SOURCE; + } + Constructor constructor = clazz.getConstructor(ConfigurationSource.class, Component.class); + configuration = (AssembledConfiguration) constructor.newInstance(source, root); + configuration.setMonitorInterval(monitorInterval); + if (level != null) { + configuration.getStatusConfiguration().withStatus(level); + } + if (verbosity != null) { + configuration.getStatusConfiguration().withVerbosity(verbosity); + } + if (packages != null) { + configuration.setPluginPackages(packages); + } + if (shutdownFlag != null) { + configuration.setShutdownHook(shutdownFlag); + } + } catch (Exception ex) { + throw new IllegalArgumentException("Invalid Configuration class specified", ex); + } + configuration.getStatusConfiguration().initialize(); + return (T)configuration; + } +} diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/assembler/impl/DefaultCustomLevelAssembler.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/assembler/impl/DefaultCustomLevelAssembler.java new file mode 100644 index 0000000..0dacf95 --- /dev/null +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/assembler/impl/DefaultCustomLevelAssembler.java @@ -0,0 +1,33 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache license, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the license for the specific language governing permissions and + * limitations under the license. + */ +package org.apache.logging.log4j.core.config.assembler.impl; + +import org.apache.logging.log4j.core.config.Configuration; +import org.apache.logging.log4j.core.config.assembler.api.CustomLevelAssembler; + +/** + * + */ +public class DefaultCustomLevelAssembler extends DefaultComponentAssembler implements + CustomLevelAssembler { + + public DefaultCustomLevelAssembler(DefaultConfigurationAssembler assembler, String name, + String level) { + super(assembler, name, "CustomLevel"); + addAttribute("level", level); + } +} diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/assembler/impl/DefaultFilterAssembler.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/assembler/impl/DefaultFilterAssembler.java new file mode 100644 index 0000000..4a2caad --- /dev/null +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/assembler/impl/DefaultFilterAssembler.java @@ -0,0 +1,34 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache license, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the license for the specific language governing permissions and + * limitations under the license. + */ +package org.apache.logging.log4j.core.config.assembler.impl; + +import org.apache.logging.log4j.core.config.Configuration; +import org.apache.logging.log4j.core.config.assembler.api.ComponentAssembler; +import org.apache.logging.log4j.core.config.assembler.api.FilterAssembler; + +/** + * + */ +public class DefaultFilterAssembler extends DefaultComponentAssembler implements FilterAssembler { + + public DefaultFilterAssembler(DefaultConfigurationAssembler assembler, String type, String onMatch, + String onMisMatch) { + super(assembler, type); + addAttribute("onMatch", onMatch); + addAttribute("onMisMatch", onMisMatch); + } +} diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/assembler/impl/DefaultLayoutAssembler.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/assembler/impl/DefaultLayoutAssembler.java new file mode 100644 index 0000000..08da646 --- /dev/null +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/assembler/impl/DefaultLayoutAssembler.java @@ -0,0 +1,30 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache license, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the license for the specific language governing permissions and + * limitations under the license. + */ +package org.apache.logging.log4j.core.config.assembler.impl; + +import org.apache.logging.log4j.core.config.Configuration; +import org.apache.logging.log4j.core.config.assembler.api.LayoutAssembler; + +/** + * + */ +public class DefaultLayoutAssembler extends DefaultComponentAssembler implements LayoutAssembler { + + public DefaultLayoutAssembler(DefaultConfigurationAssembler assembler, String type) { + super(assembler, type); + } +} diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/assembler/impl/DefaultLoggerAssembler.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/assembler/impl/DefaultLoggerAssembler.java new file mode 100644 index 0000000..82e36b9 --- /dev/null +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/assembler/impl/DefaultLoggerAssembler.java @@ -0,0 +1,62 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache license, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the license for the specific language governing permissions and + * limitations under the license. + */ +package org.apache.logging.log4j.core.config.assembler.impl; + +import org.apache.logging.log4j.core.config.Configuration; +import org.apache.logging.log4j.core.config.assembler.api.Component; +import org.apache.logging.log4j.core.config.assembler.api.LoggerAssembler; + +/** + * + */ +public class DefaultLoggerAssembler extends DefaultComponentAssembler implements LoggerAssembler { + + /** + * Configure a logger. + * @param assembler + * @param name + * @param level + */ + public DefaultLoggerAssembler(DefaultConfigurationAssembler assembler, String name, String level) { + super(assembler, name, "Logger"); + addAttribute("level", level); + } + + /** + * Configure a logger. + * @param assembler + * @param name + * @param level + * @param type + */ + public DefaultLoggerAssembler(DefaultConfigurationAssembler assembler, String name, String level, String type) { + super(assembler, name, type); + addAttribute("level", level); + } + + @Override + public LoggerAssembler addAppenderRef(Component ref) { + this.addSubComponent(ref); + return this; + } + + @Override + public LoggerAssembler addFilter(Component filter) { + addSubComponent(filter); + return this; + } +} \ No newline at end of file diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/assembler/impl/DefaultRootLoggerAssembler.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/assembler/impl/DefaultRootLoggerAssembler.java new file mode 100644 index 0000000..ac0a76d --- /dev/null +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/assembler/impl/DefaultRootLoggerAssembler.java @@ -0,0 +1,62 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache license, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the license for the specific language governing permissions and + * limitations under the license. + */ +package org.apache.logging.log4j.core.config.assembler.impl; + +import org.apache.logging.log4j.core.config.Configuration; +import org.apache.logging.log4j.core.config.assembler.api.Component; +import org.apache.logging.log4j.core.config.assembler.api.LoggerAssembler; +import org.apache.logging.log4j.core.config.assembler.api.RootLoggerAssembler; + +/** + * + */ +public class DefaultRootLoggerAssembler extends DefaultComponentAssembler implements RootLoggerAssembler { + + /** + * Configure the root logger. + * @param assembler + * @param level + */ + public DefaultRootLoggerAssembler(DefaultConfigurationAssembler assembler, String level) { + super(assembler, "", "Root"); + addAttribute("level", level); + } + + /** + * Configure the root logger. + * @param assembler + * @param level + * @param type + */ + public DefaultRootLoggerAssembler(DefaultConfigurationAssembler assembler, String level, String type) { + super(assembler, "", type); + addAttribute("level", level); + } + + @Override + public RootLoggerAssembler addAppenderRef(Component ref) { + this.addSubComponent(ref); + return this; + } + + + @Override + public RootLoggerAssembler addFilter(Component filter) { + addSubComponent(filter); + return this; + } +} \ No newline at end of file diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/visitors/PluginAttributeVisitor.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/visitors/PluginAttributeVisitor.java index 63e5cb5..acaea29 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/visitors/PluginAttributeVisitor.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/visitors/PluginAttributeVisitor.java @@ -44,7 +44,7 @@ public class PluginAttributeVisitor extends AbstractPluginVisitor assembler = getConfigurationAssembler(PropertiesConfiguration.class); + String value = properties.getProperty(STATUS_KEY); + if (value != null) { + assembler.setStatusLevel(Level.toLevel(value, Level.ERROR)); + } else { + assembler.setStatusLevel(Level.ERROR); + } + value = properties.getProperty(SHUTDOWN_HOOK); + if (value != null) { + assembler.setShutdownHook(value); + } + value = properties.getProperty(VERBOSE); + if (value != null) { + assembler.setVerbosity(value); + } + value = properties.getProperty(PACKAGES); + if (value != null) { + assembler.setPackages(value); + } + value = properties.getProperty(CONFIG_NAME); + if (value != null) { + assembler.setConfigurationName(value); + } + value = properties.getProperty(MONITOR_INTERVAL); + if (value != null) { + assembler.setMonitorInterval(value); + } + Properties props = PropertiesUtil.extractSubset(properties, "property"); + for (String key : props.stringPropertyNames()) { + assembler.addProperty(key, props.getProperty(key)); + } + + Properties levelProps = PropertiesUtil.extractSubset(properties, "customLevel"); + if (levelProps.size() > 0) { + for (String key : levelProps.stringPropertyNames()) { + assembler.addCustomLevel(assembler.getCustomLevelAssembler(key, props.getProperty(key)).assemble()); + } + } + + String filterProp = properties.getProperty("filters"); + if (filterProp != null) { + String[] filterNames = filterProp.split(","); + for (String filterName : filterNames) { + String name = filterName.trim(); + assembler.addFilter(createFilter(assembler, name, PropertiesUtil.extractSubset(properties, "filter." + name))); + } + } + String appenderProp = properties.getProperty("appenders"); + if (appenderProp != null) { + String[] appenderNames = appenderProp.split(","); + for (String appenderName : appenderNames) { + String name = appenderName.trim(); + assembler.addAppender(createAppender(assembler, name, PropertiesUtil.extractSubset(properties, "appender." + name))); + } + } + String loggerProp = properties.getProperty("loggers"); + if (appenderProp != null) { + String[] loggerNames = loggerProp.split(","); + for (String loggerName : loggerNames) { + String name = loggerName.trim(); + if (!name.equals("root")) { + assembler.addLogger(createLogger(assembler, name, PropertiesUtil.extractSubset(properties, "logger." + name))); + } + } + } + + props = PropertiesUtil.extractSubset(properties, "rootLogger"); + if (props.size() > 0) { + assembler.addRootLogger(createRootLogger(assembler, props)); + } + + return assembler.assemble(); + } + + private Component createAppender(ConfigurationAssembler assembler, String key, Properties properties) { + String name = properties.getProperty(CONFIG_NAME); + if (Strings.isEmpty(name)) { + throw new ConfigurationException("No name attribute provided for Appender " + key); + } + properties.remove(CONFIG_NAME); + String type = properties.getProperty(CONFIG_TYPE); + if (Strings.isEmpty(type)) { + throw new ConfigurationException("No type attribute provided for Appender " + key); + } + properties.remove(CONFIG_TYPE); + AppenderAssembler appenderAssembler = assembler.getAppenderAssembler(name, type); + String filters = properties.getProperty("filters"); + if (filters != null) { + properties.remove("filters"); + String[] filterNames = filters.split(","); + for (String filterName : filterNames) { + filterName = filterName.trim(); + Properties filterProps = PropertiesUtil.extractSubset(properties, "filter." + filterName); + appenderAssembler.addFilter(createFilter(assembler, filterName, filterProps)); + } + } + Properties layoutProps = PropertiesUtil.extractSubset(properties, "layout"); + if (layoutProps.size() > 0) { + appenderAssembler.addLayout(createLayout(assembler, name, layoutProps)); + } + + processRemainingProperties(appenderAssembler, name, properties); + return appenderAssembler.assemble(); + } + + private Component createFilter(ConfigurationAssembler assembler, String key, Properties properties) { + String type = properties.getProperty(CONFIG_TYPE); + if (Strings.isEmpty(type)) { + throw new ConfigurationException("No type attribute provided for Appender " + key); + } + properties.remove(CONFIG_TYPE); + String onMatch = properties.getProperty("onMatch"); + if (onMatch != null) { + properties.remove("onMatch"); + } + String onMisMatch = properties.getProperty("onMisMatch"); + if (onMisMatch != null) { + properties.remove("onMisMatch"); + } + FilterAssembler filterAssembler = assembler.getFilterAssembler(type, onMatch, onMisMatch); + processRemainingProperties(filterAssembler, key, properties); + return filterAssembler.assemble(); + } + + private Component createAppenderRef(ConfigurationAssembler assembler, String key, Properties properties) { + String ref = properties.getProperty("ref"); + if (Strings.isEmpty(ref)) { + throw new ConfigurationException("No ref attribute provided for AppenderRef " + key); + } + properties.remove("ref"); + AppenderRefAssembler appenderRefAssembler = assembler.getAppenderRefAssembler(ref); + String level = properties.getProperty("level"); + if (!Strings.isEmpty(level)) { + appenderRefAssembler.addAttribute("level", level); + } + String filters = properties.getProperty("filters"); + if (filters != null) { + properties.remove("filters"); + String[] filterNames = filters.split(","); + for (String filterName : filterNames) { + filterName = filterName.trim(); + Properties filterProps = PropertiesUtil.extractSubset(properties, "filter." + filterName); + appenderRefAssembler.addFilter(createFilter(assembler, filterName, filterProps)); + } + } + return appenderRefAssembler.assemble(); + } + + private Component createLogger(ConfigurationAssembler assembler, String key, Properties properties) { + String name = properties.getProperty(CONFIG_NAME); + if (Strings.isEmpty(name)) { + throw new ConfigurationException("No name attribute provided for Logger " + key); + } + properties.remove(CONFIG_NAME); + String level = properties.getProperty("level"); + if (level != null) { + properties.remove("level"); + } + LoggerAssembler loggerAssembler; + String type = properties.getProperty(CONFIG_TYPE); + if (type != null) { + if (type.equalsIgnoreCase("asyncLogger")) { + loggerAssembler = assembler.getAsyncLoggerAssembler(name, level); + } else { + throw new ConfigurationException("Unknown Logger type " + type + " for Logger " + name); + } + } else { + loggerAssembler = assembler.getLoggerAssembler(name, level); + } + String appenderRefs = properties.getProperty("appenderRefs"); + if (appenderRefs != null) { + properties.remove("appenderRefs"); + String[] refNames = appenderRefs.split(","); + for (String appenderRef : refNames) { + appenderRef = appenderRef.trim(); + Properties refProps = PropertiesUtil.extractSubset(properties, "appenderRef." + appenderRef); + loggerAssembler.addAppenderRef(createAppenderRef(assembler, appenderRef, refProps)); + } + } + String filters = properties.getProperty("filters"); + if (filters != null) { + properties.remove("filters"); + String[] filterNames = filters.split(","); + for (String filterName : filterNames) { + filterName = filterName.trim(); + Properties filterProps = PropertiesUtil.extractSubset(properties, "filter." + filterName); + loggerAssembler.addFilter(createFilter(assembler, filterName, filterProps)); + } + } + String additivity = properties.getProperty("additivity"); + if (!Strings.isEmpty(additivity)) { + loggerAssembler.addAttribute("additivity", additivity); + } + return loggerAssembler.assemble(); + } + + private Component createRootLogger(ConfigurationAssembler assembler, Properties properties) { + String level = properties.getProperty("level"); + if (level != null) { + properties.remove("level"); + } + RootLoggerAssembler loggerAssembler; + String type = properties.getProperty(CONFIG_TYPE); + if (type != null) { + if (type.equalsIgnoreCase("asyncRoot")) { + loggerAssembler = assembler.getAsyncRootLoggerAssembler(level); + } else { + throw new ConfigurationException("Unknown Logger type for root logger" + type); + } + } else { + loggerAssembler = assembler.getRootLoggerAssembler(level); + } + String appenderRefs = properties.getProperty("appenderRefs"); + if (appenderRefs != null) { + properties.remove("appenderRefs"); + String[] refNames = appenderRefs.split(","); + for (String appenderRef : refNames) { + appenderRef = appenderRef.trim(); + Properties refProps = PropertiesUtil.extractSubset(properties, "appenderRef." + appenderRef); + loggerAssembler.addAppenderRef(createAppenderRef(assembler, appenderRef, refProps)); + } + } + String filters = properties.getProperty("filters"); + if (filters != null) { + properties.remove("filters"); + String[] filterNames = filters.split(","); + for (String filterName : filterNames) { + filterName = filterName.trim(); + Properties filterProps = PropertiesUtil.extractSubset(properties, "filter." + filterName); + loggerAssembler.addFilter(createFilter(assembler, filterName, filterProps)); + } + } + return loggerAssembler.assemble(); + } + + private Component createLayout(ConfigurationAssembler assembler, String appenderName, Properties properties) { + String type = properties.getProperty(CONFIG_TYPE); + if (Strings.isEmpty(type)) { + throw new ConfigurationException("No type attribute provided for Layout on Appender " + appenderName); + } + properties.remove(CONFIG_TYPE); + LayoutAssembler layoutAssembler = assembler.getLayoutAssembler(type); + processRemainingProperties(layoutAssembler, appenderName, properties); + return layoutAssembler.assemble(); + } + + @SuppressWarnings("rawtypes") + private Component createComponent(ComponentAssembler parent, String key, Properties properties) { + String name = properties.getProperty(CONFIG_NAME); + if (name != null) { + properties.remove(CONFIG_NAME); + } + String type = properties.getProperty(CONFIG_TYPE); + if (Strings.isEmpty(type)) { + throw new ConfigurationException("No type attribute provided for component " + key); + } + properties.remove(CONFIG_TYPE); + @SuppressWarnings("unchecked") + ComponentAssembler componentAssembler = parent.getAssembler().getComponentAssembler(name, type); + processRemainingProperties(componentAssembler, name, properties); + return componentAssembler.assemble(); + } + + @SuppressWarnings("rawtypes") + private void processRemainingProperties(ComponentAssembler assembler, String name, Properties properties) { + while (properties.size() > 0) { + String propertyName = properties.stringPropertyNames().iterator().next(); + + int index = propertyName.indexOf('.'); + if (index > 0) { + String prefix = propertyName.substring(0, index); + Properties componentProperties = PropertiesUtil.extractSubset(properties, prefix); + assembler.addSubComponent(createComponent(assembler, prefix, componentProperties)); + } else { + assembler.addAttribute(propertyName, properties.getProperty(propertyName)); + properties.remove(propertyName); + } + } + } + + @Override + public Configuration getConfiguration(final String name, final URI configLocation) { + InputStream is; + try { + URL url = configLocation.toURL(); + ConfigurationSource source = new ConfigurationSource(url.openStream(), url); + return getConfiguration(source); + } catch (Exception ex) { + throw new ConfigurationException("Unable to access " + configLocation.toString()); + } + } +} diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/util/PropertiesUtil.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/util/PropertiesUtil.java new file mode 100644 index 0000000..c43ce93 --- /dev/null +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/util/PropertiesUtil.java @@ -0,0 +1,42 @@ +package org.apache.logging.log4j.core.util; + +import java.util.ArrayList; +import java.util.List; +import java.util.Properties; + +/** + * + */ +public class PropertiesUtil { + + /** + * Extracts properties that start with or are equals to the specific prefix and returns them in a + * new Properties object with the prefix removed. + * @param properties The Properties to evaluate. + * @param prefix The prefix to extract. + * @return The subset of properties. + */ + public static Properties extractSubset(Properties properties, String prefix) { + Properties subset = new Properties(); + + if (prefix == null || prefix.length() == 0) { + return subset; + } + + String prefixToMatch = prefix.charAt(prefix.length() - 1) != '.' ? prefix + '.' : prefix; + + List keys = new ArrayList<>(); + + for (String key : properties.stringPropertyNames()) { + if (key.startsWith(prefixToMatch)) { + subset.setProperty(key.substring(prefixToMatch.length()), properties.getProperty(key)); + keys.add(key); + } + } + for (String key : keys) { + properties.remove(key); + } + + return subset; + } +} diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/core/config/assembler/ConfigurationAssemblerTest.java b/log4j-core/src/test/java/org/apache/logging/log4j/core/config/assembler/ConfigurationAssemblerTest.java new file mode 100644 index 0000000..3e0ef2f --- /dev/null +++ b/log4j-core/src/test/java/org/apache/logging/log4j/core/config/assembler/ConfigurationAssemblerTest.java @@ -0,0 +1,59 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache license, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the license for the specific language governing permissions and + * limitations under the license. + */ +package org.apache.logging.log4j.core.config.assembler; + +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.apache.logging.log4j.core.Appender; +import org.apache.logging.log4j.core.Filter; +import org.apache.logging.log4j.core.LifeCycle; +import org.apache.logging.log4j.core.LoggerContext; +import org.apache.logging.log4j.core.config.Configuration; + +import org.apache.logging.log4j.core.config.ConfigurationFactory; +import org.apache.logging.log4j.core.config.LoggerConfig; +import org.apache.logging.log4j.core.filter.ThresholdFilter; +import org.junit.Test; + +import java.util.Map; + +import static org.junit.Assert.*; + +/** + * + */ +public class ConfigurationAssemblerTest { + + @Test + public void doConfigure() throws Exception { + System.setProperty(ConfigurationFactory.CONFIGURATION_FACTORY_PROPERTY, "org.apache.logging.log4j.core.config.assembler.CustomConfigurationFactory"); + Configuration config = ((LoggerContext)LogManager.getContext(false)).getConfiguration(); + assertNotNull("No configuration created", config); + assertEquals("Incorrect State: " + config.getState(), config.getState(), LifeCycle.State.STARTED); + Map appenders = config.getAppenders(); + assertNotNull(appenders); + assertTrue("Incorrect number of Appenders: " + appenders.size(), appenders.size() == 1); + Map loggers = config.getLoggers(); + assertNotNull(loggers); + assertTrue("Incorrect number of LoggerConfigs: " + loggers.size(), loggers.size() == 2); + Filter filter = config.getFilter(); + assertNotNull("No Filter", filter); + assertTrue("Not a Threshold Filter", filter instanceof ThresholdFilter); + Logger logger = LogManager.getLogger(getClass()); + logger.info("Welcome to Log4j!"); + } +} diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/core/config/assembler/CustomConfigurationFactory.java b/log4j-core/src/test/java/org/apache/logging/log4j/core/config/assembler/CustomConfigurationFactory.java new file mode 100644 index 0000000..da60afb --- /dev/null +++ b/log4j-core/src/test/java/org/apache/logging/log4j/core/config/assembler/CustomConfigurationFactory.java @@ -0,0 +1,68 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache license, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the license for the specific language governing permissions and + * limitations under the license. + */ +package org.apache.logging.log4j.core.config.assembler; + +import org.apache.logging.log4j.Level; +import org.apache.logging.log4j.core.config.Configuration; +import org.apache.logging.log4j.core.config.ConfigurationFactory; +import org.apache.logging.log4j.core.config.ConfigurationSource; +import org.apache.logging.log4j.core.config.assembler.api.AppenderAssembler; +import org.apache.logging.log4j.core.config.assembler.api.ConfigurationAssembler; +import org.apache.logging.log4j.core.config.assembler.impl.AssembledConfiguration; + +import java.net.URI; + +/** + * Normally this would be a plugin. However, we don't want it used for everything so it will be defined + * via a system property. + */ +//@Plugin(name = "CustomConfigurationFactory", category = ConfigurationFactory.CATEGORY) +//@Order(50) +public class CustomConfigurationFactory extends ConfigurationFactory { + + @Override + protected String[] getSupportedTypes() { + return new String[] {"*"}; + } + + @Override + public Configuration getConfiguration(ConfigurationSource source) { + return getConfiguration(source.toString(), null); + } + + @Override + public Configuration getConfiguration(final String name, final URI configLocation) { + ConfigurationAssembler assembler = getConfigurationAssembler(); + assembler.setStatusLevel(Level.ERROR); + assembler.addFilter( + assembler.getFilterAssembler("ThresholdFilter", "ACCEPT", "NEUTRAL").addAttribute("level", "DEBUG") + .assemble()); + AppenderAssembler appenderAssembler = assembler.getAppenderAssembler("Stdout", "CONSOLE").addAttribute("target", "SYSTEM_OUT"); + appenderAssembler.addLayout(assembler.getLayoutAssembler("PatternLayout"). + addAttribute("pattern", "%d [%t] %-5level: %msg%n%throwable").assemble()); + appenderAssembler.addFilter( + assembler.getFilterAssembler("MarkerFilter", "DENY", "NEUTRAL").addAttribute("marker", "FLOW"). + assemble()); + assembler.addAppender(appenderAssembler.assemble()); + assembler.addLogger(assembler.getLoggerAssembler("org.apache.logging.log4j", "DEBUG"). + addAppenderRef(assembler.getAppenderRefAssembler("Stdout").assemble()). + addAttribute("additivity", "false").assemble()); + assembler.addRootLogger(assembler.getRootLoggerAssembler("ERROR") + .addAppenderRef(assembler.getAppenderRefAssembler("Stdout").assemble()).assemble()); + return assembler.assemble(); + } +} diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/core/config/properties/PropertiesConfigurationTest.java b/log4j-core/src/test/java/org/apache/logging/log4j/core/config/properties/PropertiesConfigurationTest.java new file mode 100644 index 0000000..6c78abb --- /dev/null +++ b/log4j-core/src/test/java/org/apache/logging/log4j/core/config/properties/PropertiesConfigurationTest.java @@ -0,0 +1,60 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache license, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the license for the specific language governing permissions and + * limitations under the license. + */ +package org.apache.logging.log4j.core.config.properties; + +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.apache.logging.log4j.core.Appender; +import org.apache.logging.log4j.core.Filter; +import org.apache.logging.log4j.core.LifeCycle; +import org.apache.logging.log4j.core.LoggerContext; +import org.apache.logging.log4j.core.config.Configuration; +import org.apache.logging.log4j.core.config.ConfigurationFactory; +import org.apache.logging.log4j.core.config.LoggerConfig; +import org.apache.logging.log4j.core.filter.ThresholdFilter; +import org.junit.Test; + +import java.util.Map; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; + +/** + * + */ +public class PropertiesConfigurationTest { + + @Test + public void testPropertiesConfiguration() { + System.setProperty(ConfigurationFactory.CONFIGURATION_FILE_PROPERTY, "target/test-classes/log4j2-properties.properties"); + Configuration config = ((LoggerContext)LogManager.getContext(false)).getConfiguration(); + assertNotNull("No configuration created", config); + assertEquals("Incorrect State: " + config.getState(), config.getState(), LifeCycle.State.STARTED); + Map appenders = config.getAppenders(); + assertNotNull(appenders); + assertTrue("Incorrect number of Appenders: " + appenders.size(), appenders.size() == 1); + Map loggers = config.getLoggers(); + assertNotNull(loggers); + assertTrue("Incorrect number of LoggerConfigs: " + loggers.size(), loggers.size() == 2); + Filter filter = config.getFilter(); + assertNotNull("No Filter", filter); + assertTrue("Not a Threshold Filter", filter instanceof ThresholdFilter); + Logger logger = LogManager.getLogger(getClass()); + logger.info("Welcome to Log4j!"); + } +} diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/core/config/properties/RollingFilePropertiesTest.java b/log4j-core/src/test/java/org/apache/logging/log4j/core/config/properties/RollingFilePropertiesTest.java new file mode 100644 index 0000000..9607284 --- /dev/null +++ b/log4j-core/src/test/java/org/apache/logging/log4j/core/config/properties/RollingFilePropertiesTest.java @@ -0,0 +1,59 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache license, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the license for the specific language governing permissions and + * limitations under the license. + */ +package org.apache.logging.log4j.core.config.properties; + +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.apache.logging.log4j.core.Appender; +import org.apache.logging.log4j.core.Filter; +import org.apache.logging.log4j.core.LifeCycle; +import org.apache.logging.log4j.core.LoggerContext; +import org.apache.logging.log4j.core.config.Configuration; +import org.apache.logging.log4j.core.config.ConfigurationFactory; +import org.apache.logging.log4j.core.config.LoggerConfig; +import org.apache.logging.log4j.core.filter.ThresholdFilter; +import org.junit.Test; + +import java.util.Map; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; + +/** + * + */ +public class RollingFilePropertiesTest { + @Test + public void testPropertiesConfiguration() { + System.setProperty(ConfigurationFactory.CONFIGURATION_FILE_PROPERTY, "target/test-classes/log4j-rolling.properties"); + Configuration config = ((LoggerContext) LogManager.getContext(false)).getConfiguration(); + assertNotNull("No configuration created", config); + assertEquals("Incorrect State: " + config.getState(), config.getState(), LifeCycle.State.STARTED); + Map appenders = config.getAppenders(); + assertNotNull(appenders); + assertTrue("Incorrect number of Appenders: " + appenders.size(), appenders.size() == 3); + Map loggers = config.getLoggers(); + assertNotNull(loggers); + assertTrue("Incorrect number of LoggerConfigs: " + loggers.size(), loggers.size() == 2); + Filter filter = config.getFilter(); + assertNotNull("No Filter", filter); + assertTrue("Not a Threshold Filter", filter instanceof ThresholdFilter); + Logger logger = LogManager.getLogger(getClass()); + logger.info("Welcome to Log4j!"); + } +} diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/core/util/PropertiesUtilTest.java b/log4j-core/src/test/java/org/apache/logging/log4j/core/util/PropertiesUtilTest.java new file mode 100644 index 0000000..0fc6f20 --- /dev/null +++ b/log4j-core/src/test/java/org/apache/logging/log4j/core/util/PropertiesUtilTest.java @@ -0,0 +1,25 @@ +package org.apache.logging.log4j.core.util; + +import org.junit.Test; + +import java.io.FileInputStream; +import java.util.Properties; + +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; + +/** + * + */ +public class PropertiesUtilTest { + + @Test + public void testSubset() throws Exception { + Properties props = new Properties(); + props.load(new FileInputStream("target/test-classes/log4j2-properties.properties")); + Properties subset = PropertiesUtil.extractSubset(props, "appender.Stdout.filter.marker"); + assertNotNull("No subset returned", subset); + assertTrue("Incorrect number of items. Expected 4, actual " + subset.size(), subset.size() == 4); + assertTrue("Missing propertu", subset.containsKey("type")); + } +} diff --git a/log4j-core/src/test/resources/log4j-rolling.properties b/log4j-core/src/test/resources/log4j-rolling.properties new file mode 100644 index 0000000..111bb18 --- /dev/null +++ b/log4j-core/src/test/resources/log4j-rolling.properties @@ -0,0 +1,59 @@ +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to You under the Apache License, Version 2.0 +# (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +status = debug +name = PropertiesConfigTest + +property.filename = target/rolling/rollingtest.log + +filters = threshold + +filter.threshold.type = ThresholdFilter +filter.threshold.level = debug + +appenders = console, rolling, list + +appender.console.type = Console +appender.console.name = STDOUT +appender.console.layout.type = PatternLayout +appender.console.layout.pattern = %m%n + +appender.rolling.type = RollingFile +appender.rolling.name = RollingFile +appender.rolling.fileName = ${filename} +appender.rolling.filePattern = target/rolling2/test1-%d{MM-dd-yy-HH-mm-ss}.log.gz +appender.rolling.layout.type = PatternLayout +appender.rolling.layout.pattern = %d %p %C{1.} [%t] %m%n +appender.rolling.policy.type = TimeBasedTriggeringPolicy +appender.rolling.policy.interval = 2 +appender.rolling.policy.modulate = true + +appender.list.type = List +appender.list.name = List +appender.list.filters = threshold +appender.list.filter.threshold.type = ThresholdFilter +appender.list.filter.threshold.level = error + +loggers = rolling + +logger.rolling.name = org.apache.logging.log4j.core.appender.rolling +logger.rolling.level = debug +logger.rolling.additivity = false +logger.rolling.appenderRefs = rolling +logger.rolling.appenderRef.rolling.ref = RollingFile + +rootLogger.level = info +rootLogger.appenderRefs = stdout +rootLogger.appenderRef.stdout.ref = STDOUT \ No newline at end of file diff --git a/log4j-core/src/test/resources/log4j2-properties.properties b/log4j-core/src/test/resources/log4j2-properties.properties new file mode 100644 index 0000000..56afedf --- /dev/null +++ b/log4j-core/src/test/resources/log4j2-properties.properties @@ -0,0 +1,44 @@ +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to You under the Apache License, Version 2.0 +# (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +filters = Threshold + +filter.Threshold.type = ThresholdFilter +filter.Threshold.level = DEBUG + +appenders = Stdout + +appender.Stdout.type = Console +appender.Stdout.name = StdOut +appender.Stdout.target = SYSTEM_OUT +appender.Stdout.layout.type = PatternLayout +appender.Stdout.layout.pattern = %d [%t] %-5level: %msg%n%throwable +appender.Stdout.filters = marker +appender.Stdout.filter.marker.type = MarkerFilter +appender.Stdout.filter.marker.onMatch = DENY +appender.Stdout.filter.marker.onMisMatch = NEUTRAL +appender.Stdout.filter.marker.marker = FLOW + +loggers = log4j + +logger.log4j.name = org.apache.logging.log4j +logger.log4j.appenderRefs = console +logger.log4j.appenderRef.console.ref = StdOut +logger.log4j.level = DEBUG +logger.log4j.additivity = false + +rootLogger.appenderRefs = console +rootLogger.appenderRef.console.ref = StdOut +rootLogger.level = ERROR