logger.go 1.8 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192
  1. package middleware
  2. import (
  3. "fmt"
  4. "log/slog"
  5. "net/http"
  6. "strings"
  7. "time"
  8. "github.com/ncarlier/webhookd/pkg/logger"
  9. )
  10. type key int
  11. const (
  12. requestIDKey key = 0
  13. )
  14. // Logger is a middleware to log HTTP request
  15. func Logger(next http.Handler) http.Handler {
  16. return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
  17. o := &responseObserver{ResponseWriter: w}
  18. start := time.Now()
  19. defer func() {
  20. requestID, ok := r.Context().Value(requestIDKey).(string)
  21. if !ok {
  22. requestID = "0"
  23. }
  24. logger.LogIf(
  25. logger.RequestOutputEnabled,
  26. slog.LevelInfo+1,
  27. fmt.Sprintf("%s %s %s", r.Method, r.URL, r.Proto),
  28. "ip", getRequestIP(r),
  29. "time", start.Format("02/Jan/2006:15:04:05 -0700"),
  30. "duration", time.Since(start).Milliseconds(),
  31. "status", o.status,
  32. "bytes", o.written,
  33. "referer", r.Referer(),
  34. "ua", r.UserAgent(),
  35. "reqid", requestID,
  36. )
  37. }()
  38. next.ServeHTTP(o, r)
  39. })
  40. }
  41. func getRequestIP(r *http.Request) string {
  42. ip := r.Header.Get("X-Forwarded-For")
  43. if ip == "" {
  44. ip = r.RemoteAddr
  45. }
  46. if comma := strings.Index(ip, ","); comma != -1 {
  47. ip = ip[0:comma]
  48. }
  49. if colon := strings.LastIndex(ip, ":"); colon != -1 {
  50. ip = ip[:colon]
  51. }
  52. return ip
  53. }
  54. type responseObserver struct {
  55. http.ResponseWriter
  56. status int
  57. written int64
  58. wroteHeader bool
  59. }
  60. func (o *responseObserver) Write(p []byte) (n int, err error) {
  61. if !o.wroteHeader {
  62. o.WriteHeader(http.StatusOK)
  63. }
  64. n, err = o.ResponseWriter.Write(p)
  65. o.written += int64(n)
  66. return
  67. }
  68. func (o *responseObserver) WriteHeader(code int) {
  69. o.ResponseWriter.WriteHeader(code)
  70. if o.wroteHeader {
  71. return
  72. }
  73. o.wroteHeader = true
  74. o.status = code
  75. }
  76. func (o *responseObserver) Flush() {
  77. flusher, ok := o.ResponseWriter.(http.Flusher)
  78. if ok {
  79. flusher.Flush()
  80. }
  81. }