1
- /// Describes the level of verbosity of a metric event .
2
- #[ derive( Debug , Clone , PartialEq , Eq ) ]
1
+ /// Verbosity of a metric.
2
+ #[ derive( Clone , Copy , Debug , Eq , PartialEq , PartialOrd ) ]
3
3
pub struct Level ( LevelInner ) ;
4
4
5
5
impl Level {
@@ -19,7 +19,22 @@ impl Level {
19
19
pub const ERROR : Self = Self ( LevelInner :: Error ) ;
20
20
}
21
21
22
- #[ derive( Debug , Clone , PartialEq , Eq ) ]
22
+ impl std:: convert:: TryFrom < & str > for Level {
23
+ type Error = String ;
24
+
25
+ fn try_from ( value : & str ) -> Result < Self , Self :: Error > {
26
+ match value. trim ( ) {
27
+ "trace" | "TRACE" => Ok ( Level :: TRACE ) ,
28
+ "debug" | "DEBUG" => Ok ( Level :: DEBUG ) ,
29
+ "info" | "INFO" => Ok ( Level :: INFO ) ,
30
+ "warn" | "WARN" => Ok ( Level :: WARN ) ,
31
+ "error" | "ERROR" => Ok ( Level :: ERROR ) ,
32
+ unknown => Err ( format ! ( "unknown log level: {} (expected one of 'trace', 'debug', 'info', 'warn', or 'error')" , unknown) ) ,
33
+ }
34
+ }
35
+ }
36
+
37
+ #[ derive( Clone , Copy , Debug , Eq , Ord , PartialEq , PartialOrd ) ]
23
38
enum LevelInner {
24
39
Trace = 0 ,
25
40
Debug = 1 ,
@@ -44,7 +59,7 @@ enum LevelInner {
44
59
///
45
60
/// Metadata usage is exporter-specific, and may be ignored entirely. See the documentation of the specific exporter
46
61
/// being used for more information.
47
- #[ derive( Debug , Clone , PartialEq , Eq ) ]
62
+ #[ derive( Clone , Debug , Eq , PartialEq ) ]
48
63
pub struct Metadata < ' a > {
49
64
target : & ' a str ,
50
65
level : Level ,
@@ -77,3 +92,68 @@ impl<'a> Metadata<'a> {
77
92
self . module_path
78
93
}
79
94
}
95
+
96
+ #[ cfg( test) ]
97
+ mod tests {
98
+ use std:: convert:: TryFrom as _;
99
+
100
+ use super :: * ;
101
+
102
+ #[ test]
103
+ fn level_try_from_valid ( ) {
104
+ let cases = & [
105
+ ( "trace" , Level :: TRACE ) , ( "TRACE" , Level :: TRACE ) ,
106
+ ( "debug" , Level :: DEBUG ) , ( "DEBUG" , Level :: DEBUG ) ,
107
+ ( "info" , Level :: INFO ) , ( "INFO" , Level :: INFO ) ,
108
+ ( "warn" , Level :: WARN ) , ( "WARN" , Level :: WARN ) ,
109
+ ( "error" , Level :: ERROR ) , ( "ERROR" , Level :: ERROR ) ,
110
+ ] ;
111
+
112
+ for ( input, expected) in cases {
113
+ assert_eq ! ( Level :: try_from( * input) . unwrap( ) , * expected) ;
114
+
115
+ // Now try with some whitespace on either end.
116
+ let input_whitespace = format ! ( " {} " , input) ;
117
+ assert_eq ! ( Level :: try_from( & * input_whitespace) . unwrap( ) , * expected) ;
118
+ }
119
+ }
120
+
121
+ #[ test]
122
+ fn level_try_from_invalid ( ) {
123
+ let cases = & [ "" , "foo" , "bar" , "baz" , "qux" , "quux" ] ;
124
+
125
+ for input in cases {
126
+ assert ! ( Level :: try_from( * input) . is_err( ) ) ;
127
+ }
128
+ }
129
+
130
+ #[ test]
131
+ fn level_ordering ( ) {
132
+ // A few manual comparisons because it makes me feel better:
133
+ assert ! ( Level :: TRACE < Level :: DEBUG ) ;
134
+ assert ! ( Level :: DEBUG < Level :: INFO ) ;
135
+ assert ! ( Level :: ERROR > Level :: DEBUG ) ;
136
+ assert ! ( Level :: WARN == Level :: WARN ) ;
137
+
138
+ // Now check each level programmatically.
139
+ let levels = & [
140
+ Level :: TRACE , Level :: DEBUG , Level :: INFO , Level :: WARN , Level :: ERROR ,
141
+ ] ;
142
+
143
+ for i in 0 ..levels. len ( ) {
144
+ let current_level = levels[ i] ;
145
+ let lower_levels = & levels[ ..i] ;
146
+ let higher_levels = & levels[ i + 1 ..] ;
147
+
148
+ for lower_level in lower_levels {
149
+ assert ! ( current_level > * lower_level) ;
150
+ assert ! ( * lower_level < current_level) ;
151
+ }
152
+
153
+ for higher_level in higher_levels {
154
+ assert ! ( current_level < * higher_level) ;
155
+ assert ! ( * higher_level > current_level) ;
156
+ }
157
+ }
158
+ }
159
+ }
0 commit comments