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     */
017    package org.apache.logging.log4j;
018    
019    import java.io.Serializable;
020    import java.util.Collection;
021    import java.util.Locale;
022    import java.util.concurrent.ConcurrentHashMap;
023    import java.util.concurrent.ConcurrentMap;
024    
025    import org.apache.logging.log4j.spi.StandardLevel;
026    
027    /**
028     * Levels used for identifying the severity of an event. Levels are organized from most specific to least:
029     * <ul>
030     * <li>{@link #OFF} (most specific, no logging)</li>
031     * <li>{@link #FATAL} (most specific, little data)</li>
032     * <li>{@link #ERROR}</li>
033     * <li>{@link #WARN}</li>
034     * <li>{@link #INFO}</li>
035     * <li>{@link #DEBUG}</li>
036     * <li>{@link #TRACE} (least specific, a lot of data)</li>
037     * <li>{@link #ALL} (least specific, all data)</li>
038     * </ul>
039     *
040     * Typically, configuring a level in a filter or on a logger will cause logging events of that level and those
041     * that are more specific to pass through the filter.
042     * A special level, {@link #ALL}, is guaranteed to capture all levels when used in logging configurations.
043     */
044    public final class Level implements Comparable<Level>, Serializable {
045    
046        private static final long serialVersionUID = 1581082L;
047        private static final ConcurrentMap<String, Level> levels = new ConcurrentHashMap<String, Level>();
048    
049        /**
050         * No events will be logged.
051         */
052        public static final Level OFF;
053    
054        /**
055         * A severe error that will prevent the application from continuing.
056         */
057        public static final Level FATAL;
058    
059        /**
060         * An error in the application, possibly recoverable.
061         */
062        public static final Level ERROR;
063    
064        /**
065         * An event that might possible lead to an error.
066         */
067        public static final Level WARN;
068    
069        /**
070         * An event for informational purposes.
071         */
072        public static final Level INFO;
073    
074        /**
075         * A general debugging event.
076         */
077        public static final Level DEBUG;
078    
079        /**
080         * A fine-grained debug message, typically capturing the flow through the application.
081         */
082        public static final Level TRACE;
083    
084        /**
085         * All events should be logged.
086         */
087        public static final Level ALL;
088    
089        static {
090            OFF = new Level("OFF", StandardLevel.OFF.intLevel());
091            FATAL = new Level("FATAL", StandardLevel.FATAL.intLevel());
092            ERROR = new Level("ERROR", StandardLevel.ERROR.intLevel());
093            WARN = new Level("WARN", StandardLevel.WARN.intLevel());
094            INFO = new Level("INFO", StandardLevel.INFO.intLevel());
095            DEBUG = new Level("DEBUG", StandardLevel.DEBUG.intLevel());
096            TRACE = new Level("TRACE", StandardLevel.TRACE.intLevel());
097            ALL = new Level("ALL", StandardLevel.ALL.intLevel());
098        }
099    
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