log.go 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122
  1. package server
  2. import (
  3. "fmt"
  4. "github.com/emersion/go-smtp"
  5. "github.com/gorilla/websocket"
  6. "heckel.io/ntfy/log"
  7. "heckel.io/ntfy/util"
  8. "net/http"
  9. "strings"
  10. "unicode/utf8"
  11. )
  12. // Log tags
  13. const (
  14. tagStartup = "startup"
  15. tagHTTP = "http"
  16. tagPublish = "publish"
  17. tagSubscribe = "subscribe"
  18. tagFirebase = "firebase"
  19. tagSMTP = "smtp" // Receive email
  20. tagEmail = "email" // Send email
  21. tagFileCache = "file_cache"
  22. tagMessageCache = "message_cache"
  23. tagStripe = "stripe"
  24. tagAccount = "account"
  25. tagManager = "manager"
  26. tagResetter = "resetter"
  27. tagWebsocket = "websocket"
  28. tagMatrix = "matrix"
  29. )
  30. var (
  31. normalErrorCodes = []int{http.StatusNotFound, http.StatusBadRequest, http.StatusTooManyRequests, http.StatusUnauthorized, http.StatusInsufficientStorage}
  32. )
  33. // logr creates a new log event with HTTP request fields
  34. func logr(r *http.Request) *log.Event {
  35. return log.Tag(tagHTTP).Fields(httpContext(r)) // Tag may be overwritten
  36. }
  37. // logv creates a new log event with visitor fields
  38. func logv(v *visitor) *log.Event {
  39. return log.With(v)
  40. }
  41. // logvr creates a new log event with HTTP request and visitor fields
  42. func logvr(v *visitor, r *http.Request) *log.Event {
  43. return logr(r).With(v)
  44. }
  45. // logvrm creates a new log event with HTTP request, visitor fields and message fields
  46. func logvrm(v *visitor, r *http.Request, m *message) *log.Event {
  47. return logvr(v, r).With(m)
  48. }
  49. // logvrm creates a new log event with visitor fields and message fields
  50. func logvm(v *visitor, m *message) *log.Event {
  51. return logv(v).With(m)
  52. }
  53. // logem creates a new log event with email fields
  54. func logem(smtpConn *smtp.Conn) *log.Event {
  55. ev := log.Tag(tagSMTP).Field("smtp_hostname", smtpConn.Hostname())
  56. if smtpConn.Conn() != nil {
  57. ev.Field("smtp_remote_addr", smtpConn.Conn().RemoteAddr().String())
  58. }
  59. return ev
  60. }
  61. func httpContext(r *http.Request) log.Context {
  62. requestURI := r.RequestURI
  63. if requestURI == "" {
  64. requestURI = r.URL.Path
  65. }
  66. return log.Context{
  67. "http_method": r.Method,
  68. "http_path": requestURI,
  69. }
  70. }
  71. func websocketErrorContext(err error) log.Context {
  72. if c, ok := err.(*websocket.CloseError); ok {
  73. return log.Context{
  74. "error": c.Error(),
  75. "error_code": c.Code,
  76. "error_type": "websocket.CloseError",
  77. }
  78. }
  79. return log.Context{
  80. "error": err.Error(),
  81. }
  82. }
  83. func renderHTTPRequest(r *http.Request) string {
  84. peekLimit := 4096
  85. lines := fmt.Sprintf("%s %s %s\n", r.Method, r.URL.RequestURI(), r.Proto)
  86. for key, values := range r.Header {
  87. for _, value := range values {
  88. lines += fmt.Sprintf("%s: %s\n", key, value)
  89. }
  90. }
  91. lines += "\n"
  92. body, err := util.Peek(r.Body, peekLimit)
  93. if err != nil {
  94. lines = fmt.Sprintf("(could not read body: %s)\n", err.Error())
  95. } else if utf8.Valid(body.PeekedBytes) {
  96. lines += string(body.PeekedBytes)
  97. if body.LimitReached {
  98. lines += fmt.Sprintf(" ... (peeked %d bytes)", peekLimit)
  99. }
  100. lines += "\n"
  101. } else {
  102. if body.LimitReached {
  103. lines += fmt.Sprintf("(peeked bytes not UTF-8, peek limit of %d bytes reached, hex: %x ...)\n", peekLimit, body.PeekedBytes)
  104. } else {
  105. lines += fmt.Sprintf("(peeked bytes not UTF-8, %d bytes, hex: %x)\n", len(body.PeekedBytes), body.PeekedBytes)
  106. }
  107. }
  108. r.Body = body // Important: Reset body, so it can be re-read
  109. return strings.TrimSpace(lines)
  110. }