1 /*
2  * Licensed to the Apache Software Foundation (ASF) under one or more
3  * contributor license agreements. See the NOTICE file distributed with
4  * this work for additional information regarding copyright ownership.
5  * The ASF licenses this file to You under the Apache license, Version 2.0
6  * (the "License"); you may not use this file except in compliance with
7  * the License. You may obtain a copy of the License at
8  *
9  *      http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the license for the specific language governing permissions and
15  * limitations under the license.
16  */

17 package org.apache.logging.log4j;
18
19 import java.io.Serializable;
20 import java.util.Collection;
21 import java.util.Locale;
22 import java.util.Objects;
23 import java.util.concurrent.ConcurrentHashMap;
24 import java.util.concurrent.ConcurrentMap;
25
26 import org.apache.logging.log4j.spi.StandardLevel;
27 import org.apache.logging.log4j.util.Strings;
28
29 /**
30  * Levels used for identifying the severity of an event. Levels are organized from most specific to least:
31  * <table>
32  * <tr>
33  * <th>Name</th>
34  * <th>Description</th>
35  * </tr>
36  * <tr>
37  * <td>{@link #OFF}</td>
38  * <td>No events will be logged.</td>
39  * </tr>
40  * <tr>
41  * <td>{@link #FATAL}</td>
42  * <td>A fatal event that will prevent the application from continuing.</td>
43  * </tr>
44  * <tr>
45  * <td>{@link #ERROR}</td>
46  * <td>An error in the application, possibly recoverable.</td>
47  * </tr>
48  * <tr>
49  * <td>{@link #WARN}</td>
50  * <td>An event that might possible lead to an error.</td>
51  * </tr>
52  * <tr>
53  * <td>{@link #INFO}</td>
54  * <td>An event for informational purposes.</td>
55  * </tr>
56  * <tr>
57  * <td>{@link #DEBUG}</td>
58  * <td>A general debugging event.</td>
59  * </tr>
60  * <tr>
61  * <td>{@link #TRACE}</td>
62  * <td>A fine-grained debug message, typically capturing the flow through the application.</td>
63  * </tr>
64  * <tr>
65  * <td>{@link #ALL}</td>
66  * <td>All events should be logged.</td>
67  * </tr>
68  * </table>
69  * <p>
70  * Typically, configuring a level in a filter or on a logger will cause logging events of that level and those that are
71  * more specific to pass through the filter. A special level, {@link #ALL}, is guaranteed to capture all levels when
72  * used in logging configurations.
73  * </p>
74  */

