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