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