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     private final String name;
101     private final int intLevel;
102     private final StandardLevel standardLevel;
103 
104     private Level(final String name, final int intLevel) {
105         if (name == null || name.isEmpty()) {
106             throw new IllegalArgumentException("Illegal null Level constant");
107         }
108         if (intLevel < 0) {
109             throw new IllegalArgumentException("Illegal Level int less than zero.");
110         }
111         this.name = name;
112         this.intLevel = intLevel;
113         this.standardLevel = StandardLevel.getStandardLevel(intLevel);
114         if (levels.putIfAbsent(name, this) != null) {
115             throw new IllegalStateException("Level " + name + " has already been defined.");
116         }
117     }
118 
119     /**
120      * Gets the integral value of this Level.
121      *
122      * @return the value of this Level.
123      */
124     public int intLevel() {
125         return this.intLevel;
126     }
127 
128     /**
129      * Gets the standard Level values as an enum.
130      *
131      * @return an enum of the standard Levels.
132      */
133     public StandardLevel getStandardLevel() {
134         return standardLevel;
135     }
136 
137     /**
138      * Compares this level against the level passed as an argument and returns true if this level is the same or is less
139      * specific.T
140      *
141      * @param level
142      *            The level to test.
143      * @return True if this level Level is less specific or the same as the given Level.
144      */
145     public boolean isLessSpecificThan(final Level level) {
146         return this.intLevel >= level.intLevel;
147     }
148 
149     /**
150      * Compares this level against the level passed as an argument and returns true if this level is the same or is more
151      * specific.
152      *
153      * @param level
154      *            The level to test.
155      * @return True if this level Level is more specific or the same as the given Level.
156      */
157     public boolean isMoreSpecificThan(final Level level) {
158         return this.intLevel <= level.intLevel;
159     }
160 
161     @Override
162     @SuppressWarnings("CloneDoesntCallSuperClone")
163     public Level clone() throws CloneNotSupportedException {
164         throw new CloneNotSupportedException();
165     }
166 
167     @Override
168     public int compareTo(final Level other) {
169         return intLevel < other.intLevel ? -1 : (intLevel > other.intLevel ? 1 : 0);
170     }
171 
172     @Override
173     public boolean equals(final Object other) {
174         return other instanceof Level && other == this;
175     }
176 
177     public Class<Level> getDeclaringClass() {
178         return Level.class;
179     }
180 
181     @Override
182     public int hashCode() {
183         return this.name.hashCode();
184     }
185 
186     /**
187      * Gets the symbolic name of this Level. Equivalent to calling {@link #toString()}.
188      *
189      * @return the name of this Level.
190      */
191     public String name() {
192         return this.name;
193     }
194 
195     @Override
196     public String toString() {
197         return this.name;
198     }
199 
200     /**
201      * Retrieves an existing Level or creates on if it didn't previously exist.
202      * @param name The name of the level.
203      * @param intValue The integer value for the Level. If the level was previously created this value is ignored.
204      * @return The Level.
205      * @throws java.lang.IllegalArgumentException if the name is null or intValue is less than zero.
206      */
207     public static Level forName(final String name, final int intValue) {
208         final Level level = levels.get(name);
209         if (level != null) {
210             return level;
211         }
212         try {
213             return new Level(name, intValue);
214         } catch (final IllegalStateException ex) {
215             // The level was added by something else so just return that one.
216             return levels.get(name);
217         }
218     }
219 
220     /**
221      * Return the Level associated with the name or null if the Level cannot be found.
222      * @param name The name of the Level.
223      * @return The Level or null.
224      */
225     public static Level getLevel(final String name) {
226         return levels.get(name);
227     }
228 
229     /**
230      * Converts the string passed as argument to a level. If the
231      * conversion fails, then this method returns {@link #DEBUG}.
232      *
233      * @param sArg The name of the desired Level.
234      * @return The Level associated with the String.
235      */
236     public static Level toLevel(final String sArg) {
237         return toLevel(sArg, Level.DEBUG);
238     }
239 
240     /**
241      * Converts the string passed as argument to a level. If the
242      * conversion fails, then this method returns the value of
243      * <code>defaultLevel</code>.
244      *
245      * @param name The name of the desired Level.
246      * @param defaultLevel The Level to use if the String is invalid.
247      * @return The Level associated with the String.
248      */
249     public static Level toLevel(final String name, final Level defaultLevel) {
250         if (name == null) {
251             return defaultLevel;
252         }
253         final Level level = levels.get(name.toUpperCase(Locale.ENGLISH));
254         return level == null ? defaultLevel : level;
255     }
256 
257     /**
258      * Return an array of all the Levels that have been registered.
259      * @return An array of Levels.
260      */
261     public static Level[] values() {
262         final Collection<Level> values = Level.levels.values();
263         return values.toArray(new Level[values.size()]);
264     }
265 
266     /**
267      * Return the Level associated with the name.
268      * @param name The name of the Level to return.
269      * @return The Level.
270      * @throws java.lang.NullPointerException if the Level name is {@code null}.
271      * @throws java.lang.IllegalArgumentException if the Level name is not registered.
272      */
273     public static Level valueOf(final String name) {
274         if (name == null) {
275             throw new NullPointerException("No level name given.");
276         }
277         final String levelName = name.toUpperCase();
278         if (levels.containsKey(levelName)) {
279             return levels.get(levelName);
280         }
281         throw new IllegalArgumentException("Unknown level constant [" + levelName + "].");
282     }
283 
284     /**
285      * Returns the enum constant of the specified enum type with the specified name. The name must match exactly an
286      * identifier used to declare an enum constant in this type. (Extraneous whitespace characters are not permitted.)
287      *
288      * @param enumType the {@code Class} object of the enum type from which to return a constant
289      * @param name     the name of the constant to return
290      * @param <T>      The enum type whose constant is to be returned
291      * @return the enum constant of the specified enum type with the specified name
292      * @throws java.lang.IllegalArgumentException if the specified enum type has no constant with the specified name,
293      *                                            or the specified class object does not represent an enum type
294      * @throws java.lang.NullPointerException     if {@code enumType} or {@code name} are {@code null}
295      * @see java.lang.Enum#valueOf(Class, String)
296      */
297     public static <T extends Enum<T>> T valueOf(final Class<T> enumType, final String name) {
298         return Enum.valueOf(enumType, name);
299     }
300 
301     // for deserialization
302     protected Object readResolve() {
303         return Level.valueOf(this.name);
304     }
305 }
306