View Javadoc
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.concurrent.ConcurrentHashMap;
23  import java.util.concurrent.ConcurrentMap;
24  
25  import org.apache.logging.log4j.spi.StandardLevel;
26  
27  /**
28   * Levels used for identifying the severity of an event. Levels are organized from most specific to least:
29   * <ul>
30   * <li>{@link #OFF} (most specific, no logging)</li>
31   * <li>{@link #FATAL} (most specific, little data)</li>
32   * <li>{@link #ERROR}</li>
33   * <li>{@link #WARN}</li>
34   * <li>{@link #INFO}</li>
35   * <li>{@link #DEBUG}</li>
36   * <li>{@link #TRACE} (least specific, a lot of data)</li>
37   * <li>{@link #ALL} (least specific, all data)</li>
38   * </ul>
39   *
40   * Typically, configuring a level in a filter or on a logger will cause logging events of that level and those
41   * that are more specific to pass through the filter.
42   * A special level, {@link #ALL}, is guaranteed to capture all levels when used in logging configurations.
43   */
44  public final class Level implements Comparable<Level>, Serializable {
45  
46      private static final long serialVersionUID = 1581082L;
47      private static final ConcurrentMap<String, Level> levels = new ConcurrentHashMap<String, Level>();
48  
49      /**
50       * No events will be logged.
51       */
52      public static final Level OFF;
53  
54      /**
55       * A severe error that will prevent the application from continuing.
56       */
57      public static final Level FATAL;
58  
59      /**
60       * An error in the application, possibly recoverable.
61       */
62      public static final Level ERROR;
63  
64      /**
65       * An event that might possible lead to an error.
66       */
67      public static final Level WARN;
68  
69      /**
70       * An event for informational purposes.
71       */
72      public static final Level INFO;
73  
74      /**
75       * A general debugging event.
76       */
77      public static final Level DEBUG;
78  
79      /**
80       * A fine-grained debug message, typically capturing the flow through the application.
81       */
82      public static final Level TRACE;
83  
84      /**
85       * All events should be logged.
86       */
87      public static final Level ALL;
88  
89      static {
90          OFF = new Level("OFF", StandardLevel.OFF.intLevel());
91          FATAL = new Level("FATAL", StandardLevel.FATAL.intLevel());
92          ERROR = new Level("ERROR", StandardLevel.ERROR.intLevel());
93          WARN = new Level("WARN", StandardLevel.WARN.intLevel());
94          INFO = new Level("INFO", StandardLevel.INFO.intLevel());
95          DEBUG = new Level("DEBUG", StandardLevel.DEBUG.intLevel());
96          TRACE = new Level("TRACE", StandardLevel.TRACE.intLevel());
97          ALL = new Level("ALL", StandardLevel.ALL.intLevel());
98      }
99  
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();
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