Skip to content

Commit

Permalink
logger: add default logger and subsystem log handler
Browse files Browse the repository at this point in the history
Adds ability to control logging via env vars.
  • Loading branch information
malt3 committed Jan 9, 2024
1 parent ec100d2 commit c97d6cc
Show file tree
Hide file tree
Showing 2 changed files with 143 additions and 0 deletions.
56 changes: 56 additions & 0 deletions internal/logger/logger.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
// Package logger provides a slog.Logger that can be configured via environment variables.
// NUNKI_LOG_LEVEL can be used to set the log level.
// NUNKI_LOG_FORMAT can be used to set the log format.
package logger

import (
"fmt"
"io"
"log/slog"
"os"
"strconv"
"strings"
)

// Default returns a logger configured via environment variables.
func Default() (*slog.Logger, error) {
logLevel, err := getLogLevel()
if err != nil {
return nil, err
}
return slog.New(logHandler()(os.Stderr, &slog.HandlerOptions{
Level: logLevel,
})), nil
}

func getLogLevel() (slog.Level, error) {
logLevel := os.Getenv("NUNKI_LOG_LEVEL")
switch strings.ToLower(logLevel) {
case "debug":
return slog.LevelDebug, nil
case "", "info":
return slog.LevelInfo, nil
case "warn":
return slog.LevelWarn, nil
case "error":
return slog.LevelError, nil
}

numericLevel, err := strconv.Atoi(logLevel)
if err != nil {
return slog.Level(0), fmt.Errorf("invalid log level: %q", logLevel)
}
return slog.Level(numericLevel), nil
}

func logHandler() func(w io.Writer, opts *slog.HandlerOptions) slog.Handler {
switch strings.ToLower(os.Getenv("NUNKI_LOG_FORMAT")) {
case "json":
return func(w io.Writer, opts *slog.HandlerOptions) slog.Handler {
return slog.NewJSONHandler(w, opts)
}
}
return func(w io.Writer, opts *slog.HandlerOptions) slog.Handler {
return slog.NewTextHandler(w, opts)
}
}
87 changes: 87 additions & 0 deletions internal/logger/subsystemlog/handler.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
/*
Copyright (c) Edgeless Systems GmbH
SPDX-License-Identifier: AGPL-3.0-only
*/

// Package subsystemlog provides a slog.Handler that can be used to enable
// logging on a per-subsystem basis.
//
// NUNKI_LOG_SUBSYSTEMS can be used to enable logging for specific subsystems.
// If NUNKI_LOG_SUBSYSTEMS has the special value "*", all subsystems are enabled.
// Otherwise, a comma-separated list of subsystem names can be specified.
package subsystemlog

import (
"context"
"log/slog"
"os"
"strings"
)

// Handler is a slog.Handler that can be used to enable logging on a per-subsystem basis.
type Handler struct {
inner slog.Handler
subsystem string
enabled bool
}

// NewHandler returns a new Handler.
func NewHandler(inner slog.Handler, subsystem string) (*Handler, error) {
if subsystem != "" {
inner = inner.WithGroup(subsystem)
}

return &Handler{
inner: inner,
subsystem: subsystem,
enabled: subsystemEnvEnabled(subsystem),
}, nil
}

// Enabled returns true if the given level is enabled.
func (h *Handler) Enabled(ctx context.Context, level slog.Level) bool {
return h.enabled && h.inner.Enabled(ctx, level)
}

// Handle handles the given record.
func (h *Handler) Handle(ctx context.Context, record slog.Record) error {
return h.inner.Handle(ctx, record)
}

// WithAttrs returns a new Handler with the given attributes.
func (h *Handler) WithAttrs(attrs []slog.Attr) slog.Handler {
return &Handler{
inner: h.inner.WithAttrs(attrs),
subsystem: h.subsystem,
enabled: h.enabled,
}
}

// WithGroup returns a new Handler with the given group.
func (h *Handler) WithGroup(name string) slog.Handler {
return &Handler{
inner: h.inner.WithGroup(name),
subsystem: h.subsystem,
enabled: h.enabled,
}
}

func subsystemEnvEnabled(subsystem string) bool {
allowList := os.Getenv("NUNKI_LOG_SUBSYSTEMS")

return subsystemAllowListMatch(subsystem, allowList)
}

func subsystemAllowListMatch(subsystem string, allowList string) bool {
if allowList == "*" {
return true
}
for _, allow := range strings.Split(allowList, ",") {
allow = strings.ToLower(strings.TrimSpace(allow))
if allow == subsystem {
return true
}
}
return false
}

0 comments on commit c97d6cc

Please sign in to comment.