package middleware import ( "bytes" "io" "log" "net/http" "time" ) // LoggingMiddleware логирует входящие HTTP-запросы func LoggingMiddleware(logger *log.Logger) func(http.Handler) http.Handler { return func(next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { start := time.Now() // Логируем основные параметры запроса logData := map[string]interface{}{ "method": r.Method, "path": r.URL.Path, "query": r.URL.RawQuery, "ip": r.RemoteAddr, } // Чтение тела запроса (для логирования) var bodyBytes []byte if r.Body != nil { bodyBytes, _ = io.ReadAll(r.Body) r.Body = io.NopCloser(bytes.NewBuffer(bodyBytes)) if len(bodyBytes) > 0 { logData["body_size"] = len(bodyBytes) // Для JSON-запросов логируем тело if r.Header.Get("Content-Type") == "application/json" { logData["body"] = string(bodyBytes) } } } // Перехват ответа rw := &responseWriter{ResponseWriter: w, status: http.StatusOK} // Обработка запроса next.ServeHTTP(rw, r) // Дополняем данные для логирования duration := time.Since(start) logData["status"] = rw.status logData["duration"] = duration.String() logData["response_size"] = rw.size // Форматированный вывод лога logger.Printf( "%s %s %d %s | IP: %s | Duration: %s | Body: %d bytes", r.Method, r.URL.Path, rw.status, http.StatusText(rw.status), r.RemoteAddr, duration, len(bodyBytes), ) }) } } // Кастомный responseWriter для перехвата статуса и размера ответа type responseWriter struct { http.ResponseWriter status int size int } func (rw *responseWriter) WriteHeader(code int) { rw.status = code rw.ResponseWriter.WriteHeader(code) } func (rw *responseWriter) Write(b []byte) (int, error) { size, err := rw.ResponseWriter.Write(b) rw.size += size return size, err }