chore: add logger for push notifications

This commit is contained in:
Krispire Admin
2026-06-08 18:13:24 +05:30
parent 05d906aee9
commit f2a04ae652
2 changed files with 71 additions and 16 deletions
+38 -9
View File
@@ -3,8 +3,11 @@ package service
import (
"context"
"encoding/json"
"io"
"net/http"
"net/url"
"strconv"
"strings"
"time"
webpush "github.com/SherClockHolmes/webpush-go"
@@ -81,10 +84,13 @@ func (p *PushSender) SendToUser(ctx context.Context, userID string, payload Push
Endpoint: s.Endpoint,
Keys: webpush.Keys{P256dh: s.P256dh, Auth: s.Auth},
}
status, err := p.sendWithRetry(ctx, body, sub)
status, respBody, err := p.sendWithRetry(ctx, body, sub)
if err != nil {
failed++
p.logger.Warn("push: send failed", zap.String("user", userID), zap.Error(err))
p.logger.Warn("push: send failed",
zap.String("user", userID),
zap.String("host", endpointHost(s.Endpoint)),
zap.Error(err))
continue
}
switch {
@@ -96,7 +102,13 @@ func (p *PushSender) SendToUser(ctx context.Context, userID string, payload Push
}
case status >= 400:
failed++
p.logger.Warn("push: non-2xx", zap.Int("status", status), zap.String("user", userID))
// The response body carries the real reason (e.g. a VAPID
// credential mismatch, malformed request) — log it.
p.logger.Warn("push: non-2xx",
zap.Int("status", status),
zap.String("user", userID),
zap.String("host", endpointHost(s.Endpoint)),
zap.String("body", respBody))
default:
sent++
}
@@ -108,8 +120,10 @@ func (p *PushSender) SendToUser(ctx context.Context, userID string, payload Push
// sendWithRetry posts one notification, retrying on transient failures
// (network error or 429/5xx) with a short backoff that honors Retry-After.
// Returns the final HTTP status, or an error if every attempt errored.
func (p *PushSender) sendWithRetry(ctx context.Context, body []byte, sub *webpush.Subscription) (int, error) {
// Returns the final HTTP status and, on a 4xx/5xx, a snippet of the response
// body (the push service's error reason). Returns an error if every attempt
// errored at the transport level.
func (p *PushSender) sendWithRetry(ctx context.Context, body []byte, sub *webpush.Subscription) (int, string, error) {
var lastErr error
for attempt := 1; attempt <= pushMaxAttempts; attempt++ {
resp, err := webpush.SendNotification(body, sub, &webpush.Options{
@@ -127,18 +141,33 @@ func (p *PushSender) sendWithRetry(ctx context.Context, body []byte, sub *webpus
sleepCtx(ctx, backoff(attempt))
continue
}
return 0, err
return 0, "", err
}
status := resp.StatusCode
retryAfter := resp.Header.Get("Retry-After")
_ = resp.Body.Close()
if isTransientStatus(status) && attempt < pushMaxAttempts {
_ = resp.Body.Close()
sleepCtx(ctx, retryDelay(retryAfter, attempt))
continue
}
return status, nil
// Final attempt — capture the body on errors for diagnostics.
var snippet string
if status >= 400 {
b, _ := io.ReadAll(io.LimitReader(resp.Body, 512))
snippet = strings.TrimSpace(string(b))
}
_ = resp.Body.Close()
return status, snippet, nil
}
return 0, lastErr
return 0, "", lastErr
}
// endpointHost extracts the host of a push endpoint for log context.
func endpointHost(endpoint string) string {
if u, err := url.Parse(endpoint); err == nil {
return u.Host
}
return ""
}
func isTransientStatus(s int) bool {