logger.go 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142
  1. // Copyright 2014 Manu Martinez-Almeida. All rights reserved.
  2. // Use of this source code is governed by a MIT style
  3. // license that can be found in the LICENSE file.
  4. package gin
  5. import (
  6. "fmt"
  7. "io"
  8. "os"
  9. "time"
  10. "github.com/mattn/go-isatty"
  11. )
  12. var (
  13. green = string([]byte{27, 91, 57, 55, 59, 52, 50, 109})
  14. white = string([]byte{27, 91, 57, 48, 59, 52, 55, 109})
  15. yellow = string([]byte{27, 91, 57, 55, 59, 52, 51, 109})
  16. red = string([]byte{27, 91, 57, 55, 59, 52, 49, 109})
  17. blue = string([]byte{27, 91, 57, 55, 59, 52, 52, 109})
  18. magenta = string([]byte{27, 91, 57, 55, 59, 52, 53, 109})
  19. cyan = string([]byte{27, 91, 57, 55, 59, 52, 54, 109})
  20. reset = string([]byte{27, 91, 48, 109})
  21. disableColor = false
  22. )
  23. func DisableConsoleColor() {
  24. disableColor = true
  25. }
  26. func ErrorLogger() HandlerFunc {
  27. return ErrorLoggerT(ErrorTypeAny)
  28. }
  29. func ErrorLoggerT(typ ErrorType) HandlerFunc {
  30. return func(c *Context) {
  31. c.Next()
  32. errors := c.Errors.ByType(typ)
  33. if len(errors) > 0 {
  34. c.JSON(-1, errors)
  35. }
  36. }
  37. }
  38. // Logger instances a Logger middleware that will write the logs to gin.DefaultWriter
  39. // By default gin.DefaultWriter = os.Stdout
  40. func Logger() HandlerFunc {
  41. return LoggerWithWriter(DefaultWriter)
  42. }
  43. // LoggerWithWriter instance a Logger middleware with the specified writter buffer.
  44. // Example: os.Stdout, a file opened in write mode, a socket...
  45. func LoggerWithWriter(out io.Writer, notlogged ...string) HandlerFunc {
  46. isTerm := true
  47. if w, ok := out.(*os.File); !ok ||
  48. (os.Getenv("TERM") == "dumb" || (!isatty.IsTerminal(w.Fd()) && !isatty.IsCygwinTerminal(w.Fd()))) ||
  49. disableColor {
  50. isTerm = false
  51. }
  52. var skip map[string]struct{}
  53. if length := len(notlogged); length > 0 {
  54. skip = make(map[string]struct{}, length)
  55. for _, path := range notlogged {
  56. skip[path] = struct{}{}
  57. }
  58. }
  59. return func(c *Context) {
  60. // Start timer
  61. start := time.Now()
  62. path := c.Request.URL.Path
  63. // Process request
  64. c.Next()
  65. // Log only when path is not being skipped
  66. if _, ok := skip[path]; !ok {
  67. // Stop timer
  68. end := time.Now()
  69. latency := end.Sub(start)
  70. clientIP := c.ClientIP()
  71. method := c.Request.Method
  72. statusCode := c.Writer.Status()
  73. var statusColor, methodColor string
  74. if isTerm {
  75. statusColor = colorForStatus(statusCode)
  76. methodColor = colorForMethod(method)
  77. }
  78. comment := c.Errors.ByType(ErrorTypePrivate).String()
  79. fmt.Fprintf(out, "[GIN] %v |%s %3d %s| %13v | %15s |%s %s %-7s %s\n%s",
  80. end.Format("2006/01/02 - 15:04:05"),
  81. statusColor, statusCode, reset,
  82. latency,
  83. clientIP,
  84. methodColor, method, reset,
  85. path,
  86. comment,
  87. )
  88. }
  89. }
  90. }
  91. func colorForStatus(code int) string {
  92. switch {
  93. case code >= 200 && code < 300:
  94. return green
  95. case code >= 300 && code < 400:
  96. return white
  97. case code >= 400 && code < 500:
  98. return yellow
  99. default:
  100. return red
  101. }
  102. }
  103. func colorForMethod(method string) string {
  104. switch method {
  105. case "GET":
  106. return blue
  107. case "POST":
  108. return cyan
  109. case "PUT":
  110. return yellow
  111. case "DELETE":
  112. return red
  113. case "PATCH":
  114. return green
  115. case "HEAD":
  116. return magenta
  117. case "OPTIONS":
  118. return white
  119. default:
  120. return reset
  121. }
  122. }