log.go 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118
  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. // logr creates a new log event with HTTP request fields
  31. func logr(r *http.Request) *log.Event {
  32. return log.Tag(tagHTTP).Fields(httpContext(r)) // Tag may be overwritten
  33. }
  34. // logv creates a new log event with visitor fields
  35. func logv(v *visitor) *log.Event {
  36. return log.With(v)
  37. }
  38. // logvr creates a new log event with HTTP request and visitor fields
  39. func logvr(v *visitor, r *http.Request) *log.Event {
  40. return logr(r).With(v)
  41. }
  42. // logvrm creates a new log event with HTTP request, visitor fields and message fields
  43. func logvrm(v *visitor, r *http.Request, m *message) *log.Event {
  44. return logvr(v, r).With(m)
  45. }
  46. // logvrm creates a new log event with visitor fields and message fields
  47. func logvm(v *visitor, m *message) *log.Event {
  48. return logv(v).With(m)
  49. }
  50. // logem creates a new log event with email fields
  51. func logem(smtpConn *smtp.Conn) *log.Event {
  52. ev := log.Tag(tagSMTP).Field("smtp_hostname", smtpConn.Hostname())
  53. if smtpConn.Conn() != nil {
  54. ev.Field("smtp_remote_addr", smtpConn.Conn().RemoteAddr().String())
  55. }
  56. return ev
  57. }
  58. func httpContext(r *http.Request) log.Context {
  59. requestURI := r.RequestURI
  60. if requestURI == "" {
  61. requestURI = r.URL.Path
  62. }
  63. return log.Context{
  64. "http_method": r.Method,
  65. "http_path": requestURI,
  66. }
  67. }
  68. func websocketErrorContext(err error) log.Context {
  69. if c, ok := err.(*websocket.CloseError); ok {
  70. return log.Context{
  71. "error": c.Error(),
  72. "error_code": c.Code,
  73. "error_type": "websocket.CloseError",
  74. }
  75. }
  76. return log.Context{
  77. "error": err.Error(),
  78. }
  79. }
  80. func renderHTTPRequest(r *http.Request) string {
  81. peekLimit := 4096
  82. lines := fmt.Sprintf("%s %s %s\n", r.Method, r.URL.RequestURI(), r.Proto)
  83. for key, values := range r.Header {
  84. for _, value := range values {
  85. lines += fmt.Sprintf("%s: %s\n", key, value)
  86. }
  87. }
  88. lines += "\n"
  89. body, err := util.Peek(r.Body, peekLimit)
  90. if err != nil {
  91. lines = fmt.Sprintf("(could not read body: %s)\n", err.Error())
  92. } else if utf8.Valid(body.PeekedBytes) {
  93. lines += string(body.PeekedBytes)
  94. if body.LimitReached {
  95. lines += fmt.Sprintf(" ... (peeked %d bytes)", peekLimit)
  96. }
  97. lines += "\n"
  98. } else {
  99. if body.LimitReached {
  100. lines += fmt.Sprintf("(peeked bytes not UTF-8, peek limit of %d bytes reached, hex: %x ...)\n", peekLimit, body.PeekedBytes)
  101. } else {
  102. lines += fmt.Sprintf("(peeked bytes not UTF-8, %d bytes, hex: %x)\n", len(body.PeekedBytes), body.PeekedBytes)
  103. }
  104. }
  105. r.Body = body // Important: Reset body, so it can be re-read
  106. return strings.TrimSpace(lines)
  107. }