1 /** 2 * Defines the concept of a *Log Level*, that is, a quantifiable *severity* of 3 * a log message, which can be used to determine if such a message is shown, or 4 * where that message gets routed. 5 */ 6 module slf4d.level; 7 import slf4d; 8 9 /** 10 * The set of pre-defined logging levels that are universally recognized. 11 */ 12 const enum Levels { 13 /** 14 * The lowest severity log level defined by SLF4D, usually for fine-grained 15 * debugging of individual statements and control flow. 16 */ 17 TRACE = Level(10, "TRACE"), 18 /** 19 * A low severity log level used for extra information that's only useful 20 * when debugging a program's behavior. 21 */ 22 DEBUG = Level(20, "DEBUG"), 23 24 /** 25 * A medium severity log level used for reporting information during 26 * standard, nominal program operation. 27 */ 28 INFO = Level(30, "INFO"), 29 30 /** 31 * A namehigher severity log level for reporting anomalous but non-fatal issues 32 * that arise at runtime. 33 */ 34 WARN = Level(40, "WARN"), 35 36 /** 37 * A severe log level for program errors that indicate a fatal bug that 38 * leads to program failure or inconsistent state. 39 */ 40 ERROR = Level(50, "ERROR") 41 } 42 43 unittest { 44 assert(Levels.TRACE.value < Levels.DEBUG.value); 45 assert(Levels.DEBUG.value < Levels.INFO.value); 46 assert(Levels.INFO.value < Levels.WARN.value); 47 assert(Levels.WARN.value < Levels.ERROR.value); 48 } 49 50 /** 51 * Attempts to parse one of the standard logging levels defined by `Levels` 52 * from a string. The provided string is checked against the names of each of 53 * the defined logging levels, and the level whose name matches is returned, 54 * ignoring capitalization or whitespace. 55 * Params: 56 * s = The string to parse. 57 * Returns: The level that was parsed, or if none was found, a `LoggingException` 58 * is thrown. 59 */ 60 Level parseLoggingLevel(string s) { 61 import std.string : strip, toUpper; 62 import std.traits : EnumMembers; 63 if (s is null || s.strip.toUpper.length == 0) { 64 throw new LoggingException("Cannot parse logging level from a null or empty string."); 65 } 66 s = s.strip.toUpper; 67 static foreach(lvl; EnumMembers!Levels) { 68 if (s == lvl.name) { 69 return lvl; 70 } 71 } 72 throw new LoggingException("String \"" ~ s ~ "\" didn't match any logging level."); 73 } 74 75 unittest { 76 assert(parseLoggingLevel("TRACE") == Levels.TRACE); 77 assert(parseLoggingLevel("DEBUG") == Levels.DEBUG); 78 assert(parseLoggingLevel("INFO") == Levels.INFO); 79 assert(parseLoggingLevel("WARN") == Levels.WARN); 80 assert(parseLoggingLevel("ERROR") == Levels.ERROR); 81 // Check that case-sensitivity and whitespace don't matter. 82 assert(parseLoggingLevel(" inFo\n") == Levels.INFO); 83 try {// Check that invalid strings throw an exception. 84 auto l = parseLoggingLevel("not a logging level"); 85 assert(false, "Expected parseLoggingLevel to throw, but returned " ~ l.name); 86 } catch (LoggingException e) { 87 // This is fine. 88 } 89 try {// Null strings should also throw. 90 auto l = parseLoggingLevel(null); 91 assert(false, "Expected parseLoggingLevel to throw, but returned " ~ l.name); 92 } catch (LoggingException e) { 93 // This is fine. 94 } 95 try { 96 auto l = parseLoggingLevel(""); 97 assert(false, "Expected parseLoggingLevel to throw, but returned " ~ l.name); 98 } catch (LoggingException e) { 99 // This is fine. 100 } 101 } 102 103 /** 104 * The struct definition of a logging level. 105 */ 106 struct Level { 107 /** 108 * The integer value of this level. A higher value indicates a greater 109 * severity of the log message. 110 */ 111 public int value; 112 113 /** 114 * The textual name of this level, which may be shown in formatted log 115 * messages. 116 */ 117 public string name; 118 }