access.go 3.3 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798
  1. package engine
  2. import (
  3. "fmt"
  4. "net"
  5. "net/http"
  6. "os"
  7. "strconv"
  8. "strings"
  9. "time"
  10. log "github.com/sirupsen/logrus"
  11. )
  12. // CommonLogFormat returns a line with the data that is available at the start
  13. // of a request handler. The log line is in NCSA format, the same log format
  14. // used by Apache. Fields where data is not available are indicated by a "-".
  15. // See also: https://en.wikipedia.org/wiki/Common_Log_Format
  16. func (ac *Config) CommonLogFormat(req *http.Request, statusCode int, byteSize int64) string {
  17. username := "-"
  18. if ac.perm != nil {
  19. username = ac.perm.UserState().Username(req)
  20. }
  21. host, _, err := net.SplitHostPort(req.RemoteAddr)
  22. ip := host
  23. if err != nil {
  24. ip = req.RemoteAddr
  25. }
  26. statusCodeString := "-"
  27. if statusCode > 0 {
  28. statusCodeString = strconv.Itoa(statusCode)
  29. }
  30. byteSizeString := "0"
  31. if byteSize > 0 {
  32. byteSizeString = fmt.Sprintf("%d", byteSize)
  33. }
  34. timestamp := strings.Replace(time.Now().Format("02/Jan/2006 15:04:05 -0700"), " ", ":", 1)
  35. return fmt.Sprintf("%s - %s [%s] \"%s %s %s\" %s %s", ip, username, timestamp, req.Method, req.RequestURI, req.Proto, statusCodeString, byteSizeString)
  36. }
  37. // CombinedLogFormat returns a line with the data that is available at the start
  38. // of a request handler. The log line is in CLF, similar to the Common log format,
  39. // but with two extra fields.
  40. // See also: https://httpd.apache.org/docs/1.3/logs.html#combined
  41. func (ac *Config) CombinedLogFormat(req *http.Request, statusCode int, byteSize int64) string {
  42. username := "-"
  43. if ac.perm != nil {
  44. username = ac.perm.UserState().Username(req)
  45. }
  46. host, _, err := net.SplitHostPort(req.RemoteAddr)
  47. ip := host
  48. if err != nil {
  49. ip = req.RemoteAddr
  50. }
  51. statusCodeString := "-"
  52. if statusCode > 0 {
  53. statusCodeString = strconv.Itoa(statusCode)
  54. }
  55. byteSizeString := "0"
  56. if byteSize > 0 {
  57. byteSizeString = fmt.Sprintf("%d", byteSize)
  58. }
  59. timestamp := strings.Replace(time.Now().Format("02/Jan/2006 15:04:05 -0700"), " ", ":", 1)
  60. referer := req.Header.Get("Referer")
  61. userAgent := req.Header.Get("User-Agent")
  62. return fmt.Sprintf("%s - %s [%s] \"%s %s %s\" %s %s \"%s\" \"%s\"", ip, username, timestamp, req.Method, req.RequestURI, req.Proto, statusCodeString, byteSizeString, referer, userAgent)
  63. }
  64. // LogAccess creates one entry in the access log, given a http.Request,
  65. // a HTTP status code and the amount of bytes that have been transferred.
  66. func (ac *Config) LogAccess(req *http.Request, statusCode int, byteSize int64) {
  67. if ac.commonAccessLogFilename != "" {
  68. f, err := os.OpenFile(ac.commonAccessLogFilename, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0o644)
  69. if err != nil {
  70. log.Warnf("Can not open %s: %s", ac.commonAccessLogFilename, err)
  71. return
  72. }
  73. defer f.Close()
  74. _, err = f.WriteString(ac.CommonLogFormat(req, statusCode, byteSize) + "\n")
  75. if err != nil {
  76. log.Warnf("Can not write to %s: %s", ac.commonAccessLogFilename, err)
  77. return
  78. }
  79. }
  80. if ac.combinedAccessLogFilename != "" {
  81. f, err := os.OpenFile(ac.combinedAccessLogFilename, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0o644)
  82. if err != nil {
  83. log.Warnf("Can not open %s: %s", ac.combinedAccessLogFilename, err)
  84. return
  85. }
  86. defer f.Close()
  87. _, err = f.WriteString(ac.CombinedLogFormat(req, statusCode, byteSize) + "\n")
  88. if err != nil {
  89. log.Warnf("Can not write to %s: %s", ac.combinedAccessLogFilename, err)
  90. return
  91. }
  92. }
  93. }