diff options
| author | Anhgelus Morhtuuzh <william@herges.fr> | 2025-12-26 21:55:57 +0100 |
|---|---|---|
| committer | Anhgelus Morhtuuzh <william@herges.fr> | 2025-12-26 21:55:57 +0100 |
| commit | af11793ca48244eafd7dcdf66ac1dff83995a775 (patch) | |
| tree | 9fab2b55b9d2ec85e6fdfd683759c84a178fa895 /backend/logger.go | |
| parent | 89875be4a5cea6f7b054483417cb6707bb9fc93d (diff) | |
feat(backend): use custom logger
Diffstat (limited to 'backend/logger.go')
| -rw-r--r-- | backend/logger.go | 78 |
1 files changed, 78 insertions, 0 deletions
diff --git a/backend/logger.go b/backend/logger.go new file mode 100644 index 0000000..da5fadb --- /dev/null +++ b/backend/logger.go @@ -0,0 +1,78 @@ +package backend + +import ( + "context" + "log" + "log/slog" + "net/http" + "os" + "runtime/debug" +) + +const ( + loggerKey = "logger" + statusCode = "status_code" +) + +func GetLogger(ctx context.Context) *slog.Logger { + return ctx.Value(loggerKey).(*slog.Logger) +} + +type customWriter struct { + http.ResponseWriter + statusCode int +} + +func (c *customWriter) WriteHeader(statusCode int) { + c.statusCode = statusCode + if statusCode != c.statusCode { + c.ResponseWriter.WriteHeader(statusCode) + } +} + +func GetStatusCode(ctx context.Context) func() int { + return ctx.Value(statusCode).(func() int) +} + +func SetLogger(l *slog.Logger) func(http.Handler) http.Handler { + return func(next http.Handler) http.Handler { + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + logger := l.With("uri", r.RequestURI, "method", r.Method) + ww := &customWriter{ResponseWriter: w, statusCode: http.StatusOK} + ctx := context.WithValue(r.Context(), statusCode, func() int { + return ww.statusCode + }) + ctx = context.WithValue(ctx, loggerKey, logger) + defer func(logger *slog.Logger) { + rec := recover() + if rec == nil { + return + } + if rec == http.ErrAbortHandler { + panic(rec) + } + logger.Error("crashed, recovered", "error", rec, "status", http.StatusInternalServerError) + log.New(os.Stderr, "", 0).Printf("%s\n", debug.Stack()) + http.Error(ww, "internal error", http.StatusInternalServerError) + }(logger) + + next.ServeHTTP(ww, r.WithContext(ctx)) + + if ww.statusCode == http.StatusNotFound { + return + } + var lvl slog.Level + switch { + case ww.statusCode >= 500: + lvl = slog.LevelError + case ww.statusCode >= 400: + lvl = slog.LevelWarn + case ww.statusCode >= 300: + return + default: + lvl = slog.LevelInfo + } + logger.Log(context.Background(), lvl, "handled", "status", ww.statusCode) + }) + } +} |
