Skip to content

Commit c1b76ca

Browse files
committed
add ReplaceGroup
1 parent 1419ab6 commit c1b76ca

File tree

2 files changed

+41
-29
lines changed

2 files changed

+41
-29
lines changed

journal.go

Lines changed: 35 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -6,59 +6,65 @@ import (
66
"encoding/binary"
77
"io"
88
"log/slog"
9+
"log/syslog"
910
"os"
1011
"path"
1112
"runtime"
1213
"slices"
1314
"strconv"
1415
)
1516

16-
type Priority int
17-
1817
const (
19-
priEmerg Priority = iota
20-
priAlert
21-
priCrit
22-
priErr
23-
priWarning
24-
priNotice
25-
priInfo
26-
priDebug
27-
)
18+
LevelNotice slog.Level = 1
2819

29-
const (
30-
LevelNotice slog.Level = 1
3120
LevelCritical slog.Level = slog.LevelError + 1
3221
LevelAlert slog.Level = slog.LevelError + 2
3322
LevelEmergency slog.Level = slog.LevelError + 3
3423
)
3524

36-
func levelToPriority(l slog.Level) Priority {
25+
func levelToPriority(l slog.Level) syslog.Priority {
3726
switch l {
3827
case slog.LevelDebug:
39-
return priDebug
28+
return syslog.LOG_DEBUG
4029
case slog.LevelInfo:
41-
return priInfo
30+
return syslog.LOG_INFO
4231
case LevelNotice:
43-
return priNotice
32+
return syslog.LOG_NOTICE
4433
case slog.LevelWarn:
45-
return priWarning
34+
return syslog.LOG_WARNING
4635
case slog.LevelError:
47-
return priErr
36+
return syslog.LOG_ERR
4837
case LevelCritical:
49-
return priCrit
38+
return syslog.LOG_CRIT
5039
case LevelAlert:
51-
return priAlert
40+
return syslog.LOG_ALERT
41+
case LevelEmergency:
42+
return syslog.LOG_EMERG
5243
default:
53-
panic("unreachable")
44+
return syslog.LOG_INFO
5445
}
5546
}
5647

5748
type Options struct {
58-
Level slog.Leveler
49+
Level slog.Leveler
50+
51+
// ReplaceAttr is called on all non-builtin Attrs before they are written.
52+
// This can be useful for processing attributes to be in the correct format
53+
// for log statements outside of your own code as the journal only accepts
54+
// variables that are uppercase and consist only of characters, numbers and
55+
// underscores, and may not begin with an underscore.
5956
ReplaceAttr func(groups []string, a slog.Attr) slog.Attr
57+
58+
// ReplaceGroup is called on all group names before they are written. This
59+
// can be useful for processing group names to be in the correct format for
60+
// log statements outside of your own code as the journal only accepts
61+
// variables that are uppercase and consist only of characters, numbers and
62+
// underscores, and may not begin with an underscore.
63+
ReplaceGroup func(group string) string
6064
}
6165

66+
// Handler sends logs to the systemd journal.
67+
// variable names must be in uppercase and consist only of characters, numbers and underscores, and may not begin with an underscore.
6268
type Handler struct {
6369
opts Options
6470
// NOTE: We only do single Write() calls. Either the message fits in a
@@ -202,6 +208,9 @@ func (h *Handler) appendAttr(b []byte, prefix string, a slog.Attr) []byte {
202208
// If a group's key is not empty, append the group's key as a prefix.
203209
// Otherwise, if a group's key is empty, inline the group's Attrs.
204210
if a.Key != "" {
211+
if rep := h.opts.ReplaceGroup; rep != nil {
212+
a.Key = rep(a.Key)
213+
}
205214
prefix += a.Key + "_"
206215
}
207216
for _, a := range attrs {
@@ -229,6 +238,9 @@ func (h *Handler) WithGroup(name string) slog.Handler {
229238
if name == "" {
230239
return h
231240
}
241+
if rep := h.opts.ReplaceGroup; rep != nil {
242+
name = rep(name)
243+
}
232244
return &Handler{
233245
opts: h.opts,
234246
w: h.w,

journal_test.go

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -126,27 +126,27 @@ func TestWithAttrs(t *testing.T) {
126126
buf := new(bytes.Buffer)
127127
h.w = buf
128128

129-
h2 := h.WithAttrs([]slog.Attr{{Key: "key2", Value: slog.StringValue("value2")}})
130-
h3 := h2.WithAttrs([]slog.Attr{{Key: "key3", Value: slog.StringValue("value3")}})
129+
h2 := h.WithAttrs([]slog.Attr{{Key: "KEY2", Value: slog.StringValue("value2")}})
130+
h3 := h2.WithAttrs([]slog.Attr{{Key: "KEY3", Value: slog.StringValue("value3")}})
131131

132132
_ = h2.Handle(context.TODO(), slog.NewRecord(time.Now(), slog.LevelInfo, "Hello, World!", 0))
133133

134134
kv, err := deserializeKeyValue(buf)
135135
if err != nil {
136136
t.Fatal(err)
137137
}
138-
if kv["key2"] != "value2" {
139-
t.Error("expected key2=value2", kv)
138+
if kv["KEY2"] != "value2" {
139+
t.Error("expected KEY2=value2", kv)
140140
}
141141
_ = h3.Handle(context.TODO(), slog.NewRecord(time.Now(), slog.LevelInfo, "Hello, World!", 0))
142142
kv, err = deserializeKeyValue(buf)
143143
if err != nil {
144144
t.Fatal(err)
145145
}
146-
if kv["key2"] != "value2" {
146+
if kv["KEY2"] != "value2" {
147147
t.Error("expected key2=value2", kv)
148148
}
149-
if kv["key3"] != "value3" {
149+
if kv["KEY3"] != "value3" {
150150
t.Error("expected key3=value3", kv)
151151
}
152152

0 commit comments

Comments
 (0)