From 157f626c2e0853e94643d8184c3fb6f6a1e0dda4 Mon Sep 17 00:00:00 2001 From: Anton Vakhrushev Date: Mon, 15 Jun 2026 08:55:29 +0300 Subject: [PATCH] =?UTF-8?q?=D0=A1=D0=B4=D0=B5=D0=BB=D0=B0=D0=BB=20=D0=B4?= =?UTF-8?q?=D0=BB=D1=8F=20http=20=D0=B7=D0=B0=D0=BF=D1=80=D0=BE=D1=81?= =?UTF-8?q?=D0=BE=D0=B2=20=D1=83=D1=80=D0=BE=D0=B2=D0=B5=D0=BD=D1=8C=20?= =?UTF-8?q?=D0=BB=D0=BE=D0=B3=D0=B8=D1=80=D0=BE=D0=B2=D0=B0=D0=BD=D0=B8?= =?UTF-8?q?=D1=8F=20DEBUG?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- internal/httpapi/httpapi.go | 21 +++++++++++++++-- internal/httpapi/loglevel_internal_test.go | 27 ++++++++++++++++++++++ 2 files changed, 46 insertions(+), 2 deletions(-) create mode 100644 internal/httpapi/loglevel_internal_test.go diff --git a/internal/httpapi/httpapi.go b/internal/httpapi/httpapi.go index 82f825e..3679ff7 100644 --- a/internal/httpapi/httpapi.go +++ b/internal/httpapi/httpapi.go @@ -13,6 +13,7 @@ import ( "net/http" "net/url" "strconv" + "strings" "time" "github.com/go-chi/chi/v5" @@ -340,7 +341,9 @@ func errJSON(err error) map[string]string { return map[string]string{"error": err.Error()} } -// requestLogger пишет структурированный лог по каждому запросу. +// requestLogger пишет структурированный лог по каждому запросу. Частые +// служебные запросы (healthcheck, GET-страницы веб-UI с авто-рефрешем) пишем +// на DEBUG, чтобы не зашумлять INFO; мутации и REST API остаются на INFO. func requestLogger(logger *slog.Logger) func(http.Handler) http.Handler { return func(next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { @@ -349,7 +352,7 @@ func requestLogger(logger *slog.Logger) func(http.Handler) http.Handler { next.ServeHTTP(ww, r) - logger.Info("http request", + logger.Log(r.Context(), requestLogLevel(r), "http request", "method", r.Method, "path", r.URL.Path, "status", ww.Status(), @@ -360,3 +363,17 @@ func requestLogger(logger *slog.Logger) func(http.Handler) http.Handler { }) } } + +// requestLogLevel понижает уровень для частых служебных запросов: healthcheck +// и GET-страницы веб-UI (список авто-рефрешится каждые 5 с). Мутации и REST +// API (`/api/...`) остаются на INFO. +func requestLogLevel(r *http.Request) slog.Level { + switch { + case r.URL.Path == "/healthz": + return slog.LevelDebug + case r.Method == http.MethodGet && !strings.HasPrefix(r.URL.Path, "/api"): + return slog.LevelDebug + default: + return slog.LevelInfo + } +} diff --git a/internal/httpapi/loglevel_internal_test.go b/internal/httpapi/loglevel_internal_test.go new file mode 100644 index 0000000..55f27d4 --- /dev/null +++ b/internal/httpapi/loglevel_internal_test.go @@ -0,0 +1,27 @@ +package httpapi + +import ( + "log/slog" + "net/http/httptest" + "testing" +) + +func TestRequestLogLevel(t *testing.T) { + cases := []struct { + method, path string + want slog.Level + }{ + {"GET", "/healthz", slog.LevelDebug}, // healthcheck — тихо + {"GET", "/", slog.LevelDebug}, // список (авто-рефреш) + {"GET", "/review/1", slog.LevelDebug}, // страница ревью + {"GET", "/api/downloads", slog.LevelInfo}, // REST API — на INFO + {"POST", "/ui/downloads/1/apply", slog.LevelInfo}, // мутация — на INFO + {"POST", "/api/downloads", slog.LevelInfo}, // приём — на INFO + } + for _, c := range cases { + r := httptest.NewRequest(c.method, c.path, nil) + if got := requestLogLevel(r); got != c.want { + t.Errorf("%s %s: level=%v, want %v", c.method, c.path, got, c.want) + } + } +}