1 // Copyright (c) 2016 Uber Technologies, Inc. 2 // 3 // Permission is hereby granted, free of charge, to any person obtaining a copy 4 // of this software and associated documentation files (the "Software"), to deal 5 // in the Software without restriction, including without limitation the rights 6 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 // copies of the Software, and to permit persons to whom the Software is 8 // furnished to do so, subject to the following conditions: 9 // 10 // The above copyright notice and this permission notice shall be included in 11 // all copies or substantial portions of the Software. 12 // 13 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 // THE SOFTWARE. 20 21 package zapcore 22 23 import ( 24 "bytes" 25 "errors" 26 "fmt" 27 ) 28 29 var errUnmarshalNilLevel = errors.New("can't unmarshal a nil *Level") 30 31 // A Level is a logging priority. Higher levels are more important. 32 type Level int8 33 34 const ( 35 // DebugLevel logs are typically voluminous, and are usually disabled in 36 // production. 37 DebugLevel Level = iota - 1 38 // InfoLevel is the default logging priority. 39 InfoLevel 40 // WarnLevel logs are more important than Info, but don't need individual 41 // human review. 42 WarnLevel 43 // ErrorLevel logs are high-priority. If an application is running smoothly, 44 // it shouldn't generate any error-level logs. 45 ErrorLevel 46 // DPanicLevel logs are particularly important errors. In development the 47 // logger panics after writing the message. 48 DPanicLevel 49 // PanicLevel logs a message, then panics. 50 PanicLevel 51 // FatalLevel logs a message, then calls os.Exit(1). 52 FatalLevel 53 54 _minLevel = DebugLevel 55 _maxLevel = FatalLevel 56 57 // InvalidLevel is an invalid value for Level. 58 // 59 // Core implementations may panic if they see messages of this level. 60 InvalidLevel = _maxLevel + 1 61 ) 62 63 // ParseLevel parses a level based on the lower-case or all-caps ASCII 64 // representation of the log level. If the provided ASCII representation is 65 // invalid an error is returned. 66 // 67 // This is particularly useful when dealing with text input to configure log 68 // levels. 69 func ParseLevel(text string) (Level, error) { 70 var level Level 71 err := level.UnmarshalText([]byte(text)) 72 return level, err 73 } 74 75 type leveledEnabler interface { 76 LevelEnabler 77 78 Level() Level 79 } 80 81 // LevelOf reports the minimum enabled log level for the given LevelEnabler 82 // from Zap's supported log levels, or [InvalidLevel] if none of them are 83 // enabled. 84 // 85 // A LevelEnabler may implement a 'Level() Level' method to override the 86 // behavior of this function. 87 // 88 // func (c *core) Level() Level { 89 // return c.currentLevel 90 // } 91 // 92 // It is recommended that [Core] implementations that wrap other cores use 93 // LevelOf to retrieve the level of the wrapped core. For example, 94 // 95 // func (c *coreWrapper) Level() Level { 96 // return zapcore.LevelOf(c.wrappedCore) 97 // } 98 func LevelOf(enab LevelEnabler) Level { 99 if lvler, ok := enab.(leveledEnabler); ok { 100 return lvler.Level() 101 } 102 103 for lvl := _minLevel; lvl <= _maxLevel; lvl++ { 104 if enab.Enabled(lvl) { 105 return lvl 106 } 107 } 108 109 return InvalidLevel 110 } 111 112 // String returns a lower-case ASCII representation of the log level. 113 func (l Level) String() string { 114 switch l { 115 case DebugLevel: 116 return "debug" 117 case InfoLevel: 118 return "info" 119 case WarnLevel: 120 return "warn" 121 case ErrorLevel: 122 return "error" 123 case DPanicLevel: 124 return "dpanic" 125 case PanicLevel: 126 return "panic" 127 case FatalLevel: 128 return "fatal" 129 default: 130 return fmt.Sprintf("Level(%d)", l) 131 } 132 } 133 134 // CapitalString returns an all-caps ASCII representation of the log level. 135 func (l Level) CapitalString() string { 136 // Printing levels in all-caps is common enough that we should export this 137 // functionality. 138 switch l { 139 case DebugLevel: 140 return "DEBUG" 141 case InfoLevel: 142 return "INFO" 143 case WarnLevel: 144 return "WARN" 145 case ErrorLevel: 146 return "ERROR" 147 case DPanicLevel: 148 return "DPANIC" 149 case PanicLevel: 150 return "PANIC" 151 case FatalLevel: 152 return "FATAL" 153 default: 154 return fmt.Sprintf("LEVEL(%d)", l) 155 } 156 } 157 158 // MarshalText marshals the Level to text. Note that the text representation 159 // drops the -Level suffix (see example). 160 func (l Level) MarshalText() ([]byte, error) { 161 return []byte(l.String()), nil 162 } 163 164 // UnmarshalText unmarshals text to a level. Like MarshalText, UnmarshalText 165 // expects the text representation of a Level to drop the -Level suffix (see 166 // example). 167 // 168 // In particular, this makes it easy to configure logging levels using YAML, 169 // TOML, or JSON files. 170 func (l *Level) UnmarshalText(text []byte) error { 171 if l == nil { 172 return errUnmarshalNilLevel 173 } 174 if !l.unmarshalText(text) && !l.unmarshalText(bytes.ToLower(text)) { 175 return fmt.Errorf("unrecognized level: %q", text) 176 } 177 return nil 178 } 179 180 func (l *Level) unmarshalText(text []byte) bool { 181 switch string(text) { 182 case "debug", "DEBUG": 183 *l = DebugLevel 184 case "info", "INFO", "": // make the zero value useful 185 *l = InfoLevel 186 case "warn", "WARN": 187 *l = WarnLevel 188 case "error", "ERROR": 189 *l = ErrorLevel 190 case "dpanic", "DPANIC": 191 *l = DPanicLevel 192 case "panic", "PANIC": 193 *l = PanicLevel 194 case "fatal", "FATAL": 195 *l = FatalLevel 196 default: 197 return false 198 } 199 return true 200 } 201 202 // Set sets the level for the flag.Value interface. 203 func (l *Level) Set(s string) error { 204 return l.UnmarshalText([]byte(s)) 205 } 206 207 // Get gets the level for the flag.Getter interface. 208 func (l *Level) Get() interface{} { 209 return *l 210 } 211 212 // Enabled returns true if the given level is at or above this level. 213 func (l Level) Enabled(lvl Level) bool { 214 return lvl >= l 215 } 216 217 // LevelEnabler decides whether a given logging level is enabled when logging a 218 // message. 219 // 220 // Enablers are intended to be used to implement deterministic filters; 221 // concerns like sampling are better implemented as a Core. 222 // 223 // Each concrete Level value implements a static LevelEnabler which returns 224 // true for itself and all higher logging levels. For example WarnLevel.Enabled() 225 // will return true for WarnLevel, ErrorLevel, DPanicLevel, PanicLevel, and 226 // FatalLevel, but return false for InfoLevel and DebugLevel. 227 type LevelEnabler interface { 228 Enabled(Level) bool 229 } 230