level.go

// Level parsing and filter primitives. The Level values themselves live in
// lambdalog.go; this file provides the conversion layer that reads levels
// from config files, environment variables, and HTTP query parameters.
package lambdalog

import (
	"fmt"
	"strings"
)

// ParseLevel accepts any of the canonical level names (case-insensitive),
// single-letter shorthand (d/i/w/e), and numeric severities matching
// syslog-style values (7, 6, 4, 3). Unknown inputs yield an error; callers
// typically treat that as "keep the current level".
func ParseLevel(s string) (Level, error) {
	switch strings.ToLower(strings.TrimSpace(s)) {
	case "debug", "d", "7":
		return LevelDebug, nil
	case "info", "i", "6":
		return LevelInfo, nil
	case "warn", "warning", "w", "4":
		return LevelWarn, nil
	case "error", "err", "e", "3":
		return LevelError, nil
	case "":
		return LevelInfo, fmt.Errorf("empty level string")
	default:
		return LevelInfo, fmt.Errorf("unknown level %q", s)
	}
}

// MustParseLevel is the panicking sibling of ParseLevel, intended for use at
// package init time where an invalid configuration is unrecoverable.
func MustParseLevel(s string) Level {
	lv, err := ParseLevel(s)
	if err != nil {
		panic(err)
	}
	return lv
}

// String returns the canonical lower-case name for a Level. Unknown levels
// render as "info" to match the default rank behaviour.
func (l Level) String() string {
	switch l {
	case LevelDebug:
		return "debug"
	case LevelInfo:
		return "info"
	case LevelWarn:
		return "warn"
	case LevelError:
		return "error"
	default:
		return "info"
	}
}

// Enabled reports whether records at lv would be emitted by a logger with
// threshold min. Exposed for external callers that want to avoid building
// expensive attribute slices when the level is filtered out.
func Enabled(lv, min Level) bool {
	return levelEnabled(lv, min)
}

// Levels returns the four recognised levels in ascending severity order.
// Useful for callers wiring up CLI flag completers or config validators.
func Levels() []Level {
	return []Level{LevelDebug, LevelInfo, LevelWarn, LevelError}
}

// LevelFilter is a composable predicate: it returns true when a record at
// lv should be emitted. Filters stack via All/Any combinators and plug into
// Logger through WithFilter.
type LevelFilter func(Level) bool

// AllLevels accepts every level.
func AllLevels() LevelFilter { return func(Level) bool { return true } }

// AtLeast returns a filter that admits records whose level is at or above
// the given threshold.
func AtLeast(min Level) LevelFilter {
	return func(lv Level) bool { return levelEnabled(lv, min) }
}

// Only returns a filter that admits records at exactly one level.
func Only(lv Level) LevelFilter {
	return func(other Level) bool { return other == lv }
}