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 }