logger.go 2.9 KB

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