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.Objects; 023import java.util.concurrent.ConcurrentHashMap; 024import java.util.concurrent.ConcurrentMap; 025 026import org.apache.logging.log4j.spi.StandardLevel; 027import org.apache.logging.log4j.util.Strings; 028 029/** 030 * Levels used for identifying the severity of an event. Levels are organized from most specific to least: 031 * <ul> 032 * <li>{@link #OFF} (most specific, no logging)</li> 033 * <li>{@link #FATAL} (most specific, little data)</li> 034 * <li>{@link #ERROR}</li> 035 * <li>{@link #WARN}</li> 036 * <li>{@link #INFO}</li> 037 * <li>{@link #DEBUG}</li> 038 * <li>{@link #TRACE} (least specific, a lot of data)</li> 039 * <li>{@link #ALL} (least specific, all data)</li> 040 * </ul> 041 * 042 * Typically, configuring a level in a filter or on a logger will cause logging events of that level and those that are 043 * more specific to pass through the filter. A special level, {@link #ALL}, is guaranteed to capture all levels when 044 * used in logging configurations. 045 */ 046public final class Level implements Comparable<Level>, Serializable { 047 048 /** 049 * No events will be logged. 050 */ 051 public static final Level OFF; 052 053 /** 054 * A severe error that will prevent the application from continuing. 055 */ 056 public static final Level FATAL; 057 058 /** 059 * An error in the application, possibly recoverable. 060 */ 061 public static final Level ERROR; 062 063 /** 064 * An event that might possible lead to an error. 065 */ 066 public static final Level WARN; 067 068 /** 069 * An event for informational purposes. 070 */ 071 public static final Level INFO; 072 073 /** 074 * A general debugging event. 075 */ 076 public static final Level DEBUG; 077 078 /** 079 * A fine-grained debug message, typically capturing the flow through the application. 080 */ 081 public static final Level TRACE; 082 083 /** 084 * All events should be logged. 085 */ 086 public static final Level ALL; 087 088 /** 089 * @since 2.1 090 */ 091 public static final String CATEGORY = "Level"; 092 093 private static final ConcurrentMap<String, Level> LEVELS = new ConcurrentHashMap<>(); // SUPPRESS CHECKSTYLE 094 095 private static final long serialVersionUID = 1581082L; 096 097 static { 098 OFF = new Level("OFF", StandardLevel.OFF.intLevel()); 099 FATAL = new Level("FATAL", StandardLevel.FATAL.intLevel()); 100 ERROR = new Level("ERROR", StandardLevel.ERROR.intLevel()); 101 WARN = new Level("WARN", StandardLevel.WARN.intLevel()); 102 INFO = new Level("INFO", StandardLevel.INFO.intLevel()); 103 DEBUG = new Level("DEBUG", StandardLevel.DEBUG.intLevel()); 104 TRACE = new Level("TRACE", StandardLevel.TRACE.intLevel()); 105 ALL = new Level("ALL", StandardLevel.ALL.intLevel()); 106 } 107 108 private final String name; 109 private final int intLevel; 110 private final StandardLevel standardLevel; 111 112 private Level(final String name, final int intLevel) { 113 if (Strings.isEmpty(name)) { 114 throw new IllegalArgumentException("Illegal null or empty Level name."); 115 } 116 if (intLevel < 0) { 117 throw new IllegalArgumentException("Illegal Level int less than zero."); 118 } 119 this.name = name; 120 this.intLevel = intLevel; 121 this.standardLevel = StandardLevel.getStandardLevel(intLevel); 122 if (LEVELS.putIfAbsent(name, this) != null) { 123 throw new IllegalStateException("Level " + name + " has already been defined."); 124 } 125 } 126 127 /** 128 * Gets the integral value of this Level. 129 * 130 * @return the value of this Level. 131 */ 132 public int intLevel() { 133 return this.intLevel; 134 } 135 136 /** 137 * Gets the standard Level values as an enum. 138 * 139 * @return an enum of the standard Levels. 140 */ 141 public StandardLevel getStandardLevel() { 142 return standardLevel; 143 } 144 145 /** 146 * Compares this level against the levels passed as arguments and returns true if this level is in between the given 147 * levels. 148 * 149 * @param minLevel The minimum level to test. 150 * @param maxLevel The maximum level to test. 151 * @return True true if this level is in between the given levels 152 * @since 2.4 153 */ 154 public boolean isInRange(final Level minLevel, final Level maxLevel) { 155 return this.intLevel >= minLevel.intLevel && this.intLevel <= maxLevel.intLevel; 156 } 157 158 /** 159 * Compares this level against the level passed as an argument and returns true if this level is the same or is less 160 * specific. 161 * <p> 162 * Concretely, {@link #ALL} is less specific than {@link #TRACE}, which is less specific than {@link #DEBUG}, which 163 * is less specific than {@link #INFO}, which is less specific than {@link #WARN}, which is less specific than 164 * {@link #ERROR}, which is less specific than {@link #FATAL}, and finally {@link #OFF}, which is the most specific 165 * standard level. 166 * </p> 167 * 168 * @param level 169 * The level to test. 170 * @return True if this level Level is less specific or the same as the given Level. 171 */ 172 public boolean isLessSpecificThan(final Level level) { 173 return this.intLevel >= level.intLevel; 174 } 175 176 /** 177 * Compares this level against the level passed as an argument and returns true if this level is the same or is more 178 * specific. 179 * <p> 180 * Concretely, {@link #FATAL} is more specific than {@link #ERROR}, which is more specific than {@link #WARN}, 181 * etc., until {@link #TRACE}, and finally {@link #ALL}, which is the least specific standard level. 182 * The most specific level is {@link #OFF}. 183 * </p> 184 * 185 * @param level The level to test. 186 * @return True if this level Level is more specific or the same as the given Level. 187 */ 188 public boolean isMoreSpecificThan(final Level level) { 189 return this.intLevel <= level.intLevel; 190 } 191 192 @Override 193 @SuppressWarnings("CloneDoesntCallSuperClone") 194 // CHECKSTYLE:OFF 195 public Level clone() throws CloneNotSupportedException { 196 throw new CloneNotSupportedException(); 197 } 198 // CHECKSTYLE:ON 199 200 @Override 201 public int compareTo(final Level other) { 202 return intLevel < other.intLevel ? -1 : (intLevel > other.intLevel ? 1 : 0); 203 } 204 205 @Override 206 public boolean equals(final Object other) { 207 return other instanceof Level && other == this; 208 } 209 210 public Class<Level> getDeclaringClass() { 211 return Level.class; 212 } 213 214 @Override 215 public int hashCode() { 216 return this.name.hashCode(); 217 } 218 219 /** 220 * Gets the symbolic name of this Level. Equivalent to calling {@link #toString()}. 221 * 222 * @return the name of this Level. 223 */ 224 public String name() { 225 return this.name; 226 } 227 228 @Override 229 public String toString() { 230 return this.name; 231 } 232 233 /** 234 * Retrieves an existing Level or creates on if it didn't previously exist. 235 * 236 * @param name The name of the level. 237 * @param intValue The integer value for the Level. If the level was previously created this value is ignored. 238 * @return The Level. 239 * @throws java.lang.IllegalArgumentException if the name is null or intValue is less than zero. 240 */ 241 public static Level forName(final String name, final int intValue) { 242 final Level level = LEVELS.get(name); 243 if (level != null) { 244 return level; 245 } 246 try { 247 return new Level(name, intValue); 248 } catch (final IllegalStateException ex) { 249 // The level was added by something else so just return that one. 250 return LEVELS.get(name); 251 } 252 } 253 254 /** 255 * Return the Level associated with the name or null if the Level cannot be found. 256 * 257 * @param name The name of the Level. 258 * @return The Level or null. 259 */ 260 public static Level getLevel(final String name) { 261 return LEVELS.get(name); 262 } 263 264 /** 265 * Converts the string passed as argument to a level. If the conversion fails, then this method returns 266 * {@link #DEBUG}. 267 * 268 * @param sArg The name of the desired Level. 269 * @return The Level associated with the String. 270 */ 271 public static Level toLevel(final String sArg) { 272 return toLevel(sArg, Level.DEBUG); 273 } 274 275 /** 276 * Converts the string passed as argument to a level. If the conversion fails, then this method returns the value of 277 * <code>defaultLevel</code>. 278 * 279 * @param name The name of the desired Level. 280 * @param defaultLevel The Level to use if the String is invalid. 281 * @return The Level associated with the String. 282 */ 283 public static Level toLevel(final String name, final Level defaultLevel) { 284 if (name == null) { 285 return defaultLevel; 286 } 287 final Level level = LEVELS.get(toUpperCase(name.trim())); 288 return level == null ? defaultLevel : level; 289 } 290 291 private static String toUpperCase(final String name) { 292 return name.toUpperCase(Locale.ENGLISH); 293 } 294 295 /** 296 * Return an array of all the Levels that have been registered. 297 * 298 * @return An array of Levels. 299 */ 300 public static Level[] values() { 301 final Collection<Level> values = Level.LEVELS.values(); 302 return values.toArray(new Level[values.size()]); 303 } 304 305 /** 306 * Return the Level associated with the name. 307 * 308 * @param name The name of the Level to return. 309 * @return The Level. 310 * @throws java.lang.NullPointerException if the Level name is {@code null}. 311 * @throws java.lang.IllegalArgumentException if the Level name is not registered. 312 */ 313 public static Level valueOf(final String name) { 314 Objects.requireNonNull(name, "No level name given."); 315 final String levelName = toUpperCase(name.trim()); 316 final Level level = LEVELS.get(levelName); 317 if (level != null) { 318 return level; 319 } 320 throw new IllegalArgumentException("Unknown level constant [" + levelName + "]."); 321 } 322 323 /** 324 * Returns the enum constant of the specified enum type with the specified name. The name must match exactly an 325 * identifier used to declare an enum constant in this type. (Extraneous whitespace characters are not permitted.) 326 * 327 * @param enumType the {@code Class} object of the enum type from which to return a constant 328 * @param name the name of the constant to return 329 * @param <T> The enum type whose constant is to be returned 330 * @return the enum constant of the specified enum type with the specified name 331 * @throws java.lang.IllegalArgumentException if the specified enum type has no constant with the specified name, or 332 * the specified class object does not represent an enum type 333 * @throws java.lang.NullPointerException if {@code enumType} or {@code name} are {@code null} 334 * @see java.lang.Enum#valueOf(Class, String) 335 */ 336 public static <T extends Enum<T>> T valueOf(final Class<T> enumType, final String name) { 337 return Enum.valueOf(enumType, name); 338 } 339 340 // for deserialization 341 protected Object readResolve() { 342 return Level.valueOf(this.name); 343 } 344}