LOG4J2-589 CustomLevel elements should be configured in a containing CustomLevels element.
* Renamed CustomLevelPlugin to CustomLevelConfig * Added method Configuration#getCustomLevels * Added plugin CustomLevels to act as the CustomLevel container * Updated manual page * Updated schema Project: http://git-wip-us.apache.org/repos/asf/logging-log4j2/repo Commit: http://git-wip-us.apache.org/repos/asf/logging-log4j2/commit/ba3feb23 Tree: http://git-wip-us.apache.org/repos/asf/logging-log4j2/tree/ba3feb23 Diff: http://git-wip-us.apache.org/repos/asf/logging-log4j2/diff/ba3feb23 Branch: refs/heads/master Commit: ba3feb23378ca23eadb9f2a7e3b6fd073ea7afe9 Parents: bfbcc93 Author: rpopma <[email protected]> Authored: Sat Sep 27 00:14:43 2014 +0900 Committer: rpopma <[email protected]> Committed: Sat Sep 27 00:14:43 2014 +0900 ---------------------------------------------------------------------- .../core/config/AbstractConfiguration.java | 22 ++++- .../log4j/core/config/Configuration.java | 30 +++++- .../log4j/core/config/CustomLevelConfig.java | 99 ++++++++++++++++++++ .../log4j/core/config/CustomLevelPlugin.java | 51 ---------- .../logging/log4j/core/config/CustomLevels.java | 59 ++++++++++++ log4j-core/src/main/resources/Log4j-config.xsd | 5 +- src/site/xdoc/manual/customloglevels.xml.vm | 8 +- 7 files changed, 211 insertions(+), 63 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/ba3feb23/log4j-core/src/main/java/org/apache/logging/log4j/core/config/AbstractConfiguration.java ---------------------------------------------------------------------- diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/AbstractConfiguration.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/AbstractConfiguration.java index 325545b..fa5b4cb 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/AbstractConfiguration.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/AbstractConfiguration.java @@ -98,6 +98,7 @@ public abstract class AbstractConfiguration extends AbstractFilterable implement private String name; private ConcurrentMap<String, Appender> appenders = new ConcurrentHashMap<String, Appender>(); private ConcurrentMap<String, LoggerConfig> loggers = new ConcurrentHashMap<String, LoggerConfig>(); + private List<CustomLevelConfig> customLevels = Collections.emptyList(); private final ConcurrentMap<String, String> properties = new ConcurrentHashMap<String, String>(); private final StrLookup tempLookup = new Interpolator(properties); private final StrSubstitutor subst = new StrSubstitutor(tempLookup); @@ -371,9 +372,12 @@ public abstract class AbstractConfiguration extends AbstractFilterable implement root = l.getRoot(); setRoot = true; } - } else if (child.getObject() instanceof Level) { - // This else clause prevents the warning message below from being logged. - // Nothing to do: plugin already created the custom Level instance. + } else if (child.getName().equalsIgnoreCase("CustomLevels")) { + customLevels = ((CustomLevels) child.getObject()).getCustomLevels(); + } else if (child.getObject() instanceof CustomLevelConfig) { + List<CustomLevelConfig> copy = new ArrayList<CustomLevelConfig>(customLevels); + copy.add((CustomLevelConfig) child.getObject()); + customLevels = copy; } else { LOGGER.error("Unknown object \"{}\" of type {} is ignored.", child.getName(), child.getObject().getClass().getName()); @@ -605,6 +609,15 @@ public abstract class AbstractConfiguration extends AbstractFilterable implement app.stop(); } } + + /* + * (non-Javadoc) + * @see org.apache.logging.log4j.core.config.Configuration#getCustomLevels() + */ + @Override + public List<CustomLevelConfig> getCustomLevels() { + return Collections.unmodifiableList(customLevels); + } /** * Locates the appropriate LoggerConfig for a Logger name. This will remove tokens from the @@ -732,8 +745,7 @@ public abstract class AbstractConfiguration extends AbstractFilterable implement * @see org.apache.logging.log4j.core.config.plugins.visitors.PluginVisitor * @see org.apache.logging.log4j.core.config.plugins.convert.TypeConverter */ - private <T> Object createPluginObject(final PluginType<T> type, final Node node, final LogEvent event) - { + private <T> Object createPluginObject(final PluginType<T> type, final Node node, final LogEvent event) { final Class<T> clazz = type.getPluginClass(); if (Map.class.isAssignableFrom(clazz)) { http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/ba3feb23/log4j-core/src/main/java/org/apache/logging/log4j/core/config/Configuration.java ---------------------------------------------------------------------- diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/Configuration.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/Configuration.java index ae2e99f..beacbb3 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/Configuration.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/Configuration.java @@ -16,6 +16,7 @@ */ package org.apache.logging.log4j.core.config; +import org.apache.logging.log4j.Level; import org.apache.logging.log4j.core.Appender; import org.apache.logging.log4j.core.Filter; import org.apache.logging.log4j.core.LogEvent; @@ -37,13 +38,15 @@ public interface Configuration extends Filterable { /** * Returns the configuration name. + * * @return the name of the configuration. */ String getName(); /** - * Locates the appropriate LoggerConfig for a Logger name. This will remove tokens from the - * package name as necessary or return the root LoggerConfig if no other matches were found. + * Locates the appropriate LoggerConfig for a Logger name. This will remove tokens from the package name as + * necessary or return the root LoggerConfig if no other matches were found. + * * @param name The Logger name. * @return The located LoggerConfig. */ @@ -51,6 +54,7 @@ public interface Configuration extends Filterable { /** * Returns the Appender with the specified name. + * * @param name The name of the Appender. * @return the Appender with the specified name or null if the Appender cannot be located. */ @@ -58,6 +62,7 @@ public interface Configuration extends Filterable { /** * Returns a Map containing all the Appenders and their name. + * * @return A Map containing each Appender's name and the Appender object. */ Map<String, Appender> getAppenders(); @@ -107,10 +112,29 @@ public interface Configuration extends Filterable { Advertiser getAdvertiser(); boolean isShutdownHookEnabled(); - + /** * Returns the source of this configuration. + * * @return the source of this configuration */ ConfigurationSource getConfigurationSource(); + + /** + * <p> + * Returns a list of descriptors of the custom levels defined in the current configuration. The returned list does + * <em>not</em> include custom levels that are defined in code with direct calls to {@link Level.forName}. + * </p> + * <p> + * Note that the list does not include levels of previous configurations. For example, suppose a configuration + * contains custom levels A, B and C. The configuration is then modified to contain custom levels B, C and D. For + * the new configuration, this method will return only {B, C, D}, that is, only the custom levels defined in + * <em>this</em> configuration. The previously defined level A still exists (and can be obtained with + * {@link Level#getLevel(String)}), it is just not in the current configuration. {@link Level#values()} will return + * {A, B, C, D and the built-in levels}. + * </p> + * + * @return the custom levels defined in the current configuration + */ + List<CustomLevelConfig> getCustomLevels(); } http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/ba3feb23/log4j-core/src/main/java/org/apache/logging/log4j/core/config/CustomLevelConfig.java ---------------------------------------------------------------------- diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/CustomLevelConfig.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/CustomLevelConfig.java new file mode 100644 index 0000000..24e772a --- /dev/null +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/CustomLevelConfig.java @@ -0,0 +1,99 @@ +/* + * 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; + +import org.apache.logging.log4j.Level; +import org.apache.logging.log4j.core.config.plugins.Plugin; +import org.apache.logging.log4j.core.config.plugins.PluginAttribute; +import org.apache.logging.log4j.core.config.plugins.PluginFactory; +import org.apache.logging.log4j.core.util.Assert; +import org.apache.logging.log4j.status.StatusLogger; + +/** + * Descriptor of a custom Level object that is created via configuration. + */ +@Plugin(name = "CustomLevel", category = "Core", printObject = true) +public final class CustomLevelConfig { + + private final String levelName; + private final int intLevel; + + private CustomLevelConfig(final String levelName, final int intLevel) { + this.levelName = Assert.requireNonNull(levelName, "levelName is null"); + this.intLevel = intLevel; + } + + /** + * Creates a CustomLevelConfig object. This also defines the Level object with a call to + * {@link Level#forName(String, int)}. + * + * @param levelName name of the custom level. + * @param intLevel the intLevel that determines where this level resides relative to the built-in levels + * @return A CustomLevelConfig object. + */ + @PluginFactory + public static CustomLevelConfig createLevel(// @formatter:off + @PluginAttribute("name") final String levelName, + @PluginAttribute("intLevel") final int intLevel) { + // @formatter:on + + StatusLogger.getLogger().debug("Creating CustomLevel(name='{}', intValue={})", levelName, intLevel); + Level.forName(levelName, intLevel); + return new CustomLevelConfig(levelName, intLevel); + } + + /** + * Returns the custom level name. + * + * @return the custom level name + */ + public String getLevelName() { + return levelName; + } + + /** + * Returns the custom level intLevel that determines the strength of the custom level relative to the built-in + * levels. + * + * @return the custom level intLevel + */ + public int getIntLevel() { + return intLevel; + } + + @Override + public int hashCode() { + return intLevel ^ levelName.hashCode(); + } + + @Override + public boolean equals(Object object) { + if (this == object) { + return true; + } + if (!(object instanceof CustomLevelConfig)) { + return false; + } + CustomLevelConfig other = (CustomLevelConfig) object; + return this.intLevel == other.intLevel && this.levelName.equals(other.levelName); + } + + @Override + public String toString() { + return "CustomLevel[name=" + levelName + ", intLevel=" + intLevel + "]"; + } +} http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/ba3feb23/log4j-core/src/main/java/org/apache/logging/log4j/core/config/CustomLevelPlugin.java ---------------------------------------------------------------------- diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/CustomLevelPlugin.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/CustomLevelPlugin.java deleted file mode 100644 index 532e811..0000000 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/CustomLevelPlugin.java +++ /dev/null @@ -1,51 +0,0 @@ -/* - * 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; - -import org.apache.logging.log4j.Level; -import org.apache.logging.log4j.core.config.plugins.Plugin; -import org.apache.logging.log4j.core.config.plugins.PluginAttribute; -import org.apache.logging.log4j.core.config.plugins.PluginFactory; -import org.apache.logging.log4j.status.StatusLogger; - -/** - * Custom Level object that is created via configuration. - */ -@Plugin(name = "CustomLevel", category = "Core", printObject = true) -public final class CustomLevelPlugin { - - private CustomLevelPlugin() { - } - - /** - * Creates a custom Level object. - * - * @param levelName name of the custom level. - * @param intLevel the intLevel that determines where this level resides relative to the built-in levels - * @return A Level object. - */ - @PluginFactory - public static Level createLevel(// @formatter:off - @PluginAttribute("name") final String levelName, - @PluginAttribute("intLevel") final int intLevel) { - // @formatter:on - - StatusLogger.getLogger().debug("Creating CustomLevel(name='{}', intValue={})", levelName, intLevel); - Level result = Level.forName(levelName, intLevel); - return result; - } -} http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/ba3feb23/log4j-core/src/main/java/org/apache/logging/log4j/core/config/CustomLevels.java ---------------------------------------------------------------------- diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/CustomLevels.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/CustomLevels.java new file mode 100644 index 0000000..440aef3 --- /dev/null +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/CustomLevels.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; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +import org.apache.logging.log4j.core.config.plugins.Plugin; +import org.apache.logging.log4j.core.config.plugins.PluginElement; +import org.apache.logging.log4j.core.config.plugins.PluginFactory; + +/** + * Container for CustomLevelConfig objects. + */ +@Plugin(name = "CustomLevels", category = "Core", printObject = true) +public final class CustomLevels { + + private final List<CustomLevelConfig> customLevels; + + private CustomLevels(final CustomLevelConfig[] customLevels) { + this.customLevels = new ArrayList<CustomLevelConfig>(Arrays.asList(customLevels)); + } + + /** + * Create a CustomLevels object to contain all the CustomLevelConfigs. + * + * @param customLevels An array of CustomLevelConfigs. + * @return A CustomLevels object. + */ + @PluginFactory + public static CustomLevels createCustomLevels(// + @PluginElement("CustomLevels") final CustomLevelConfig[] customLevels) { + return new CustomLevels(customLevels == null ? new CustomLevelConfig[0] : customLevels); + } + + /** + * Returns a list of the {@code CustomLevelConfig} objects created during configuration. + * @return the configured custom levels + */ + public List<CustomLevelConfig> getCustomLevels() { + return customLevels; + } +} http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/ba3feb23/log4j-core/src/main/resources/Log4j-config.xsd ---------------------------------------------------------------------- diff --git a/log4j-core/src/main/resources/Log4j-config.xsd b/log4j-core/src/main/resources/Log4j-config.xsd index 20c1500..8f492d1 100644 --- a/log4j-core/src/main/resources/Log4j-config.xsd +++ b/log4j-core/src/main/resources/Log4j-config.xsd @@ -20,7 +20,10 @@ <xs:element name="Configuration" type="ConfigurationType"/> <xs:complexType name="ConfigurationType"> <xs:sequence> - <xs:element name="CustomLevel" type="CustomLevelType"/> + <xs:choice minOccurs="0" maxOccurs="1"> + <xs:element name="CustomLevels" type="CustomLevelsType"/> + <xs:element name="CustomLevel" type="CustomLevelType"/> + </xs:choice> <xs:element name="Properties" type="PropertiesType"/> <xs:choice minOccurs="0" maxOccurs="1"> <xs:element name="Filters" type="FiltersType"/> http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/ba3feb23/src/site/xdoc/manual/customloglevels.xml.vm ---------------------------------------------------------------------- diff --git a/src/site/xdoc/manual/customloglevels.xml.vm b/src/site/xdoc/manual/customloglevels.xml.vm index cdb0108..09c1121 100644 --- a/src/site/xdoc/manual/customloglevels.xml.vm +++ b/src/site/xdoc/manual/customloglevels.xml.vm @@ -140,9 +140,11 @@ logger.log(Level.getLevel("FORGOT_TO_DEFINE"), "some message"); // throws except <?xml version="1.0" encoding="UTF-8"?> <Configuration status="WARN"> <!-- Define custom levels before using them for filtering below. --> - <CustomLevel name="DIAG" intLevel="350" /> - <CustomLevel name="NOTICE" intLevel="450" /> - <CustomLevel name="VERBOSE" intLevel="550" /> + <CustomLevels> + <CustomLevel name="DIAG" intLevel="350" /> + <CustomLevel name="NOTICE" intLevel="450" /> + <CustomLevel name="VERBOSE" intLevel="550" /> + </CustomLevels> <Appenders> <Console name="Console" target="SYSTEM_OUT">
