logger_test.go 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434
  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. "bytes"
  7. "errors"
  8. "fmt"
  9. "net/http"
  10. "testing"
  11. "time"
  12. "github.com/stretchr/testify/assert"
  13. )
  14. func init() {
  15. SetMode(TestMode)
  16. }
  17. func TestLogger(t *testing.T) {
  18. buffer := new(bytes.Buffer)
  19. router := New()
  20. router.Use(LoggerWithWriter(buffer))
  21. router.GET("/example", func(c *Context) {})
  22. router.POST("/example", func(c *Context) {})
  23. router.PUT("/example", func(c *Context) {})
  24. router.DELETE("/example", func(c *Context) {})
  25. router.PATCH("/example", func(c *Context) {})
  26. router.HEAD("/example", func(c *Context) {})
  27. router.OPTIONS("/example", func(c *Context) {})
  28. performRequest(router, "GET", "/example?a=100")
  29. assert.Contains(t, buffer.String(), "200")
  30. assert.Contains(t, buffer.String(), "GET")
  31. assert.Contains(t, buffer.String(), "/example")
  32. assert.Contains(t, buffer.String(), "a=100")
  33. // I wrote these first (extending the above) but then realized they are more
  34. // like integration tests because they test the whole logging process rather
  35. // than individual functions. Im not sure where these should go.
  36. buffer.Reset()
  37. performRequest(router, "POST", "/example")
  38. assert.Contains(t, buffer.String(), "200")
  39. assert.Contains(t, buffer.String(), "POST")
  40. assert.Contains(t, buffer.String(), "/example")
  41. buffer.Reset()
  42. performRequest(router, "PUT", "/example")
  43. assert.Contains(t, buffer.String(), "200")
  44. assert.Contains(t, buffer.String(), "PUT")
  45. assert.Contains(t, buffer.String(), "/example")
  46. buffer.Reset()
  47. performRequest(router, "DELETE", "/example")
  48. assert.Contains(t, buffer.String(), "200")
  49. assert.Contains(t, buffer.String(), "DELETE")
  50. assert.Contains(t, buffer.String(), "/example")
  51. buffer.Reset()
  52. performRequest(router, "PATCH", "/example")
  53. assert.Contains(t, buffer.String(), "200")
  54. assert.Contains(t, buffer.String(), "PATCH")
  55. assert.Contains(t, buffer.String(), "/example")
  56. buffer.Reset()
  57. performRequest(router, "HEAD", "/example")
  58. assert.Contains(t, buffer.String(), "200")
  59. assert.Contains(t, buffer.String(), "HEAD")
  60. assert.Contains(t, buffer.String(), "/example")
  61. buffer.Reset()
  62. performRequest(router, "OPTIONS", "/example")
  63. assert.Contains(t, buffer.String(), "200")
  64. assert.Contains(t, buffer.String(), "OPTIONS")
  65. assert.Contains(t, buffer.String(), "/example")
  66. buffer.Reset()
  67. performRequest(router, "GET", "/notfound")
  68. assert.Contains(t, buffer.String(), "404")
  69. assert.Contains(t, buffer.String(), "GET")
  70. assert.Contains(t, buffer.String(), "/notfound")
  71. }
  72. func TestLoggerWithConfig(t *testing.T) {
  73. buffer := new(bytes.Buffer)
  74. router := New()
  75. router.Use(LoggerWithConfig(LoggerConfig{Output: buffer}))
  76. router.GET("/example", func(c *Context) {})
  77. router.POST("/example", func(c *Context) {})
  78. router.PUT("/example", func(c *Context) {})
  79. router.DELETE("/example", func(c *Context) {})
  80. router.PATCH("/example", func(c *Context) {})
  81. router.HEAD("/example", func(c *Context) {})
  82. router.OPTIONS("/example", func(c *Context) {})
  83. performRequest(router, "GET", "/example?a=100")
  84. assert.Contains(t, buffer.String(), "200")
  85. assert.Contains(t, buffer.String(), "GET")
  86. assert.Contains(t, buffer.String(), "/example")
  87. assert.Contains(t, buffer.String(), "a=100")
  88. // I wrote these first (extending the above) but then realized they are more
  89. // like integration tests because they test the whole logging process rather
  90. // than individual functions. Im not sure where these should go.
  91. buffer.Reset()
  92. performRequest(router, "POST", "/example")
  93. assert.Contains(t, buffer.String(), "200")
  94. assert.Contains(t, buffer.String(), "POST")
  95. assert.Contains(t, buffer.String(), "/example")
  96. buffer.Reset()
  97. performRequest(router, "PUT", "/example")
  98. assert.Contains(t, buffer.String(), "200")
  99. assert.Contains(t, buffer.String(), "PUT")
  100. assert.Contains(t, buffer.String(), "/example")
  101. buffer.Reset()
  102. performRequest(router, "DELETE", "/example")
  103. assert.Contains(t, buffer.String(), "200")
  104. assert.Contains(t, buffer.String(), "DELETE")
  105. assert.Contains(t, buffer.String(), "/example")
  106. buffer.Reset()
  107. performRequest(router, "PATCH", "/example")
  108. assert.Contains(t, buffer.String(), "200")
  109. assert.Contains(t, buffer.String(), "PATCH")
  110. assert.Contains(t, buffer.String(), "/example")
  111. buffer.Reset()
  112. performRequest(router, "HEAD", "/example")
  113. assert.Contains(t, buffer.String(), "200")
  114. assert.Contains(t, buffer.String(), "HEAD")
  115. assert.Contains(t, buffer.String(), "/example")
  116. buffer.Reset()
  117. performRequest(router, "OPTIONS", "/example")
  118. assert.Contains(t, buffer.String(), "200")
  119. assert.Contains(t, buffer.String(), "OPTIONS")
  120. assert.Contains(t, buffer.String(), "/example")
  121. buffer.Reset()
  122. performRequest(router, "GET", "/notfound")
  123. assert.Contains(t, buffer.String(), "404")
  124. assert.Contains(t, buffer.String(), "GET")
  125. assert.Contains(t, buffer.String(), "/notfound")
  126. }
  127. func TestLoggerWithFormatter(t *testing.T) {
  128. buffer := new(bytes.Buffer)
  129. d := DefaultWriter
  130. DefaultWriter = buffer
  131. defer func() {
  132. DefaultWriter = d
  133. }()
  134. router := New()
  135. router.Use(LoggerWithFormatter(func(param LogFormatterParams) string {
  136. return fmt.Sprintf("[FORMATTER TEST] %v | %3d | %13v | %15s | %-7s %s\n%s",
  137. param.TimeStamp.Format("2006/01/02 - 15:04:05"),
  138. param.StatusCode,
  139. param.Latency,
  140. param.ClientIP,
  141. param.Method,
  142. param.Path,
  143. param.ErrorMessage,
  144. )
  145. }))
  146. router.GET("/example", func(c *Context) {})
  147. performRequest(router, "GET", "/example?a=100")
  148. // output test
  149. assert.Contains(t, buffer.String(), "[FORMATTER TEST]")
  150. assert.Contains(t, buffer.String(), "200")
  151. assert.Contains(t, buffer.String(), "GET")
  152. assert.Contains(t, buffer.String(), "/example")
  153. assert.Contains(t, buffer.String(), "a=100")
  154. }
  155. func TestLoggerWithConfigFormatting(t *testing.T) {
  156. var gotParam LogFormatterParams
  157. var gotKeys map[string]interface{}
  158. buffer := new(bytes.Buffer)
  159. router := New()
  160. router.Use(LoggerWithConfig(LoggerConfig{
  161. Output: buffer,
  162. Formatter: func(param LogFormatterParams) string {
  163. // for assert test
  164. gotParam = param
  165. return fmt.Sprintf("[FORMATTER TEST] %v | %3d | %13v | %15s | %-7s %s\n%s",
  166. param.TimeStamp.Format("2006/01/02 - 15:04:05"),
  167. param.StatusCode,
  168. param.Latency,
  169. param.ClientIP,
  170. param.Method,
  171. param.Path,
  172. param.ErrorMessage,
  173. )
  174. },
  175. }))
  176. router.GET("/example", func(c *Context) {
  177. // set dummy ClientIP
  178. c.Request.Header.Set("X-Forwarded-For", "20.20.20.20")
  179. gotKeys = c.Keys
  180. })
  181. performRequest(router, "GET", "/example?a=100")
  182. // output test
  183. assert.Contains(t, buffer.String(), "[FORMATTER TEST]")
  184. assert.Contains(t, buffer.String(), "200")
  185. assert.Contains(t, buffer.String(), "GET")
  186. assert.Contains(t, buffer.String(), "/example")
  187. assert.Contains(t, buffer.String(), "a=100")
  188. // LogFormatterParams test
  189. assert.NotNil(t, gotParam.Request)
  190. assert.NotEmpty(t, gotParam.TimeStamp)
  191. assert.Equal(t, 200, gotParam.StatusCode)
  192. assert.NotEmpty(t, gotParam.Latency)
  193. assert.Equal(t, "20.20.20.20", gotParam.ClientIP)
  194. assert.Equal(t, "GET", gotParam.Method)
  195. assert.Equal(t, "/example?a=100", gotParam.Path)
  196. assert.Empty(t, gotParam.ErrorMessage)
  197. assert.Equal(t, gotKeys, gotParam.Keys)
  198. }
  199. func TestDefaultLogFormatter(t *testing.T) {
  200. timeStamp := time.Unix(1544173902, 0).UTC()
  201. termFalseParam := LogFormatterParams{
  202. TimeStamp: timeStamp,
  203. StatusCode: 200,
  204. Latency: time.Second * 5,
  205. ClientIP: "20.20.20.20",
  206. Method: "GET",
  207. Path: "/",
  208. ErrorMessage: "",
  209. isTerm: false,
  210. }
  211. termTrueParam := LogFormatterParams{
  212. TimeStamp: timeStamp,
  213. StatusCode: 200,
  214. Latency: time.Second * 5,
  215. ClientIP: "20.20.20.20",
  216. Method: "GET",
  217. Path: "/",
  218. ErrorMessage: "",
  219. isTerm: true,
  220. }
  221. termTrueLongDurationParam := LogFormatterParams{
  222. TimeStamp: timeStamp,
  223. StatusCode: 200,
  224. Latency: time.Millisecond * 9876543210,
  225. ClientIP: "20.20.20.20",
  226. Method: "GET",
  227. Path: "/",
  228. ErrorMessage: "",
  229. isTerm: true,
  230. }
  231. termFalseLongDurationParam := LogFormatterParams{
  232. TimeStamp: timeStamp,
  233. StatusCode: 200,
  234. Latency: time.Millisecond * 9876543210,
  235. ClientIP: "20.20.20.20",
  236. Method: "GET",
  237. Path: "/",
  238. ErrorMessage: "",
  239. isTerm: false,
  240. }
  241. assert.Equal(t, "[GIN] 2018/12/07 - 09:11:42 | 200 | 5s | 20.20.20.20 | GET /\n", defaultLogFormatter(termFalseParam))
  242. assert.Equal(t, "[GIN] 2018/12/07 - 09:11:42 | 200 | 2743h29m3s | 20.20.20.20 | GET /\n", defaultLogFormatter(termFalseLongDurationParam))
  243. assert.Equal(t, "[GIN] 2018/12/07 - 09:11:42 |\x1b[97;42m 200 \x1b[0m| 5s | 20.20.20.20 |\x1b[97;44m GET \x1b[0m /\n", defaultLogFormatter(termTrueParam))
  244. assert.Equal(t, "[GIN] 2018/12/07 - 09:11:42 |\x1b[97;42m 200 \x1b[0m| 2743h29m3s | 20.20.20.20 |\x1b[97;44m GET \x1b[0m /\n", defaultLogFormatter(termTrueLongDurationParam))
  245. }
  246. func TestColorForMethod(t *testing.T) {
  247. colorForMethod := func(method string) string {
  248. p := LogFormatterParams{
  249. Method: method,
  250. }
  251. return p.MethodColor()
  252. }
  253. assert.Equal(t, blue, colorForMethod("GET"), "get should be blue")
  254. assert.Equal(t, cyan, colorForMethod("POST"), "post should be cyan")
  255. assert.Equal(t, yellow, colorForMethod("PUT"), "put should be yellow")
  256. assert.Equal(t, red, colorForMethod("DELETE"), "delete should be red")
  257. assert.Equal(t, green, colorForMethod("PATCH"), "patch should be green")
  258. assert.Equal(t, magenta, colorForMethod("HEAD"), "head should be magenta")
  259. assert.Equal(t, white, colorForMethod("OPTIONS"), "options should be white")
  260. assert.Equal(t, reset, colorForMethod("TRACE"), "trace is not defined and should be the reset color")
  261. }
  262. func TestColorForStatus(t *testing.T) {
  263. colorForStatus := func(code int) string {
  264. p := LogFormatterParams{
  265. StatusCode: code,
  266. }
  267. return p.StatusCodeColor()
  268. }
  269. assert.Equal(t, green, colorForStatus(http.StatusOK), "2xx should be green")
  270. assert.Equal(t, white, colorForStatus(http.StatusMovedPermanently), "3xx should be white")
  271. assert.Equal(t, yellow, colorForStatus(http.StatusNotFound), "4xx should be yellow")
  272. assert.Equal(t, red, colorForStatus(2), "other things should be red")
  273. }
  274. func TestResetColor(t *testing.T) {
  275. p := LogFormatterParams{}
  276. assert.Equal(t, string([]byte{27, 91, 48, 109}), p.ResetColor())
  277. }
  278. func TestIsOutputColor(t *testing.T) {
  279. // test with isTerm flag true.
  280. p := LogFormatterParams{
  281. isTerm: true,
  282. }
  283. consoleColorMode = autoColor
  284. assert.Equal(t, true, p.IsOutputColor())
  285. ForceConsoleColor()
  286. assert.Equal(t, true, p.IsOutputColor())
  287. DisableConsoleColor()
  288. assert.Equal(t, false, p.IsOutputColor())
  289. // test with isTerm flag false.
  290. p = LogFormatterParams{
  291. isTerm: false,
  292. }
  293. consoleColorMode = autoColor
  294. assert.Equal(t, false, p.IsOutputColor())
  295. ForceConsoleColor()
  296. assert.Equal(t, true, p.IsOutputColor())
  297. DisableConsoleColor()
  298. assert.Equal(t, false, p.IsOutputColor())
  299. // reset console color mode.
  300. consoleColorMode = autoColor
  301. }
  302. func TestErrorLogger(t *testing.T) {
  303. router := New()
  304. router.Use(ErrorLogger())
  305. router.GET("/error", func(c *Context) {
  306. c.Error(errors.New("this is an error")) // nolint: errcheck
  307. })
  308. router.GET("/abort", func(c *Context) {
  309. c.AbortWithError(http.StatusUnauthorized, errors.New("no authorized")) // nolint: errcheck
  310. })
  311. router.GET("/print", func(c *Context) {
  312. c.Error(errors.New("this is an error")) // nolint: errcheck
  313. c.String(http.StatusInternalServerError, "hola!")
  314. })
  315. w := performRequest(router, "GET", "/error")
  316. assert.Equal(t, http.StatusOK, w.Code)
  317. assert.Equal(t, "{\"error\":\"this is an error\"}\n", w.Body.String())
  318. w = performRequest(router, "GET", "/abort")
  319. assert.Equal(t, http.StatusUnauthorized, w.Code)
  320. assert.Equal(t, "{\"error\":\"no authorized\"}\n", w.Body.String())
  321. w = performRequest(router, "GET", "/print")
  322. assert.Equal(t, http.StatusInternalServerError, w.Code)
  323. assert.Equal(t, "hola!{\"error\":\"this is an error\"}\n", w.Body.String())
  324. }
  325. func TestLoggerWithWriterSkippingPaths(t *testing.T) {
  326. buffer := new(bytes.Buffer)
  327. router := New()
  328. router.Use(LoggerWithWriter(buffer, "/skipped"))
  329. router.GET("/logged", func(c *Context) {})
  330. router.GET("/skipped", func(c *Context) {})
  331. performRequest(router, "GET", "/logged")
  332. assert.Contains(t, buffer.String(), "200")
  333. buffer.Reset()
  334. performRequest(router, "GET", "/skipped")
  335. assert.Contains(t, buffer.String(), "")
  336. }
  337. func TestLoggerWithConfigSkippingPaths(t *testing.T) {
  338. buffer := new(bytes.Buffer)
  339. router := New()
  340. router.Use(LoggerWithConfig(LoggerConfig{
  341. Output: buffer,
  342. SkipPaths: []string{"/skipped"},
  343. }))
  344. router.GET("/logged", func(c *Context) {})
  345. router.GET("/skipped", func(c *Context) {})
  346. performRequest(router, "GET", "/logged")
  347. assert.Contains(t, buffer.String(), "200")
  348. buffer.Reset()
  349. performRequest(router, "GET", "/skipped")
  350. assert.Contains(t, buffer.String(), "")
  351. }
  352. func TestDisableConsoleColor(t *testing.T) {
  353. New()
  354. assert.Equal(t, autoColor, consoleColorMode)
  355. DisableConsoleColor()
  356. assert.Equal(t, disableColor, consoleColorMode)
  357. // reset console color mode.
  358. consoleColorMode = autoColor
  359. }
  360. func TestForceConsoleColor(t *testing.T) {
  361. New()
  362. assert.Equal(t, autoColor, consoleColorMode)
  363. ForceConsoleColor()
  364. assert.Equal(t, forceColor, consoleColorMode)
  365. // reset console color mode.
  366. consoleColorMode = autoColor
  367. }