// SPDX-License-Identifier: GPL-2.0-or-later // Copyright (C) 2026 Bryan Joshua Pedini package main import ( "log/slog" "net/http" "os" "time" ) // NewLogger builds the process-wide structured logger, text output to // stdout, level driven by LOG_LEVEL. func NewLogger(level string) *slog.Logger { var lvl slog.Level switch level { case "debug": lvl = slog.LevelDebug case "warn": lvl = slog.LevelWarn case "error": lvl = slog.LevelError default: lvl = slog.LevelInfo } handler := slog.NewTextHandler(os.Stdout, &slog.HandlerOptions{Level: lvl}) return slog.New(handler) } // statusRecorder captures the status code written by downstream handlers so // the logging middleware can report it. type statusRecorder struct { http.ResponseWriter status int } func (r *statusRecorder) WriteHeader(status int) { r.status = status r.ResponseWriter.WriteHeader(status) } // loggingMiddleware logs method, path, status, and duration at info level // for every request. func (s *WebServer) loggingMiddleware(next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { start := time.Now() rec := &statusRecorder{ResponseWriter: w, status: http.StatusOK} next.ServeHTTP(rec, r) s.Logger.Info("request", "method", r.Method, "path", r.URL.Path, "status", rec.status, "duration", time.Since(start), ) }) }