restored from backups
This commit is contained in:
@@ -0,0 +1,133 @@
|
||||
package secret
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"io"
|
||||
"log/slog"
|
||||
"os"
|
||||
"strings"
|
||||
"syscall"
|
||||
|
||||
"golang.org/x/term"
|
||||
)
|
||||
|
||||
var (
|
||||
debugEnabled bool
|
||||
debugLogger *slog.Logger
|
||||
)
|
||||
|
||||
func init() {
|
||||
initDebugLogging()
|
||||
}
|
||||
|
||||
// initDebugLogging initializes the debug logging system based on GODEBUG environment variable
|
||||
func initDebugLogging() {
|
||||
godebug := os.Getenv("GODEBUG")
|
||||
debugEnabled = strings.Contains(godebug, "berlin.sneak.pkg.secret")
|
||||
|
||||
if !debugEnabled {
|
||||
// Create a no-op logger that discards all output
|
||||
debugLogger = slog.New(slog.NewTextHandler(io.Discard, nil))
|
||||
return
|
||||
}
|
||||
|
||||
// Check if STDERR is a TTY
|
||||
isTTY := term.IsTerminal(int(syscall.Stderr))
|
||||
|
||||
var handler slog.Handler
|
||||
if isTTY {
|
||||
// TTY output: colorized structured format
|
||||
handler = newColorizedHandler(os.Stderr)
|
||||
} else {
|
||||
// Non-TTY output: JSON Lines format
|
||||
handler = slog.NewJSONHandler(os.Stderr, &slog.HandlerOptions{
|
||||
Level: slog.LevelDebug,
|
||||
})
|
||||
}
|
||||
|
||||
debugLogger = slog.New(handler)
|
||||
}
|
||||
|
||||
// IsDebugEnabled returns true if debug logging is enabled
|
||||
func IsDebugEnabled() bool {
|
||||
return debugEnabled
|
||||
}
|
||||
|
||||
// Debug logs a debug message with optional attributes
|
||||
func Debug(msg string, args ...any) {
|
||||
if !debugEnabled {
|
||||
return
|
||||
}
|
||||
debugLogger.Debug(msg, args...)
|
||||
}
|
||||
|
||||
// DebugF logs a formatted debug message with optional attributes
|
||||
func DebugF(format string, args ...any) {
|
||||
if !debugEnabled {
|
||||
return
|
||||
}
|
||||
debugLogger.Debug(fmt.Sprintf(format, args...))
|
||||
}
|
||||
|
||||
// DebugWith logs a debug message with structured attributes
|
||||
func DebugWith(msg string, attrs ...slog.Attr) {
|
||||
if !debugEnabled {
|
||||
return
|
||||
}
|
||||
debugLogger.LogAttrs(context.Background(), slog.LevelDebug, msg, attrs...)
|
||||
}
|
||||
|
||||
// colorizedHandler implements a TTY-friendly structured log handler
|
||||
type colorizedHandler struct {
|
||||
output io.Writer
|
||||
}
|
||||
|
||||
func newColorizedHandler(output io.Writer) slog.Handler {
|
||||
return &colorizedHandler{output: output}
|
||||
}
|
||||
|
||||
func (h *colorizedHandler) Enabled(_ context.Context, level slog.Level) bool {
|
||||
// Explicitly check that debug is enabled AND the level is DEBUG or higher
|
||||
// This ensures we don't default to INFO level when debug is enabled
|
||||
return debugEnabled && level >= slog.LevelDebug
|
||||
}
|
||||
|
||||
func (h *colorizedHandler) Handle(_ context.Context, record slog.Record) error {
|
||||
if !debugEnabled {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Format: [DEBUG] message {key=value, key2=value2}
|
||||
output := fmt.Sprintf("\033[36m[DEBUG]\033[0m \033[1m%s\033[0m", record.Message)
|
||||
|
||||
if record.NumAttrs() > 0 {
|
||||
output += " \033[33m{"
|
||||
first := true
|
||||
record.Attrs(func(attr slog.Attr) bool {
|
||||
if !first {
|
||||
output += ", "
|
||||
}
|
||||
first = false
|
||||
output += fmt.Sprintf("%s=%#v", attr.Key, attr.Value.Any())
|
||||
return true
|
||||
})
|
||||
output += "}\033[0m"
|
||||
}
|
||||
|
||||
output += "\n"
|
||||
_, err := h.output.Write([]byte(output))
|
||||
return err
|
||||
}
|
||||
|
||||
func (h *colorizedHandler) WithAttrs(attrs []slog.Attr) slog.Handler {
|
||||
// For simplicity, return the same handler
|
||||
// In a more complex implementation, we'd create a new handler with the attrs
|
||||
return h
|
||||
}
|
||||
|
||||
func (h *colorizedHandler) WithGroup(name string) slog.Handler {
|
||||
// For simplicity, return the same handler
|
||||
// In a more complex implementation, we'd create a new handler with the group
|
||||
return h
|
||||
}
|
||||
Reference in New Issue
Block a user