47 lines
1.6 KiB
Go
47 lines
1.6 KiB
Go
// Package middleware — общие gin-middleware: request-id, access-log
|
||
// и восстановление после паники. Ставятся в cmd/api в таком порядке,
|
||
// где request_id идёт первым — остальные пишут его в свои записи.
|
||
package middleware
|
||
|
||
import (
|
||
"log/slog"
|
||
"time"
|
||
|
||
"github.com/gin-gonic/gin"
|
||
)
|
||
|
||
// AccessLog пишет по одной записи на запрос: метод, путь, статус,
|
||
// длительность, адрес клиента и request_id.
|
||
//
|
||
// Уровень выбирается по коду ответа: 5xx — error, 4xx — warn, остальное —
|
||
// info. Так обычный трафик не засоряет ошибки, а реальные падения видно
|
||
// фильтром уровня.
|
||
func AccessLog() gin.HandlerFunc {
|
||
return func(c *gin.Context) {
|
||
start := time.Now()
|
||
c.Next()
|
||
|
||
attrs := []any{
|
||
"method", c.Request.Method,
|
||
"path", c.Request.URL.Path,
|
||
"status", c.Writer.Status(),
|
||
"duration_ms", time.Since(start).Milliseconds(),
|
||
"client_ip", c.ClientIP(),
|
||
"request_id", RequestIDFrom(c),
|
||
}
|
||
// Кто именно дёргал — важно для аудита, но не все запросы авторизованы.
|
||
if userID := c.GetString("user_id"); userID != "" {
|
||
attrs = append(attrs, "user_id", userID)
|
||
}
|
||
|
||
switch status := c.Writer.Status(); {
|
||
case status >= 500:
|
||
slog.Error("request", attrs...)
|
||
case status >= 400:
|
||
slog.Warn("request", attrs...)
|
||
default:
|
||
slog.Info("request", attrs...)
|
||
}
|
||
}
|
||
}
|