// 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...) } } }