    001    /*
    002     * Licensed to the Apache Software Foundation (ASF) under one or more
    003     * contributor license agreements. See the NOTICE file distributed with
    004     * this work for additional information regarding copyright ownership.
    005     * The ASF licenses this file to You under the Apache license, Version 2.0
    006     * (the "License"); you may not use this file except in compliance with
    007     * the License. You may obtain a copy of the License at
    008     *
    009     *      http://www.apache.org/licenses/LICENSE-2.0
    010     *
    011     * Unless required by applicable law or agreed to in writing, software
    012     * distributed under the License is distributed on an "AS IS" BASIS,
    013     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    014     * See the license for the specific language governing permissions and
    015     * limitations under the license.
    016     */
    017    package org.apache.logging.log4j;
    018
    019    import java.io.Serializable;
    020    import java.util.Collection;
    021    import java.util.Locale;
    022    import java.util.concurrent.ConcurrentHashMap;
    023    import java.util.concurrent.ConcurrentMap;
    024
    025    import org.apache.logging.log4j.spi.StandardLevel;
    026
    027    /**
    028     * Levels used for identifying the severity of an event. Levels are organized from most specific to least:
    029     * <ul>
    030     * <li>{@link #OFF} (most specific, no logging)</li>
    031     * <li>{@link #FATAL} (most specific, little data)</li>
    032     * <li>{@link #ERROR}</li>
    033     * <li>{@link #WARN}</li>
    034     * <li>{@link #INFO}</li>
    035     * <li>{@link #DEBUG}</li>
    036     * <li>{@link #TRACE} (least specific, a lot of data)</li>
    037     * <li>{@link #ALL} (least specific, all data)</li>
    038     * </ul>
    039     *
    040     * Typically, configuring a level in a filter or on a logger will cause logging events of that level and those
    041     * that are more specific to pass through the filter.
    042     * A special level, {@link #ALL}, is guaranteed to capture all levels when used in logging configurations.
    043     */
    044    public final class Level implements Comparable<Level>, Serializable {
    045
    046        private static final long serialVersionUID = 1581082L;
    047        private static final ConcurrentMap<String, Level> levels = new ConcurrentHashMap<String, Level>();
    048
    049        /**
    050         * No events will be logged.
    051         */
    052        public static final Level OFF;
    053
    054        /**
    055         * A severe error that will prevent the application from continuing.
    056         */
    057        public static final Level FATAL;
    058
    059        /**
    060         * An error in the application, possibly recoverable.
    061         */
    062        public static final Level ERROR;
    063
    064        /**
    065         * An event that might possible lead to an error.
    066         */
    067        public static final Level WARN;
    068
    069        /**
    070         * An event for informational purposes.
    071         */
    072        public static final Level INFO;
    073
    074        /**
    075         * A general debugging event.
    076         */
    077        public static final Level DEBUG;
    078
    079        /**
    080         * A fine-grained debug message, typically capturing the flow through the application.
    081         */
    082        public static final Level TRACE;
    083
    084        /**
    085         * All events should be logged.
    086         */
    087        public static final Level ALL;
    088
    089        static {
    090            OFF = new Level("OFF", StandardLevel.OFF.intLevel());
    091            FATAL = new Level("FATAL", StandardLevel.FATAL.intLevel());
    092            ERROR = new Level("ERROR", StandardLevel.ERROR.intLevel());
    093            WARN = new Level("WARN", StandardLevel.WARN.intLevel());
    094            INFO = new Level("INFO", StandardLevel.INFO.intLevel());
    095            DEBUG = new Level("DEBUG", StandardLevel.DEBUG.intLevel());
    096            TRACE = new Level("TRACE", StandardLevel.TRACE.intLevel());
    097            ALL = new Level("ALL", StandardLevel.ALL.intLevel());
    098        }
    099
    100        /**
    101         * @since 2.1
    102         */
    103        public static final String CATEGORY = "Level";
    104
    105        private final String name;
    106        private final int intLevel;
    107        private final StandardLevel standardLevel;
    108
    109        private Level(final String name, final int intLevel) {
    110            if (name == null || name.isEmpty()) {
    111                throw new IllegalArgumentException("Illegal null Level constant");
    112            }
    113            if (intLevel < 0) {
    114                throw new IllegalArgumentException("Illegal Level int less than zero.");
    115            }
    116            this.name = name;
    117            this.intLevel = intLevel;
    118            this.standardLevel = StandardLevel.getStandardLevel(intLevel);
    119            if (levels.putIfAbsent(name, this) != null) {
    120                throw new IllegalStateException("Level " + name + " has already been defined.");
    121            }
    122        }
    123
    124        /**
    125         * Gets the integral value of this Level.
    126         *
    127         * @return the value of this Level.
    128         */
    129        public int intLevel() {
    130            return this.intLevel;
    131        }
    132
    133        /**
    134         * Gets the standard Level values as an enum.
    135         *
    136         * @return an enum of the standard Levels.
    137         */
    138        public StandardLevel getStandardLevel() {
    139            return standardLevel;
    140        }
    141
    142        /**
    143         * Compares this level against the level passed as an argument and returns true if this level is the same or is less
    144         * specific.T
    145         *
    146         * @param level
    147         *            The level to test.
    148         * @return True if this level Level is less specific or the same as the given Level.
    149         */
    150        public boolean isLessSpecificThan(final Level level) {
    151            return this.intLevel >= level.intLevel;
    152        }
    153
    154        /**
    155         * Compares this level against the level passed as an argument and returns true if this level is the same or is more
    156         * specific.
    157         *
    158         * @param level
    159         *            The level to test.
    160         * @return True if this level Level is more specific or the same as the given Level.
    161         */
    162        public boolean isMoreSpecificThan(final Level level) {
    163            return this.intLevel <= level.intLevel;
    164        }
    165
    166        @Override
    167        @SuppressWarnings("CloneDoesntCallSuperClone")
    168        public Level clone() throws CloneNotSupportedException {
    169            throw new CloneNotSupportedException();
    170        }
    171
    172        @Override
    173        public int compareTo(final Level other) {
    174            return intLevel < other.intLevel ? -1 : (intLevel > other.intLevel ? 1 : 0);
    175        }
    176
    177        @Override
    178        public boolean equals(final Object other) {
    179            return other instanceof Level && other == this;
    180        }
    181
    182        public Class<Level> getDeclaringClass() {
    183            return Level.class;
    184        }
    185
    186        @Override
    187        public int hashCode() {
    188            return this.name.hashCode();
    189        }
    190
    191        /**
    192         * Gets the symbolic name of this Level. Equivalent to calling {@link #toString()}.
    193         *
    194         * @return the name of this Level.
    195         */
    196        public String name() {
    197            return this.name;
    198        }
    199
    200        @Override
    201        public String toString() {
    202            return this.name;
    203        }
    204
    205        /**
    206         * Retrieves an existing Level or creates on if it didn't previously exist.
    207         * @param name The name of the level.
    208         * @param intValue The integer value for the Level. If the level was previously created this value is ignored.
    209         * @return The Level.
    210         * @throws java.lang.IllegalArgumentException if the name is null or intValue is less than zero.
    211         */
    212        public static Level forName(final String name, final int intValue) {
    213            final Level level = levels.get(name);
    214            if (level != null) {
    215                return level;
    216            }
    217            try {
    218                return new Level(name, intValue);
    219            } catch (final IllegalStateException ex) {
    220                // The level was added by something else so just return that one.
    221                return levels.get(name);
    222            }
    223        }
    224
    225        /**
    226         * Return the Level associated with the name or null if the Level cannot be found.
    227         * @param name The name of the Level.
    228         * @return The Level or null.
    229         */
    230        public static Level getLevel(final String name) {
    231            return levels.get(name);
    232        }
    233
    234        /**
    235         * Converts the string passed as argument to a level. If the
    236         * conversion fails, then this method returns {@link #DEBUG}.
    237         *
    238         * @param sArg The name of the desired Level.
    239         * @return The Level associated with the String.
    240         */
    241        public static Level toLevel(final String sArg) {
    242            return toLevel(sArg, Level.DEBUG);
    243        }
    244
    245        /**
    246         * Converts the string passed as argument to a level. If the
    247         * conversion fails, then this method returns the value of
    248         * <code>defaultLevel</code>.
    249         *
    250         * @param name The name of the desired Level.
    251         * @param defaultLevel The Level to use if the String is invalid.
    252         * @return The Level associated with the String.
    253         */
    254        public static Level toLevel(final String name, final Level defaultLevel) {
    255            if (name == null) {
    256                return defaultLevel;
    257            }
    258            final Level level = levels.get(name.toUpperCase(Locale.ENGLISH));
    259            return level == null ? defaultLevel : level;
    260        }
    261
    262        /**
    263         * Return an array of all the Levels that have been registered.
    264         * @return An array of Levels.
    265         */
    266        public static Level[] values() {
    267            final Collection<Level> values = Level.levels.values();
    268            return values.toArray(new Level[values.size()]);
    269        }
    270
    271        /**
    272         * Return the Level associated with the name.
    273         * @param name The name of the Level to return.
    274         * @return The Level.
    275         * @throws java.lang.NullPointerException if the Level name is {@code null}.
    276         * @throws java.lang.IllegalArgumentException if the Level name is not registered.
    277         */
    278        public static Level valueOf(final String name) {
    279            if (name == null) {
    280                throw new NullPointerException("No level name given.");
    281            }
    282            final String levelName = name.toUpperCase(Locale.ENGLISH);
    283            if (levels.containsKey(levelName)) {
    284                return levels.get(levelName);
    285            }
    286            throw new IllegalArgumentException("Unknown level constant [" + levelName + "].");
    287        }
    288
    289        /**
    290         * Returns the enum constant of the specified enum type with the specified name. The name must match exactly an
    291         * identifier used to declare an enum constant in this type. (Extraneous whitespace characters are not permitted.)
    292         *
    293         * @param enumType the {@code Class} object of the enum type from which to return a constant
    294         * @param name     the name of the constant to return
    295         * @param <T>      The enum type whose constant is to be returned
    296         * @return the enum constant of the specified enum type with the specified name
    297         * @throws java.lang.IllegalArgumentException if the specified enum type has no constant with the specified name,
    298         *                                            or the specified class object does not represent an enum type
    299         * @throws java.lang.NullPointerException     if {@code enumType} or {@code name} are {@code null}
    300         * @see java.lang.Enum#valueOf(Class, String)
    301         */
    302        public static <T extends Enum<T>> T valueOf(final Class<T> enumType, final String name) {
    303            return Enum.valueOf(enumType, name);
    304        }
    305
    306        // for deserialization
    307        protected Object readResolve() {
    308            return Level.valueOf(this.name);
    309        }
    310    }
    311