Skip to content

Commit 0bb808d

Browse files
committed
improve notification formatting
1 parent c159843 commit 0bb808d

3 files changed

Lines changed: 72 additions & 21 deletions

File tree

src/config/config.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -151,7 +151,7 @@ type DiscordNotif struct {
151151
}
152152

153153
type HttpNotif struct {
154-
ReceiverURL string `env:"HTTP_RECEIVER"`
154+
ReceiverURLs []string `env:"HTTP_RECEIVER"`
155155
}
156156
func (cfg *Config) ReadEnv() {
157157

src/logging/notify.go

Lines changed: 45 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -2,15 +2,17 @@ package logging
22

33
import (
44
"context"
5+
"encoding/json"
56
"explo/src/config"
67
"fmt"
78
"log/slog"
9+
"net/http"
810
"strings"
911

1012
"github.com/nikoksr/notify"
1113
"github.com/nikoksr/notify/service/discord"
14+
nhttp "github.com/nikoksr/notify/service/http"
1215
"github.com/nikoksr/notify/service/matrix"
13-
"github.com/nikoksr/notify/service/http"
1416
"maunium.net/go/mautrix/id"
1517
)
1618

@@ -66,49 +68,74 @@ func sendDiscord(cfg config.DiscordNotif, msg string) error {
6668
}
6769

6870
func sendHttp(cfg config.HttpNotif, msg string) error {
69-
httpNotify := http.New()
71+
httpNotify := nhttp.New()
72+
webhooks := getNotifWebhooks(cfg.ReceiverURLs)
7073

71-
httpNotify.AddReceiversURLs(cfg.ReceiverURL)
72-
httpNotify.AddReceivers(&http.Webhook{
73-
URL: cfg.ReceiverURL,
74-
})
74+
httpNotify.AddReceivers(webhooks...)
7575
notifier := notify.NewWithServices(httpNotify)
7676

77-
if err := notifier.Send(context.Background(), "Explo", msg); err != nil {
77+
if err := notifier.Send(context.Background(), "", msg); err != nil {
7878
return fmt.Errorf("failed to send HTTP notification: %s", err.Error())
7979
}
8080
return nil
8181
}
8282

83-
// format notification to JSON
84-
func formatNotification(r slog.Record) string {
85-
var attrs []string
83+
func getNotifWebhooks(urls []string) []*nhttp.Webhook{
84+
var webhooks []*nhttp.Webhook
8685

87-
r.Attrs(func(a slog.Attr) bool {
88-
attrs = append(attrs, fmt.Sprintf("%s=%v", a.Key, a.Value))
89-
return true
90-
})
86+
for _, url := range urls {
9187

88+
webhooks = append(webhooks, &nhttp.Webhook{
89+
ContentType: "application/json",
90+
URL: url,
91+
Method: http.MethodPost,
92+
BuildPayload: func(subject, message string) (payload any) {
93+
payl := json.RawMessage(message)
94+
return payl
95+
},
9296

97+
})
98+
}
99+
return webhooks
100+
}
101+
102+
// format notification for message client
103+
func formatRecordMsgClient(n Notification) string {
104+
attrs := make([]string, 0, len(n.Attrs))
105+
106+
for k, v := range n.Attrs {
107+
attrs = append(attrs, fmt.Sprintf("%s=%v", k, v))
108+
}
93109
return fmt.Sprintf(
94110
"[%s] %s\n%s",
95-
r.Level,
96-
r.Message,
111+
n.Level,
112+
n.Message,
97113
strings.Join(attrs, ", "),
98114
)
99115
}
100116

101-
func (c NotificationClient) SendNotification(r slog.Record) {
117+
func formatRecordJSON(n Notification) string {
118+
nJSON, err := json.Marshal(n)
119+
if err != nil {
120+
slog.Error("failed to marshal notification", "err", err)
121+
}
122+
return string(nJSON)
123+
}
124+
125+
126+
func (c NotificationClient) SendNotification(n Notification) {
102127
var err error
103-
msg := formatNotification(r)
104128
switch c.Cfg.Service {
105129
case "matrix":
130+
msg := formatRecordMsgClient(n)
106131
err = sendMatrix(c.Cfg.Matrix, msg)
107132

108133
case "discord":
134+
msg := formatRecordMsgClient(n)
109135
err = sendDiscord(c.Cfg.Discord, msg)
110136

111137
case "http":
138+
msg := formatRecordJSON(n)
112139
err = sendHttp(c.Cfg.Http, msg)
113140

114141
case "": // no system defined

src/logging/notify_handler.go

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package logging
33
import (
44
"log/slog"
55
"context"
6+
"time"
67
)
78
// slog handler that checks whether to send notifications
89

@@ -11,15 +12,23 @@ type notifyHandler struct {
1112
notify NotificationClient
1213
}
1314

15+
type Notification struct {
16+
Time time.Time `json:"time"`
17+
Level string `json:"level"`
18+
Message string `json:"message"`
19+
Attrs map[string]any `json:"attributes"`
20+
21+
}
22+
1423
func (h *notifyHandler) Enabled(ctx context.Context, level slog.Level) bool {
1524
return h.handler.Enabled(ctx, level)
1625
}
1726

1827
func (h *notifyHandler) Handle(ctx context.Context, r slog.Record) error {
1928
if shouldNotify(r) {
2029
// send notification in another goroutine
21-
rec := r
22-
go h.notify.SendNotification(rec)
30+
notifyStruct := recordToStruct(r)
31+
go h.notify.SendNotification(notifyStruct)
2332
}
2433
return h.handler.Handle(ctx, r)
2534
}
@@ -50,4 +59,19 @@ func shouldNotify(r slog.Record) bool {
5059
})
5160

5261
return notify
62+
}
63+
64+
func recordToStruct(r slog.Record) Notification {
65+
attrs := make(map[string]any, r.NumAttrs())
66+
67+
r.Attrs(func(a slog.Attr) bool {
68+
attrs[a.Key] = a.Value.Any()
69+
return true
70+
})
71+
72+
return Notification{
73+
Level: r.Level.String(),
74+
Message: r.Message,
75+
Attrs: attrs,
76+
}
5377
}

0 commit comments

Comments
 (0)