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
115
116
117
118
119
120
121
122
|
package main
import (
"context"
"fmt"
"log/slog"
"os"
"strconv"
"strings"
"unicode"
"unicode/utf8"
)
type IRCLogHandler struct {
level slog.Level
}
func NewIRCLogHandler(level slog.Level) *IRCLogHandler {
return &IRCLogHandler{
level: level,
}
}
func (h *IRCLogHandler) Enabled(_ context.Context, level slog.Level) bool {
return level >= h.level
}
func (h *IRCLogHandler) Handle(_ context.Context, r slog.Record) error {
var sb strings.Builder
sb.WriteString("PRIVMSG " + ircChannel + " :")
sb.WriteString(r.Message)
r.Attrs(func(a slog.Attr) bool {
sb.WriteString(" ")
key := a.Key
if needsQuoting(key) {
key = strconv.Quote(key)
}
sb.WriteString(key)
sb.WriteString("=")
val := attrValueToString(a.Value)
if needsQuoting(val) {
val = strconv.Quote(val)
}
sb.WriteString(val)
return true
})
str := sb.String()
select {
case ircSendBuffered <- str:
default:
fmt.Fprintln(os.Stderr, "DROP")
}
fmt.Fprintln(os.Stderr, str)
return nil
}
func (h *IRCLogHandler) WithAttrs(attrs []slog.Attr) slog.Handler {
return h
}
func (h *IRCLogHandler) WithGroup(_ string) slog.Handler {
return h
}
func attrValueToString(v slog.Value) string {
return v.String()
}
func init() {
slog.SetDefault(slog.New(NewIRCLogHandler(slog.LevelInfo)))
}
// copied from slog
func needsQuoting(s string) bool {
if len(s) == 0 {
return true
}
for i := 0; i < len(s); {
b := s[i]
if b < utf8.RuneSelf {
if b != '\\' && (b == ' ' || b == '=' || !safeSet[b]) {
return true
}
i++
continue
}
r, size := utf8.DecodeRuneInString(s[i:])
if r == utf8.RuneError || unicode.IsSpace(r) || !unicode.IsPrint(r) {
return true
}
i += size
}
return false
}
var safeSet = [256]bool{
'!': true, '#': true, '$': true, '%': true, '&': true, '\'': true,
'*': true, '+': true, ',': true, '-': true, '.': true, '/': true,
'0': true, '1': true, '2': true, '3': true, '4': true,
'5': true, '6': true, '7': true, '8': true, '9': true,
':': true, ';': true, '<': true, '>': true, '?': true, '@': true,
'A': true, 'B': true, 'C': true, 'D': true, 'E': true, 'F': true,
'G': true, 'H': true, 'I': true, 'J': true, 'K': true, 'L': true,
'M': true, 'N': true, 'O': true, 'P': true, 'Q': true, 'R': true,
'S': true, 'T': true, 'U': true, 'V': true, 'W': true, 'X': true,
'Y': true, 'Z': true, '[': true, ']': true, '^': true, '_': true,
'a': true, 'b': true, 'c': true, 'd': true, 'e': true, 'f': true,
'g': true, 'h': true, 'i': true, 'j': true, 'k': true, 'l': true,
'm': true, 'n': true, 'o': true, 'p': true, 'q': true, 'r': true,
's': true, 't': true, 'u': true, 'v': true, 'w': true, 'x': true,
'y': true, 'z': true, '{': true, '|': true, '}': true, '~': true,
}
|