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