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 */
017package org.apache.logging.log4j;
018
019import java.io.Serializable;
020import java.util.Collection;
021import java.util.Locale;
022import java.util.concurrent.ConcurrentHashMap;
023import java.util.concurrent.ConcurrentMap;
024
025import 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)</li>
031 * <li>{@link #FATAL}</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}</li>
037 * <li>{@link #ALL} (least specific)</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 */
044public final class Level implements Comparable<Level>, Serializable {
045
046    private static final long serialVersionUID = 3077535362528045615L;
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(String name, int intLevel) {
105        if (name == null || name.length() == 0) {
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    public int intLevel() {
120        return this.intLevel;
121    }
122
123    public StandardLevel getStandardLevel() {
124        return standardLevel;
125    }
126
127    /**
128     * Compares this level against the level passed as an argument and returns true if this
129     * level is the same or more specific.
130     *
131     * @param level The level to check.
132     * @return True if the passed Level is more specific or the same as this Level.
133     */
134    public boolean isAtLeastAsSpecificAs(final Level level) {
135        return this.intLevel <= level.intLevel;
136    }
137
138    /**
139     * Compares this level against the level passed as an argument and returns true if this
140     * level is the same or more specific.
141     *
142     * @param level The level to check.
143     * @return True if the passed Level is more specific or the same as this Level.
144     */
145    public boolean isAtLeastAsSpecificAs(final int level) {
146        return this.intLevel <= level;
147    }
148
149    /**
150     * Compares the specified Level against this one.
151     * @param level The level to check.
152     * @return True if the passed Level is more specific or the same as this Level.
153     */
154    public boolean lessOrEqual(final Level level) {
155        return this.intLevel <= level.intLevel;
156    }
157
158    /**
159     * Compares the specified Level against this one.
160     * @param level The level to check.
161     * @return True if the passed Level is more specific or the same as this Level.
162     */
163    public boolean lessOrEqual(final int level) {
164        return this.intLevel <= level;
165    }
166
167    @Override
168    @SuppressWarnings("CloneDoesntCallSuperClone")
169    public Level clone() throws CloneNotSupportedException {
170        throw new CloneNotSupportedException();
171    }
172
173    @Override
174    public int compareTo(Level other) {
175        return intLevel < other.intLevel ? -1 : (intLevel > other.intLevel ? 1 : 0);
176    }
177
178    @Override
179    public boolean equals(Object other) {
180        return other instanceof Level && other == this;
181    }
182
183    public Class<Level> getDeclaringClass() {
184        return Level.class;
185    }
186
187    @Override
188    public int hashCode() {
189        return this.name.hashCode();
190    }
191
192
193    public String name() {
194        return this.name;
195    }
196
197    @Override
198    public String toString() {
199        return this.name;
200    }
201
202    /**
203     * Retrieves an existing Level or creates on if it didn't previously exist.
204     * @param name The name of the level.
205     * @param intValue The integer value for the Level. If the level was previously created this value is ignored.
206     * @return The Level.
207     * @throws java.lang.IllegalArgumentException if the name is null or intValue is less than zero.
208     */
209    public static Level forName(String name, int intValue) {
210        Level level = levels.get(name);
211        if (level != null) {
212            return level;
213        }
214        try {
215            return new Level(name, intValue);
216        } catch (IllegalStateException ex) {
217            // The level was added by something else so just return that one.
218            return levels.get(name);
219        }
220    }
221
222    /**
223     * Return the Level assoicated with the name or null if the Level cannot be found.
224     * @param name The name of the Level.
225     * @return The Level or null.
226     */
227    public static Level getLevel(String name) {
228        return levels.get(name);
229    }
230
231    /**
232     * Converts the string passed as argument to a level. If the
233     * conversion fails, then this method returns {@link #DEBUG}.
234     *
235     * @param sArg The name of the desired Level.
236     * @return The Level associated with the String.
237     */
238    public static Level toLevel(final String sArg) {
239        return toLevel(sArg, Level.DEBUG);
240    }
241
242    /**
243     * Converts the string passed as argument to a level. If the
244     * conversion fails, then this method returns the value of
245     * <code>defaultLevel</code>.
246     *
247     * @param name The name of the desired Level.
248     * @param defaultLevel The Level to use if the String is invalid.
249     * @return The Level associated with the String.
250     */
251    public static Level toLevel(final String name, final Level defaultLevel) {
252        if (name == null) {
253            return defaultLevel;
254        }
255        Level level = levels.get(name.toUpperCase(Locale.ENGLISH));
256        return level == null ? defaultLevel : level;
257    }
258
259    /**
260     * Return an array of all the Levels that have been registered.
261     * @return An array of Levels.
262     */
263    public static Level[] values() {
264        Collection<Level> values = Level.levels.values();
265        return values.toArray(new Level[values.size()]);
266    }
267
268    /**
269     * Return the Level associated with the name.
270     * @param name The name of the Level to return.
271     * @return The Level.
272     * @throws java.lang.IllegalArgumentException if the Level name is not registered.
273     */
274    public static Level valueOf(String name) {
275        if (name == null) {
276            throw new IllegalArgumentException("Unknown level constant [" + name + "].");
277        }
278        name = name.toUpperCase();
279        if (levels.containsKey(name)) {
280            return levels.get(name);
281        }
282        throw new IllegalArgumentException("Unknown level constant [" + name + "].");
283    }
284
285    public static <T extends Enum<T>> T valueOf(Class<T> enumType, String name) {
286        return Enum.valueOf(enumType, name);
287    }
288
289    // for deserialization
290    protected Object readResolve() {
291        return Level.valueOf(this.name);
292    }
293}
294