75 public final class Level implements Comparable<Level>, Serializable {
76
77     private static final Level[] EMPTY_ARRAY = {};
78
79     private static final ConcurrentMap<String, Level> LEVELS = new ConcurrentHashMap<>(); // SUPPRESS CHECKSTYLE
80
81     /**
82      * No events will be logged.
83      */

84     public static final Level OFF = new Level("OFF", StandardLevel.OFF.intLevel());
85
86     /**
87      * A fatal event that will prevent the application from continuing.
88      */

89     public static final Level FATAL = new Level("FATAL", StandardLevel.FATAL.intLevel());
90
91     /**
92      * An error in the application, possibly recoverable.
93      */

94     public static final Level ERROR = new Level("ERROR", StandardLevel.ERROR.intLevel());
95
96     /**
97      * An event that might possible lead to an error.
98      */

99     public static final Level WARN = new Level("WARN", StandardLevel.WARN.intLevel());
100
101     /**
102      * An event for informational purposes.
103      */

104     public static final Level INFO = new Level("INFO", StandardLevel.INFO.intLevel());
105
106     /**
107      * A general debugging event.
108      */

109     public static final Level DEBUG = new Level("DEBUG", StandardLevel.DEBUG.intLevel());
110
111     /**
112      * A fine-grained debug message, typically capturing the flow through the application.
113      */

114     public static final Level TRACE = new Level("TRACE", StandardLevel.TRACE.intLevel());
115
116     /**
117      * All events should be logged.
118      */

119     public static final Level ALL = new Level("ALL", StandardLevel.ALL.intLevel());
120
121     /**
122      * @since 2.1
123      */

124     public static final String CATEGORY = "Level";
125
126     private static final long serialVersionUID = 1581082L;
127
128     private final String name;
129     private final int intLevel;
130     private final StandardLevel standardLevel;
131
132     private Level(final String name, final int intLevel) {
133         if (Strings.isEmpty(name)) {
134             throw new IllegalArgumentException("Illegal null or empty Level name.");
135         }
136         if (intLevel < 0) {
137             throw new IllegalArgumentException("Illegal Level int less than zero.");
138         }
139         this.name = name;
140         this.intLevel = intLevel;
141         this.standardLevel = StandardLevel.getStandardLevel(intLevel);
142         if (LEVELS.putIfAbsent(name, this) != null) {
143             throw new IllegalStateException("Level " + name + " has already been defined.");
144         }
145     }
146
147     /**
148      * Gets the integral value of this Level.
149      *
150      * @return the value of this Level.
151      */

152     public int intLevel() {
153         return this.intLevel;
154     }
155
156     /**
157      * Gets the standard Level values as an enum.
158      *
159      * @return an enum of the standard Levels.
160      */

161     public StandardLevel getStandardLevel() {
162         return standardLevel;
163     }
164
165     /**
166      * Compares this level against the levels passed as arguments and returns true if this level is in between the given
167      * levels.
168      *
169      * @param minLevel The minimum level to test.
170      * @param maxLevel The maximum level to test.
171      * @return True true if this level is in between the given levels
172      * @since 2.4
173      */

174     public boolean isInRange(final Level minLevel, final Level maxLevel) {
175         return this.intLevel >= minLevel.intLevel && this.intLevel <= maxLevel.intLevel;
176     }
177
178     /**
179      * Compares this level against the level passed as an argument and returns true if this level is the same or is less
180      * specific.
181      * <p>
182      * Concretely, {@link #ALL} is less specific than {@link #TRACE}, which is less specific than {@link #DEBUG}, which
183      * is less specific than {@link #INFO}, which is less specific than {@link #WARN}, which is less specific than
184      * {@link #ERROR}, which is less specific than {@link #FATAL}, and finally {@link #OFF}, which is the most specific
185      * standard level.
186      * </p>
187      *
188      * @param level
189      *            The level to test.
190      * @return True if this level Level is less specific or the same as the given Level.
191      */

192     public boolean isLessSpecificThan(final Level level) {
193         return this.intLevel >= level.intLevel;
194     }
195
196     /**
197      * Compares this level against the level passed as an argument and returns true if this level is the same or is more
198      * specific.
199      * <p>
200      * Concretely, {@link #FATAL} is more specific than {@link #ERROR}, which is more specific than {@link #WARN},
201      * etc., until {@link #TRACE}, and finally {@link #ALL}, which is the least specific standard level.
202      * The most specific level is {@link #OFF}.
203      * </p>
204      *
205      * @param level The level to test.
206      * @return True if this level Level is more specific or the same as the given Level.
207      */

208     public boolean isMoreSpecificThan(final Level level) {
209         return this.intLevel <= level.intLevel;
210     }
211
212     @Override
213     @SuppressWarnings("CloneDoesntCallSuperClone")
214     // CHECKSTYLE:OFF
215     public Level clone() throws CloneNotSupportedException {
216         throw new CloneNotSupportedException();
217     }
218     // CHECKSTYLE:ON
219
220     @Override
221     public int compareTo(final Level other) {
222         return intLevel < other.intLevel ? -1 : (intLevel > other.intLevel ? 1 : 0);
223     }
224
225     @Override
226     public boolean equals(final Object other) {
227         return other instanceof Level && other == this;
228     }
229
230     public Class<Level> getDeclaringClass() {
231         return Level.class;
232     }
233
234     @Override
235     public int hashCode() {
236         return this.name.hashCode();
237     }
238
239     /**
240      * Gets the symbolic name of this Level. Equivalent to calling {@link #toString()}.
241      *
242      * @return the name of this Level.
243      */

244     public String name() {
245         return this.name;
246     }
247
248     @Override
249     public String toString() {
250         return this.name;
251     }
252
253     /**
254      * Retrieves an existing Level or creates on if it didn't previously exist.
255      *
256      * @param name The name of the level.
257      * @param intValue The integer value for the Level. If the level was previously created this value is ignored.
258      * @return The Level.
259      * @throws java.lang.IllegalArgumentException if the name is null or intValue is less than zero.
260      */

261     public static Level forName(final String name, final int intValue) {
262         final Level level = LEVELS.get(name);
263         if (level != null) {
264             return level;
265         }
266         try {
267             return new Level(name, intValue);
268         } catch (final IllegalStateException ex) {
269             // The level was added by something else so just return that one.
270             return LEVELS.get(name);
271         }
272     }
273
274     /**
275      * Return the Level associated with the name or null if the Level cannot be found.
276      *
277      * @param name The name of the Level.
278      * @return The Level or null.
279      */

280     public static Level getLevel(final String name) {
281         return LEVELS.get(name);
282     }
283
284     /**
285      * Converts the string passed as argument to a level. If the conversion fails, then this method returns
286      * {@link #DEBUG}.
287      *
288      * @param level The name of the desired Level.
289      * @return The Level associated with the String.
290      */

291     public static Level toLevel(final String level) {
292         return toLevel(level, Level.DEBUG);
293     }
294
295     /**
296      * Converts the string passed as argument to a level. If the conversion fails, then this method returns the value of
297      * <code>defaultLevel</code>.
298      *
299      * @param name The name of the desired Level.
300      * @param defaultLevel The Level to use if the String is invalid.
301      * @return The Level associated with the String.
302      */

303     public static Level toLevel(final String name, final Level defaultLevel) {
304         if (name == null) {
305             return defaultLevel;
306         }
307         final Level level = LEVELS.get(toUpperCase(name.trim()));
308         return level == null ? defaultLevel : level;
309     }
310
311     private static String toUpperCase(final String name) {
312         return name.toUpperCase(Locale.ENGLISH);
313     }
314
315     /**
316      * Return an array of all the Levels that have been registered.
317      *
318      * @return An array of Levels.
319      */

320     public static Level[] values() {
321         return Level.LEVELS.values().toArray(EMPTY_ARRAY);
322     }
323
324     /**
325      * Return the Level associated with the name.
326      *
327      * @param name The name of the Level to return.
328      * @return The Level.
329      * @throws java.lang.NullPointerException if the Level name is {@code null}.
330      * @throws java.lang.IllegalArgumentException if the Level name is not registered.
331      */

332     public static Level valueOf(final String name) {
333         Objects.requireNonNull(name, "No level name given.");
334         final String levelName = toUpperCase(name.trim());
335         final Level level = LEVELS.get(levelName);
336         if (level != null) {
337             return level;
338         }
339         throw new IllegalArgumentException("Unknown level constant [" + levelName + "].");
340     }
341
342     /**
343      * Returns the enum constant of the specified enum type with the specified name. The name must match exactly an
344      * identifier used to declare an enum constant in this type. (Extraneous whitespace characters are not permitted.)
345      *
346      * @param enumType the {@code Class} object of the enum type from which to return a constant
347      * @param name the name of the constant to return
348      * @param <T> The enum type whose constant is to be returned
349      * @return the enum constant of the specified enum type with the specified name
350      * @throws java.lang.IllegalArgumentException if the specified enum type has no constant with the specified name, or
351      *             the specified class object does not represent an enum type
352      * @throws java.lang.NullPointerException if {@code enumType} or {@code name} are {@code null}
353      * @see java.lang.Enum#valueOf(Class, String)
354      */

355     public static <T extends Enum<T>> T valueOf(final Class<T> enumType, final String name) {
356         return Enum.valueOf(enumType, name);
357     }
358
359     // for deserialization
360     protected Object readResolve() {
361         return Level.valueOf(this.name);
362     }
363 }
364