logger_test.go 14 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, string([]byte{27, 91, 57, 55, 59, 52, 52, 109}), colorForMethod("GET"), "get should be blue")
  254. assert.Equal(t, string([]byte{27, 91, 57, 55, 59, 52, 54, 109}), colorForMethod("POST"), "post should be cyan")
  255. assert.Equal(t, string([]byte{27, 91, 57, 48, 59, 52, 51, 109}), colorForMethod("PUT"), "put should be yellow")
  256. assert.Equal(t, string([]byte{27, 91, 57, 55, 59, 52, 49, 109}), colorForMethod("DELETE"), "delete should be red")
  257. assert.Equal(t, string([]byte{27, 91, 57, 55, 59, 52, 50, 109}), colorForMethod("PATCH"), "patch should be green")
  258. assert.Equal(t, string([]byte{27, 91, 57, 55, 59, 52, 53, 109}), colorForMethod("HEAD"), "head should be magenta")
  259. assert.Equal(t, string([]byte{27, 91, 57, 48, 59, 52, 55, 109}), colorForMethod("OPTIONS"), "options should be white")
  260. assert.Equal(t, string([]byte{27, 91, 48, 109}), 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, string([]byte{27, 91, 57, 55, 59, 52, 50, 109}), colorForStatus(http.StatusOK), "2xx should be green")
  270. assert.Equal(t, string([]byte{27, 91, 57, 48, 59, 52, 55, 109}), colorForStatus(http.StatusMovedPermanently), "3xx should be white")
  271. assert.Equal(t, string([]byte{27, 91, 57, 48, 59, 52, 51, 109}), colorForStatus(http.StatusNotFound), "4xx should be yellow")
  272. assert.Equal(t, string([]byte{27, 91, 57, 55, 59, 52, 49, 109}), 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. }