log_entry.go 2.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102
  1. package requestlog
  2. import (
  3. "errors"
  4. "io"
  5. "net"
  6. "net/http"
  7. "time"
  8. )
  9. type logEntry struct {
  10. ReceivedTime time.Time
  11. RequestMethod string
  12. RequestURL string
  13. RequestHeaderSize int64
  14. RequestBodySize int64
  15. UserAgent string
  16. Referer string
  17. Proto string
  18. Status int
  19. ResponseHeaderSize int64
  20. ResponseBodySize int64
  21. Latency time.Duration
  22. }
  23. func ipFromHostPort(hp string) string {
  24. h, _, err := net.SplitHostPort(hp)
  25. if err != nil {
  26. return ""
  27. }
  28. if len(h) > 0 && h[0] == '[' {
  29. return h[1 : len(h)-1]
  30. }
  31. return h
  32. }
  33. type readCounterCloser struct {
  34. r io.ReadCloser
  35. n int64
  36. err error
  37. }
  38. func (rcc *readCounterCloser) Read(p []byte) (n int, err error) {
  39. if rcc.err != nil {
  40. return 0, rcc.err
  41. }
  42. n, rcc.err = rcc.r.Read(p)
  43. rcc.n += int64(n)
  44. return n, rcc.err
  45. }
  46. func (rcc *readCounterCloser) Close() error {
  47. rcc.err = errors.New("read from closed reader")
  48. return rcc.r.Close()
  49. }
  50. type writeCounter int64
  51. func (wc *writeCounter) Write(p []byte) (n int, err error) {
  52. *wc += writeCounter(len(p))
  53. return len(p), nil
  54. }
  55. func headerSize(h http.Header) int64 {
  56. var wc writeCounter
  57. h.Write(&wc)
  58. return int64(wc) + 2 // for CRLF
  59. }
  60. type responseStats struct {
  61. w http.ResponseWriter
  62. hsize int64
  63. wc writeCounter
  64. code int
  65. }
  66. func (r *responseStats) Header() http.Header {
  67. return r.w.Header()
  68. }
  69. func (r *responseStats) WriteHeader(statusCode int) {
  70. if r.code != 0 {
  71. return
  72. }
  73. r.hsize = headerSize(r.w.Header())
  74. r.w.WriteHeader(statusCode)
  75. r.code = statusCode
  76. }
  77. func (r *responseStats) Write(p []byte) (n int, err error) {
  78. if r.code == 0 {
  79. r.WriteHeader(http.StatusOK)
  80. }
  81. n, err = r.w.Write(p)
  82. r.wc.Write(p[:n])
  83. return
  84. }
  85. func (r *responseStats) size() (hdr, body int64) {
  86. if r.code == 0 {
  87. return headerSize(r.w.Header()), 0
  88. }
  89. // Use the header size from the time WriteHeader was called.
  90. // The Header map can be mutated after the call to add HTTP Trailers,
  91. // which we don't want to count.
  92. return r.hsize, int64(r.wc)
  93. }