Skip to content

Commit

Permalink
fix: per-subsystem log-levels
Browse files Browse the repository at this point in the history
Ex:

    GOLOG_LOG_LEVEL=error,foo=info,bar=debug

This will set the default log-level to error, foo's log-level o info,
and bar's log-level to debug.

fixes #100
  • Loading branch information
Stebalien committed Apr 17, 2021
1 parent fdd7164 commit 5802523
Show file tree
Hide file tree
Showing 2 changed files with 83 additions and 13 deletions.
51 changes: 38 additions & 13 deletions setup.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,9 @@ const (
envLoggingFmt = "GOLOG_LOG_FMT"

envLoggingFile = "GOLOG_FILE" // /path/to/file
envLoggingURL = "GOLOG_URL" // url that will be processed by sink in the zap
envLoggingURL = "GOLOG_URL" // url that will be processed by sink in the zap

envLoggingOutput = "GOLOG_OUTPUT" // possible values: stdout|stderr|file combine multiple values with '+'
envLoggingOutput = "GOLOG_OUTPUT" // possible values: stdout|stderr|file combine multiple values with '+'
envLoggingLabels = "GOLOG_LOG_LABELS" // comma-separated key-value pairs, i.e. "app=example_app,dc=sjc-1"
)

Expand All @@ -48,9 +48,12 @@ type Config struct {
// Format overrides the format of the log output. Defaults to ColorizedOutput
Format LogFormat

// Level is the minimum enabled logging level.
// Level default is the minimum enabled logging level.
Level LogLevel

// SubsystemLevels are the default levels per-subsystem. When unspecified, defaults to Level.
SubsystemLevels map[string]LogLevel

// Stderr indicates whether logs should be written to stderr.
Stderr bool

Expand Down Expand Up @@ -139,6 +142,14 @@ func SetupLogging(cfg Config) {
primaryCore = newPrimaryCore

setAllLoggers(defaultLevel)

for name, level := range cfg.SubsystemLevels {
if leveler, ok := levels[name]; ok {
leveler.SetLevel(zapcore.Level(level))
} else {
levels[name] = zap.NewAtomicLevelAt(zapcore.Level(level))
}
}
}

// SetDebugLogging calls SetAllLoggers with logging.DEBUG
Expand Down Expand Up @@ -228,10 +239,14 @@ func getLogger(name string) *zap.SugaredLogger {
defer loggerMutex.Unlock()
log, ok := loggers[name]
if !ok {
levels[name] = zap.NewAtomicLevelAt(zapcore.Level(defaultLevel))
level, ok := levels[name]
if !ok {
level = zap.NewAtomicLevelAt(zapcore.Level(defaultLevel))
levels[name] = level
}
log = zap.New(loggerCore).
WithOptions(
zap.IncreaseLevel(levels[name]),
zap.IncreaseLevel(level),
zap.AddCaller(),
).
Named(name).
Expand All @@ -246,10 +261,11 @@ func getLogger(name string) *zap.SugaredLogger {
// configFromEnv returns a Config with defaults populated using environment variables.
func configFromEnv() Config {
cfg := Config{
Format: ColorizedOutput,
Stderr: true,
Level: LevelError,
Labels: map[string]string{},
Format: ColorizedOutput,
Stderr: true,
Level: LevelError,
SubsystemLevels: map[string]LogLevel{},
Labels: map[string]string{},
}

format := os.Getenv(envLoggingFmt)
Expand All @@ -269,10 +285,19 @@ func configFromEnv() Config {
lvl = os.Getenv(envIPFSLogging)
}
if lvl != "" {
var err error
cfg.Level, err = LevelFromString(lvl)
if err != nil {
fmt.Fprintf(os.Stderr, "error setting log levels: %s\n", err)
for _, kvs := range strings.Split(lvl, ",") {
kv := strings.SplitN(kvs, "=", 2)
lvl, err := LevelFromString(kv[len(kv)-1])
if err != nil {
fmt.Fprintf(os.Stderr, "error setting log level %q: %s\n", kvs, err)
continue
}
switch len(kv) {
case 1:
cfg.Level = lvl
case 2:
cfg.SubsystemLevels[kv[0]] = lvl
}
}
}

Expand Down
45 changes: 45 additions & 0 deletions setup_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -158,3 +158,48 @@ func TestLogLabels(t *testing.T) {
t.Errorf("got %q, wanted it to contain log output", buf.String())
}
}

func TestSubsystemLevels(t *testing.T) {
r, w, err := os.Pipe()
if err != nil {
t.Fatalf("failed to open pipe: %v", err)
}

stderr := os.Stderr
os.Stderr = w
defer func() {
os.Stderr = stderr
}()

// set the go-log labels env var
os.Setenv(envLogging, "info,test1=debug")
defer os.Unsetenv(envLoggingLabels)
SetupLogging(configFromEnv())

log1 := getLogger("test1")
log2 := getLogger("test2")

log1.Debug("debug1")
log1.Info("info1")
log2.Debug("debug2")
log2.Info("info2")
w.Close()

buf := &bytes.Buffer{}
if _, err := io.Copy(buf, r); err != nil && err != io.ErrClosedPipe {
t.Fatalf("unexpected error: %v", err)
}

if !strings.Contains(buf.String(), "debug1") {
t.Errorf("got %q, wanted it to contain debug1", buf.String())
}
if strings.Contains(buf.String(), "debug2") {
t.Errorf("got %q, wanted it to not contain debug2", buf.String())
}
if !strings.Contains(buf.String(), "info1") {
t.Errorf("got %q, wanted it to contain info1", buf.String())
}
if !strings.Contains(buf.String(), "info2") {
t.Errorf("got %q, wanted it to contain info2", buf.String())
}
}

0 comments on commit 5802523

Please sign in to comment.