97 lines
2.4 KiB
Go
97 lines
2.4 KiB
Go
package middleware
|
||
|
||
import (
|
||
"bufio"
|
||
"bytes"
|
||
"errors"
|
||
"github.com/gorilla/websocket"
|
||
"io"
|
||
"log"
|
||
"net"
|
||
"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) {
|
||
// Полностью пропускаем WebSocket запросы
|
||
if websocket.IsWebSocketUpgrade(r) {
|
||
next.ServeHTTP(w, r)
|
||
return
|
||
}
|
||
|
||
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)
|
||
if r.Header.Get("Content-Type") == "application/json" {
|
||
logData["body"] = string(bodyBytes)
|
||
}
|
||
}
|
||
}
|
||
|
||
// Создаем responseWriter только для НЕ WebSocket запросов
|
||
rw := &responseWriter{ResponseWriter: w, status: http.StatusOK}
|
||
next.ServeHTTP(rw, r)
|
||
|
||
// Логирование только для НЕ WebSocket запросов
|
||
duration := time.Since(start)
|
||
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),
|
||
)
|
||
})
|
||
}
|
||
}
|
||
|
||
type responseWriter struct {
|
||
http.ResponseWriter
|
||
status int
|
||
size int
|
||
}
|
||
|
||
func (rw *responseWriter) WriteHeader(code int) {
|
||
if rw.status == 0 { // Защита от двойного вызова WriteHeader
|
||
rw.status = code
|
||
rw.ResponseWriter.WriteHeader(code)
|
||
}
|
||
}
|
||
|
||
func (rw *responseWriter) Write(b []byte) (int, error) {
|
||
if rw.status == 0 {
|
||
rw.WriteHeader(http.StatusOK)
|
||
}
|
||
size, err := rw.ResponseWriter.Write(b)
|
||
rw.size += size
|
||
return size, err
|
||
}
|
||
|
||
func (rw *responseWriter) Hijack() (net.Conn, *bufio.ReadWriter, error) {
|
||
if hijacker, ok := rw.ResponseWriter.(http.Hijacker); ok {
|
||
return hijacker.Hijack()
|
||
}
|
||
return nil, nil, errors.New("response writer does not support hijacking")
|
||
}
|