logger.go 3.1 KB

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