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        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