blob: e575c9f432c2f016f7d58c09a7e57683e6578313 [file] [log] [blame]
Don Newton7577f072020-01-06 12:41:11 -05001// 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
21package zapcore
22
23import (
24 "bytes"
25 "errors"
26 "fmt"
27)
28
29var errUnmarshalNilLevel = errors.New("can't unmarshal a nil *Level")
30
31// A Level is a logging priority. Higher levels are more important.
32type Level int8
33
34const (
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
58// String returns a lower-case ASCII representation of the log level.
59func (l Level) String() string {
60 switch l {
61 case DebugLevel:
62 return "debug"
63 case InfoLevel:
64 return "info"
65 case WarnLevel:
66 return "warn"
67 case ErrorLevel:
68 return "error"
69 case DPanicLevel:
70 return "dpanic"
71 case PanicLevel:
72 return "panic"
73 case FatalLevel:
74 return "fatal"
75 default:
76 return fmt.Sprintf("Level(%d)", l)
77 }
78}
79
80// CapitalString returns an all-caps ASCII representation of the log level.
81func (l Level) CapitalString() string {
82 // Printing levels in all-caps is common enough that we should export this
83 // functionality.
84 switch l {
85 case DebugLevel:
86 return "DEBUG"
87 case InfoLevel:
88 return "INFO"
89 case WarnLevel:
90 return "WARN"
91 case ErrorLevel:
92 return "ERROR"
93 case DPanicLevel:
94 return "DPANIC"
95 case PanicLevel:
96 return "PANIC"
97 case FatalLevel:
98 return "FATAL"
99 default:
100 return fmt.Sprintf("LEVEL(%d)", l)
101 }
102}
103
104// MarshalText marshals the Level to text. Note that the text representation
105// drops the -Level suffix (see example).
106func (l Level) MarshalText() ([]byte, error) {
107 return []byte(l.String()), nil
108}
109
110// UnmarshalText unmarshals text to a level. Like MarshalText, UnmarshalText
111// expects the text representation of a Level to drop the -Level suffix (see
112// example).
113//
114// In particular, this makes it easy to configure logging levels using YAML,
115// TOML, or JSON files.
116func (l *Level) UnmarshalText(text []byte) error {
117 if l == nil {
118 return errUnmarshalNilLevel
119 }
120 if !l.unmarshalText(text) && !l.unmarshalText(bytes.ToLower(text)) {
121 return fmt.Errorf("unrecognized level: %q", text)
122 }
123 return nil
124}
125
126func (l *Level) unmarshalText(text []byte) bool {
127 switch string(text) {
128 case "debug", "DEBUG":
129 *l = DebugLevel
130 case "info", "INFO", "": // make the zero value useful
131 *l = InfoLevel
132 case "warn", "WARN":
133 *l = WarnLevel
134 case "error", "ERROR":
135 *l = ErrorLevel
136 case "dpanic", "DPANIC":
137 *l = DPanicLevel
138 case "panic", "PANIC":
139 *l = PanicLevel
140 case "fatal", "FATAL":
141 *l = FatalLevel
142 default:
143 return false
144 }
145 return true
146}
147
148// Set sets the level for the flag.Value interface.
149func (l *Level) Set(s string) error {
150 return l.UnmarshalText([]byte(s))
151}
152
153// Get gets the level for the flag.Getter interface.
154func (l *Level) Get() interface{} {
155 return *l
156}
157
158// Enabled returns true if the given level is at or above this level.
159func (l Level) Enabled(lvl Level) bool {
160 return lvl >= l
161}
162
163// LevelEnabler decides whether a given logging level is enabled when logging a
164// message.
165//
166// Enablers are intended to be used to implement deterministic filters;
167// concerns like sampling are better implemented as a Core.
168//
169// Each concrete Level value implements a static LevelEnabler which returns
170// true for itself and all higher logging levels. For example WarnLevel.Enabled()
171// will return true for WarnLevel, ErrorLevel, DPanicLevel, PanicLevel, and
172// FatalLevel, but return false for InfoLevel and DebugLevel.
173type LevelEnabler interface {
174 Enabled(Level) bool
175}