-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathlogging_unix.go
More file actions
114 lines (96 loc) · 2.77 KB
/
logging_unix.go
File metadata and controls
114 lines (96 loc) · 2.77 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
//go:build darwin || linux
package logging
import (
"context"
"fmt"
"io"
"log/slog"
"os"
"golang.org/x/term"
)
// ConfigureLogging sets up logging with colored output for terminals
// and structured logging for non-terminal outputs on Darwin/Linux.
func ConfigureLogging(out io.Writer) error {
baseHandler := slog.NewTextHandler(out, &slog.HandlerOptions{
Level: slog.LevelDebug,
})
handler := &CustomHandler{
handler: baseHandler,
writer: out,
}
logger := slog.New(handler)
slog.SetDefault(logger)
return nil
}
// isTerminalOutput checks if the output is a terminal.
func isTerminalOutput(w io.Writer) bool {
if f, ok := w.(*os.File); ok {
return term.IsTerminal(int(f.Fd()))
}
return false
}
// Colored levels for terminal output.
var levelColors = map[slog.Level]string{
slog.LevelDebug: "\x1b[34m[DEBUG]\x1b[0m", // Blue
slog.LevelInfo: "\x1b[32m[INFO]\x1b[0m", // Green
slog.LevelWarn: "\x1b[33m[WARN]\x1b[0m", // Yellow
slog.LevelError: "\x1b[31m[ERROR]\x1b[0m", // Red
}
// Plain levels for structured logging.
var plainLevelStrings = map[slog.Level]string{
slog.LevelDebug: "[DEBUG]",
slog.LevelInfo: "[INFO]",
slog.LevelWarn: "[WARN]",
slog.LevelError: "[ERROR]",
}
// getLevelString retrieves the appropriate level string, with a fallback for unknown levels.
func getLevelString(level slog.Level, useColors bool) string {
if useColors {
if color, ok := levelColors[level]; ok {
return color
}
return fmt.Sprintf("\x1b[0m[%s]\x1b[0m", level)
}
if plain, ok := plainLevelStrings[level]; ok {
return plain
}
return fmt.Sprintf("[%s]", level)
}
// CustomHandler customizes logging for Darwin/Linux systems.
type CustomHandler struct {
handler slog.Handler
writer io.Writer
}
func (h *CustomHandler) Enabled(ctx context.Context, level slog.Level) bool {
return h.handler.Enabled(ctx, level)
}
func (h *CustomHandler) Handle(ctx context.Context, record slog.Record) error {
if isTerminalOutput(h.writer) {
levelStr := getLevelString(record.Level, true)
// Write level and message
fmt.Fprintf(h.writer, "%s %s", levelStr, record.Message)
// Print all structured attributes
record.Attrs(func(a slog.Attr) bool {
fmt.Fprintf(h.writer, " %s=%v", a.Key, a.Value.Any())
return true
})
fmt.Fprint(h.writer, "\n")
return nil
}
// Clone and add plain level string to the record
newRecord := record.Clone()
newRecord.AddAttrs(slog.String("level_str", getLevelString(record.Level, false)))
return h.handler.Handle(ctx, newRecord)
}
func (h *CustomHandler) WithAttrs(attrs []slog.Attr) slog.Handler {
return &CustomHandler{
handler: h.handler.WithAttrs(attrs),
writer: h.writer,
}
}
func (h *CustomHandler) WithGroup(name string) slog.Handler {
return &CustomHandler{
handler: h.handler.WithGroup(name),
writer: h.writer,
}
}