Skip to content

Commit cbb68a7

Browse files
authored
Revise the loglevel API to be more golang idiomatic (#165)
- LogLevel has a String method to convert the numeric level into its string version - There is only one name used to identify the default log level, and it is declared as a const `DefaultName` - Removed the "Get" name for functions that lookup a value. - A `DefaultLevel` function returns the current log level and handles locking. - Function to convert string to LogLevel is named `Parse`
1 parent f80c870 commit cbb68a7

File tree

3 files changed

+72
-80
lines changed

3 files changed

+72
-80
lines changed

levels.go

Lines changed: 33 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,14 @@ import "go.uber.org/zap/zapcore"
66
// enum.
77
type LogLevel zapcore.Level
88

9+
// DefaultName is the subsystem name that identifies the default log level.
10+
const DefaultName = ""
11+
12+
// String returns the name of a LogLevel.
13+
func (lvl LogLevel) String() string {
14+
return zapcore.Level(lvl).String()
15+
}
16+
917
var (
1018
LevelDebug = LogLevel(zapcore.DebugLevel)
1119
LevelInfo = LogLevel(zapcore.InfoLevel)
@@ -16,51 +24,43 @@ var (
1624
LevelFatal = LogLevel(zapcore.FatalLevel)
1725
)
1826

19-
// LevelFromString parses a string-based level and returns the corresponding
20-
// LogLevel.
21-
//
22-
// Supported strings are: DEBUG, INFO, WARN, ERROR, DPANIC, PANIC, FATAL, and
23-
// their lower-case forms.
24-
//
25-
// The returned LogLevel must be discarded if error is not nil.
26-
func LevelFromString(level string) (LogLevel, error) {
27-
lvl := zapcore.InfoLevel // zero value
28-
err := lvl.Set(level)
27+
// Parse parses a string-based level and returns the corresponding LogLevel. An
28+
// error is returned of the string is not the name of a supported LogLevel.
29+
func Parse(name string) (LogLevel, error) {
30+
var lvl zapcore.Level
31+
err := lvl.Set(name)
2932
return LogLevel(lvl), err
3033
}
3134

32-
// LevelName returns the name of a LogLevel.
33-
func LevelName(level LogLevel) string {
34-
return zapcore.Level(level).String()
35+
// DefaultLevel returns the current default LogLevel.
36+
func DefaultLevel() LogLevel {
37+
loggerMutex.RLock()
38+
lvl := defaultLevel
39+
loggerMutex.RUnlock()
40+
return lvl
3541
}
3642

37-
// GetLogLevel returns the current log level for a given subsystem as a string.
38-
// Passing name="*" or name="" returns the defaultLevel.
39-
func GetLogLevel(name string) (string, error) {
40-
if name == "*" || name == "" {
41-
loggerMutex.RLock()
42-
defLvl := defaultLevel
43-
loggerMutex.RUnlock()
44-
return LevelName(defLvl), nil
43+
// SubsystemLevelName returns the current log level name for a given subsystem.
44+
// An empty name, "", returns the default LogLevel name.
45+
func SubsystemLevelName(subsys string) (string, error) {
46+
if subsys == DefaultName {
47+
return DefaultLevel().String(), nil
4548
}
46-
if lvl, ok := levels[name]; ok {
47-
return lvl.Level().String(), nil
49+
lvl, ok := levels[subsys]
50+
if !ok {
51+
return "", ErrNoSuchLogger
4852
}
49-
return "", ErrNoSuchLogger
53+
return lvl.Level().String(), nil
5054
}
5155

52-
// GetAllLogLevels returns a map of all current log levels for all subsystems as strings.
53-
// The map includes a special "*" key that represents the defaultLevel.
54-
func GetAllLogLevels() map[string]string {
56+
// SubsystemLevelNames returns a map of all facility names to their current log
57+
// levels as strings. The map includes the default log level identified by the
58+
// defaultName string as the map key.
59+
func SubsystemLevelNames() map[string]string {
5560
result := make(map[string]string, len(levels)+1)
5661

57-
// Add the default level with "*" key
58-
loggerMutex.RLock()
59-
defLvl := defaultLevel
60-
loggerMutex.RUnlock()
61-
result["*"] = LevelName(defLvl)
62+
result[DefaultName] = DefaultLevel().String()
6263

63-
// Add all subsystem levels
6464
for name, level := range levels {
6565
result[name] = level.Level().String()
6666
}

log_level_test.go

Lines changed: 36 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ func clearLoggerState() {
6969
clear(levels)
7070
}
7171

72-
func TestGetDefaultLevel(t *testing.T) {
72+
func TestDefaultLevel(t *testing.T) {
7373
originalConfig := GetConfig()
7474
defer SetupLogging(originalConfig)
7575

@@ -81,47 +81,39 @@ func TestGetDefaultLevel(t *testing.T) {
8181
for _, expected := range testCases {
8282
SetupLogging(Config{Level: expected, Stderr: true})
8383

84-
// empty string arg
85-
lvl, err := GetLogLevel("")
86-
if err != nil {
87-
t.Errorf("GetLogLevel() returned error: %v", err)
88-
} else if lvl != LevelName(expected) {
89-
t.Errorf("GetLogLevel() = %v, want %v", lvl, LevelName(expected))
90-
}
91-
92-
// explicit "*"
93-
lvl, err = GetLogLevel("*")
94-
if err != nil {
95-
t.Errorf(`GetLogLevel("*") returned error: %v`, err)
96-
} else if lvl != LevelName(expected) {
97-
t.Errorf(`GetLogLevel("*") = %v, want %v`, lvl, LevelName(expected))
84+
// check default
85+
if DefaultLevel() != expected {
86+
t.Fatalf("wrong default level, want %v, got %v", DefaultLevel(), expected)
9887
}
9988

100-
// empty string
101-
lvl, err = GetLogLevel("")
89+
// empty string subsystem
90+
lvl, err := SubsystemLevelName("")
10291
if err != nil {
103-
t.Errorf(`GetLogLevel("") returned error: %v`, err)
104-
} else if lvl != LevelName(expected) {
105-
t.Errorf(`GetLogLevel("") = %v, want %v`, lvl, LevelName(expected))
92+
t.Errorf("SubsystemLevelName returned error: %v", err)
93+
} else if lvl != expected.String() {
94+
t.Errorf("SubsystemLevelName returned %v, want %v", lvl, expected)
10695
}
10796
}
10897
}
10998

110-
func TestGetAllLogLevels(t *testing.T) {
99+
func TestGetSubsystemLevelNames(t *testing.T) {
111100
originalConfig := GetConfig()
112101
defer SetupLogging(originalConfig)
113102

114103
// Clear any state from previous tests first
115104
clearLoggerState()
116105

117106
SetupLogging(Config{Level: LevelWarn, Stderr: true})
118-
base := GetAllLogLevels()
107+
base := SubsystemLevelNames()
119108

120109
if len(base) != 1 {
121-
t.Errorf("baseline GetAllLogLevels() length = %d; want 1", len(base))
110+
t.Errorf("baseline SubsystemLevelNames() length = %d; want 1", len(base))
111+
}
112+
if DefaultLevel() != LevelWarn {
113+
t.Fatal("wrong default level")
122114
}
123-
if base["*"] != LevelName(LevelWarn) {
124-
t.Errorf("baseline GetAllLogLevels()[\"*\"] = %v; want %v", base["*"], LevelName(LevelWarn))
115+
if base[DefaultName] != LevelWarn.String() {
116+
t.Errorf("baseline SubsystemLevelNames()[\"\"] = %v; want %v", base["*"], LevelWarn.String())
125117
}
126118

127119
expected := map[string]LogLevel{
@@ -135,19 +127,19 @@ func TestGetAllLogLevels(t *testing.T) {
135127
Stderr: true,
136128
})
137129

138-
all := GetAllLogLevels()
130+
all := SubsystemLevelNames()
139131

140-
if all["*"] != LevelName(LevelError) {
141-
t.Errorf(`GetAllLogLevels()["*"] = %v; want %v`, all["*"], LevelName(LevelError))
132+
if all[""] != DefaultLevel().String() {
133+
t.Errorf(`SubsystemLevelNames()[""] = %v; want %v`, all[""], DefaultLevel().String())
142134
}
143135
for name, want := range expected {
144136
got, ok := all[name]
145137
if !ok {
146-
t.Errorf("missing key %q in GetAllLogLevels()", name)
138+
t.Errorf("missing key %q in SubsystemLevelNames()", name)
147139
continue
148140
}
149-
if got != LevelName(want) {
150-
t.Errorf(`GetAllLogLevels()["%s"] = %v; want %v`, name, got, LevelName(want))
141+
if got != want.String() {
142+
t.Errorf(`SubsystemLevelNames()["%s"] = %v; want %v`, name, got, want.String())
151143
}
152144
}
153145

@@ -157,36 +149,36 @@ func TestGetAllLogLevels(t *testing.T) {
157149
t.Fatalf("SetLogLevel(dynamic) failed: %v", err)
158150
}
159151

160-
all = GetAllLogLevels()
152+
all = SubsystemLevelNames()
161153
if lvl, ok := all["dynamic"]; !ok {
162154
t.Error(`missing "dynamic" key after creation`)
163-
} else if lvl != LevelName(LevelFatal) {
164-
t.Errorf(`GetAllLogLevels()["dynamic"] = %v; want %v`, lvl, LevelName(LevelFatal))
155+
} else if lvl != LevelFatal.String() {
156+
t.Errorf(`SubsystemLevelNames()["dynamic"] = %v; want %v`, lvl, LevelFatal.String())
165157
}
166158

167159
// ensure immutability
168-
snapshot := GetAllLogLevels()
169-
snapshot["*"] = LevelName(LevelDebug)
170-
snapshot["newkey"] = LevelName(LevelInfo)
160+
snapshot := SubsystemLevelNames()
161+
snapshot[DefaultName] = DefaultLevel().String()
162+
snapshot["newkey"] = LevelInfo.String()
171163

172164
// ensure original state unchanged
173-
fresh := GetAllLogLevels()
174-
if fresh["*"] != LevelName(LevelError) {
175-
t.Errorf(`immutable check failed: fresh["*"] = %v; want %v`, fresh["*"], LevelName(LevelError))
165+
fresh := SubsystemLevelNames()
166+
if fresh[DefaultName] != LevelError.String() {
167+
t.Errorf(`immutable check failed: fresh[DefaultName] = %v; want %v`, fresh[DefaultName], LevelError.String())
176168
}
177169
if _, exists := fresh["newkey"]; exists {
178170
t.Error(`immutable check failed: "newkey" should not leak into real map`)
179171
}
180172
}
181173

182-
func TestLevelName(t *testing.T) {
174+
func TestLogLevelString(t *testing.T) {
183175
testLevels := []LogLevel{LevelDebug, LevelInfo, LevelWarn, LevelError}
184176
expectNames := []string{"debug", "info", "warn", "error"}
185177

186178
for i := range testLevels {
187-
name := LevelName(testLevels[i])
188-
if name != expectNames[i] {
189-
t.Errorf("unexpected name for level: expected %s, got %s", expectNames[i], name)
179+
if testLevels[i].String() != expectNames[i] {
180+
t.Errorf("unexpected name for level: expected %s, got %s", expectNames[i], testLevels[i].String())
190181
}
191182
}
183+
192184
}

setup.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -198,7 +198,7 @@ func setAllLoggers(lvl LogLevel) {
198198
// SetLogLevel changes the log level of a specific subsystem
199199
// name=="*" changes all subsystems
200200
func SetLogLevel(name, level string) error {
201-
lvl, err := LevelFromString(level)
201+
lvl, err := Parse(level)
202202
if err != nil {
203203
return err
204204
}
@@ -226,7 +226,7 @@ func SetLogLevel(name, level string) error {
226226
// SetLogLevelRegex sets all loggers to level `l` that match expression `e`.
227227
// An error is returned if `e` fails to compile.
228228
func SetLogLevelRegex(e, l string) error {
229-
lvl, err := LevelFromString(l)
229+
lvl, err := Parse(l)
230230
if err != nil {
231231
return err
232232
}
@@ -321,7 +321,7 @@ func configFromEnv() Config {
321321
if lvl != "" {
322322
for _, kvs := range strings.Split(lvl, ",") {
323323
kv := strings.SplitN(kvs, "=", 2)
324-
lvl, err := LevelFromString(kv[len(kv)-1])
324+
lvl, err := Parse(kv[len(kv)-1])
325325
if err != nil {
326326
fmt.Fprintf(os.Stderr, "error setting log level %q: %s\n", kvs, err)
327327
continue

0 commit comments

Comments
 (0)