Skip to content

Commit 769d065

Browse files
dunglasCopilot
andauthored
fix: log messages and levels (includes perf optimization) (#1119)
* fix: log messages and levels * review and optims * use http.StatusText * Apply suggestions from code review Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> Signed-off-by: Kévin Dunglas <kevin@dunglas.fr> * fix * cleanup * refactor * Update subscription.go Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> Signed-off-by: Kévin Dunglas <kevin@dunglas.fr> --------- Signed-off-by: Kévin Dunglas <kevin@dunglas.fr> Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
1 parent be71111 commit 769d065

13 files changed

+202
-118
lines changed

authorization.go

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -194,5 +194,8 @@ func canDispatch(s *TopicSelectorStore, topics, topicSelectors []string) bool {
194194
func (h *Hub) httpAuthorizationError(w http.ResponseWriter, r *http.Request, err error) {
195195
http.Error(w, http.StatusText(http.StatusUnauthorized), http.StatusUnauthorized)
196196

197-
h.logger.DebugContext(r.Context(), "Topic selectors not matched, not provided or authorization error", slog.Any("error", err))
197+
ctx := r.Context()
198+
if h.logger.Enabled(ctx, slog.LevelDebug) {
199+
h.logger.LogAttrs(ctx, slog.LevelDebug, "Topic selectors not matched, not provided or authorization error", slog.Any("error", err))
200+
}
198201
}

bolt.go

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -225,7 +225,10 @@ func (t *BoltTransport) dispatchHistory(ctx context.Context, s *LocalSubscriber,
225225
s.HistoryDispatched(responseLastEventID)
226226

227227
err := fmt.Errorf("unable to unmarshal update: %w", err)
228-
t.logger.ErrorContext(ctx, "Unable to unmarshal update coming from the Bolt DB", slog.Any("update", update), slog.Any("error", err))
228+
229+
if t.logger.Enabled(ctx, slog.LevelError) {
230+
t.logger.LogAttrs(ctx, slog.LevelError, "Unable to unmarshal update coming from the Bolt DB", slog.Any("update", update), slog.Any("error", err))
231+
}
229232

230233
return err
231234
}
@@ -240,7 +243,9 @@ func (t *BoltTransport) dispatchHistory(ctx context.Context, s *LocalSubscriber,
240243
s.HistoryDispatched(responseLastEventID)
241244

242245
if !afterFromID {
243-
t.logger.InfoContext(ctx, "Can't find requested LastEventID")
246+
if t.logger.Enabled(ctx, slog.LevelInfo) {
247+
t.logger.LogAttrs(ctx, slog.LevelInfo, "Can't find requested LastEventID")
248+
}
244249
}
245250

246251
return nil

config_deprecated.go

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -274,11 +274,13 @@ func Start() {
274274
log.Fatalln(err)
275275
}
276276

277+
ctx := context.Background()
278+
277279
defer func() {
278-
if err := h.transport.Close(context.Background()); err != nil {
280+
if err := h.transport.Close(ctx); err != nil {
279281
log.Fatalln(err)
280282
}
281283
}()
282284

283-
h.Serve()
285+
h.Serve(ctx)
284286
}

demo.go

Lines changed: 14 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ import (
1010
"time"
1111
)
1212

13-
const linkSuffix = `>; rel="mercure"`
13+
const hubLink = "<" + defaultHubURL + `>; rel="mercure"`
1414

1515
// uiContent is our static web server content.
1616
//
@@ -24,26 +24,24 @@ var uiContent embed.FS
2424
func (h *Hub) Demo(w http.ResponseWriter, r *http.Request) {
2525
// JSON-LD is the preferred format
2626
_ = mime.AddExtensionType(".jsonld", "application/ld+json")
27-
2827
url := r.URL.String()
2928
mimeType := mime.TypeByExtension(filepath.Ext(r.URL.Path))
3029

3130
query := r.URL.Query()
3231
body := query.Get("body")
3332
jwt := query.Get("jwt")
3433

35-
hubLink := "<" + defaultHubURL + linkSuffix
36-
if h.cookieName != defaultCookieName {
37-
hubLink = hubLink + `; cookie-name="` + h.cookieName + `"`
38-
}
39-
40-
header := w.Header()
4134
// Several Link headers are set on purpose to allow testing advanced discovery mechanism
42-
header.Add("Link", hubLink)
43-
header.Add("Link", "<"+url+`>; rel="self"`)
35+
header := w.Header()
36+
37+
if h.cookieName == defaultCookieName {
38+
header["Link"] = append(header["Link"], hubLink, "<"+url+`>; rel="self"`)
39+
} else {
40+
header["Link"] = append(header["Link"], hubLink+`; cookie-name="`+h.cookieName+`"`, "<"+url+`>; rel="self"`)
41+
}
4442

4543
if mimeType != "" {
46-
header.Set("Content-Type", mimeType)
44+
header["Content-Type"] = []string{mimeType}
4745
}
4846

4947
cookie := &http.Cookie{
@@ -61,6 +59,10 @@ func (h *Hub) Demo(w http.ResponseWriter, r *http.Request) {
6159
http.SetCookie(w, cookie)
6260

6361
if _, err := io.WriteString(w, body); err != nil {
64-
h.logger.InfoContext(r.Context(), "Failed to write demo response", slog.Any("error", err))
62+
ctx := r.Context()
63+
64+
if h.logger.Enabled(ctx, slog.LevelInfo) {
65+
h.logger.LogAttrs(ctx, slog.LevelInfo, "Failed to write demo response", slog.Any("error", err))
66+
}
6567
}
6668
}

demo_test.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ func TestEmptyBodyAndJWT(t *testing.T) {
2121

2222
resp := w.Result()
2323
assert.Equal(t, "application/ld+json", resp.Header.Get("Content-Type"))
24-
assert.Equal(t, []string{"<" + defaultHubURL + linkSuffix, "<https://example.com/demo/foo.jsonld>; rel=\"self\""}, resp.Header["Link"])
24+
assert.Equal(t, []string{hubLink, `<https://example.com/demo/foo.jsonld>; rel="self"`}, resp.Header["Link"])
2525

2626
cookie := resp.Cookies()[0]
2727
assert.Equal(t, "mercureAuthorization", cookie.Name)
@@ -47,7 +47,7 @@ func TestBodyAndJWT(t *testing.T) {
4747

4848
resp := w.Result()
4949
assert.Contains(t, resp.Header.Get("Content-Type"), "xml") // Before Go 1.17, the charset wasn't set
50-
assert.Equal(t, []string{"<" + defaultHubURL + linkSuffix, "<https://example.com/demo/foo/bar.xml?body=<hello/>&jwt=token>; rel=\"self\""}, resp.Header["Link"])
50+
assert.Equal(t, []string{hubLink, `<https://example.com/demo/foo/bar.xml?body=<hello/>&jwt=token>; rel="self"`}, resp.Header["Link"])
5151

5252
cookie := resp.Cookies()[0]
5353
assert.Equal(t, "mercureAuthorization", cookie.Name)

handler.go

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package mercure
33
import (
44
"context"
55
"io/fs"
6+
"log/slog"
67
"net/http"
78

89
"github.com/gorilla/mux"
@@ -83,7 +84,9 @@ func (h *Hub) registerSubscriptionHandlers(ctx context.Context, r *mux.Router) {
8384
}
8485

8586
if _, ok := h.transport.(TransportSubscribers); !ok {
86-
h.logger.ErrorContext(ctx, "The current transport doesn't support subscriptions. Subscription API disabled.")
87+
if h.logger.Enabled(ctx, slog.LevelError) {
88+
h.logger.LogAttrs(ctx, slog.LevelError, "The current transport doesn't support subscriptions. Subscription API disabled.")
89+
}
8790

8891
return
8992
}

handler_deprecated.go

Lines changed: 38 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -22,12 +22,12 @@ import (
2222
// Serve starts the HTTP server.
2323
//
2424
// Deprecated: use the Caddy server module or the standalone library instead.
25-
func (h *Hub) Serve() { //nolint:funlen
25+
func (h *Hub) Serve(ctx context.Context) { //nolint:funlen
2626
addr := h.config.GetString("addr")
2727

2828
h.server = &http.Server{
2929
Addr: addr,
30-
Handler: h.baseHandler(),
30+
Handler: h.baseHandler(ctx),
3131
ReadTimeout: h.config.GetDuration("read_timeout"),
3232
ReadHeaderTimeout: h.config.GetDuration("read_header_timeout"),
3333
WriteTimeout: h.config.GetDuration("write_timeout"),
@@ -44,22 +44,30 @@ func (h *Hub) Serve() { //nolint:funlen
4444
WriteTimeout: h.config.GetDuration("write_timeout"),
4545
}
4646

47-
h.logger.Info("Mercure metrics started", slog.String("addr", addr))
47+
if h.logger.Enabled(ctx, slog.LevelInfo) {
48+
h.logger.LogAttrs(ctx, slog.LevelInfo, "Mercure metrics started", slog.String("addr", addr))
49+
}
4850

49-
go h.metricsServer.ListenAndServe()
51+
go func() {
52+
if err := h.metricsServer.ListenAndServe(); err != nil && !errors.Is(err, http.ErrServerClosed) && h.logger.Enabled(ctx, slog.LevelError) { //nolint:gosec
53+
h.logger.LogAttrs(ctx, slog.LevelError, "Mercure metrics server error", slog.Any("error", err))
54+
}
55+
}()
5056
}
5157

5258
acme := len(h.allowedHosts) > 0
5359

5460
certFile := h.config.GetString("cert_file")
5561
keyFile := h.config.GetString("key_file")
5662

57-
done := h.listenShutdown()
63+
done := h.listenShutdown(ctx)
5864

5965
var err error
6066

6167
if !acme && certFile == "" && keyFile == "" { //nolint:nestif
62-
h.logger.Info("Mercure started", slog.String("protocol", "http"), slog.String("addr", addr))
68+
if h.logger.Enabled(ctx, slog.LevelInfo) {
69+
h.logger.LogAttrs(ctx, slog.LevelInfo, "Mercure started", slog.String("protocol", "http"), slog.String("addr", addr))
70+
}
6371

6472
err = h.server.ListenAndServe()
6573
} else {
@@ -78,23 +86,30 @@ func (h *Hub) Serve() { //nolint:funlen
7886
h.server.TLSConfig = certManager.TLSConfig()
7987

8088
// Mandatory for Let's Encrypt http-01 challenge
81-
go http.ListenAndServe(h.config.GetString("acme_http01_addr"), certManager.HTTPHandler(nil)) //nolint:gosec
89+
go func() {
90+
//nolint:gosec
91+
if err := http.ListenAndServe(h.config.GetString("acme_http01_addr"), certManager.HTTPHandler(nil)); err != nil && !errors.Is(err, http.ErrServerClosed) && h.logger.Enabled(ctx, slog.LevelError) {
92+
h.logger.LogAttrs(ctx, slog.LevelError, "Error running HTTP endpoint", slog.Any("error", err))
93+
}
94+
}()
8295
}
8396

84-
h.logger.Info("Mercure started", slog.String("protocol", "https"), slog.String("addr", addr))
97+
if h.logger.Enabled(ctx, slog.LevelInfo) {
98+
h.logger.LogAttrs(ctx, slog.LevelInfo, "Mercure started", slog.String("protocol", "https"), slog.String("addr", addr))
99+
}
85100

86101
err = h.server.ListenAndServeTLS(certFile, keyFile)
87102
}
88103

89-
if !errors.Is(err, http.ErrServerClosed) {
90-
h.logger.Error("Unexpected error", slog.Any("error", err))
104+
if !errors.Is(err, http.ErrServerClosed) && h.logger.Enabled(ctx, slog.LevelError) {
105+
h.logger.LogAttrs(ctx, slog.LevelError, "Unexpected error", slog.Any("error", err))
91106
}
92107

93108
<-done
94109
}
95110

96111
// Deprecated: use the Caddy server module or the standalone library instead.
97-
func (h *Hub) listenShutdown() <-chan struct{} {
112+
func (h *Hub) listenShutdown(ctx context.Context) <-chan struct{} {
98113
idleConnsClosed := make(chan struct{})
99114

100115
h.server.RegisterOnShutdown(func() {
@@ -110,17 +125,19 @@ func (h *Hub) listenShutdown() <-chan struct{} {
110125
signal.Notify(sigint, os.Interrupt)
111126
<-sigint
112127

113-
if err := h.server.Shutdown(context.Background()); err != nil {
114-
h.logger.Error("Unexpected error during server shutdown", slog.Any("error", err))
128+
if err := h.server.Shutdown(ctx); err != nil && h.logger.Enabled(ctx, slog.LevelError) {
129+
h.logger.LogAttrs(ctx, slog.LevelError, "Unexpected error during server shutdown", slog.Any("error", err))
115130
}
116131

117132
if h.metricsServer != nil {
118-
if err := h.metricsServer.Shutdown(context.Background()); err != nil {
119-
h.logger.Error("Unexpected error during metrics server shutdown", slog.Any("error", err))
133+
if err := h.metricsServer.Shutdown(ctx); err != nil && h.logger.Enabled(ctx, slog.LevelError) {
134+
h.logger.LogAttrs(ctx, slog.LevelError, "Unexpected error during metrics server shutdown", slog.Any("error", err))
120135
}
121136
}
122137

123-
h.logger.Info("My Baby Shot Me Down")
138+
if h.logger.Enabled(ctx, slog.LevelInfo) {
139+
h.logger.LogAttrs(ctx, slog.LevelInfo, "My Baby Shot Me Down")
140+
}
124141

125142
select {
126143
case <-idleConnsClosed:
@@ -135,9 +152,9 @@ func (h *Hub) listenShutdown() <-chan struct{} {
135152
// chainHandlers configures and chains handlers.
136153
//
137154
// Deprecated: use the Caddy server module or the standalone library instead.
138-
func (h *Hub) chainHandlers() http.Handler { //nolint:funlen
155+
func (h *Hub) chainHandlers(ctx context.Context) http.Handler { //nolint:funlen
139156
r := mux.NewRouter()
140-
h.registerSubscriptionHandlers(context.Background(), r)
157+
h.registerSubscriptionHandlers(ctx, r)
141158

142159
r.HandleFunc(defaultHubURL, h.SubscribeHandler).Methods(http.MethodGet, http.MethodHead)
143160
r.HandleFunc(defaultHubURL, h.PublishHandler).Methods(http.MethodPost)
@@ -200,7 +217,7 @@ func (h *Hub) chainHandlers() http.Handler { //nolint:funlen
200217

201218
var loggingHandler http.Handler
202219

203-
if h.logger.Enabled(context.Background(), slog.LevelError) {
220+
if h.logger.Enabled(ctx, slog.LevelError) {
204221
loggingHandler = handlers.CombinedLoggingHandler(os.Stderr, secureHandler)
205222
} else {
206223
loggingHandler = secureHandler
@@ -215,15 +232,15 @@ func (h *Hub) chainHandlers() http.Handler { //nolint:funlen
215232
}
216233

217234
// Deprecated: use the Caddy server module or the standalone library instead.
218-
func (h *Hub) baseHandler() http.Handler {
235+
func (h *Hub) baseHandler(ctx context.Context) http.Handler {
219236
mainRouter := mux.NewRouter()
220237
mainRouter.UseEncodedPath()
221238
mainRouter.SkipClean(true)
222239

223240
// Register /healthz (if enabled, in a way that doesn't pollute the HTTP logs).
224241
registerHealthz(mainRouter)
225242

226-
handler := h.chainHandlers()
243+
handler := h.chainHandlers(ctx)
227244
mainRouter.PathPrefix("/").Handler(handler)
228245

229246
return mainRouter

localsubscriber.go

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -117,7 +117,9 @@ func (s *LocalSubscriber) Disconnect() {
117117
func (s *LocalSubscriber) handleFullChan(ctx context.Context) {
118118
s.doDisconnect()
119119

120-
s.logger.ErrorContext(ctx, "Subscriber unable to receive updates fast enough")
120+
if s.logger.Enabled(ctx, slog.LevelInfo) {
121+
s.logger.LogAttrs(ctx, slog.LevelInfo, "Subscriber unable to receive updates fast enough")
122+
}
121123
}
122124

123125
func (s *LocalSubscriber) doDisconnect() {

0 commit comments

Comments
 (0)