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