request_metrics.go 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201
  1. package middleware
  2. import (
  3. "net/http"
  4. "strconv"
  5. "strings"
  6. "time"
  7. "github.com/grafana/grafana/pkg/metrics"
  8. "gopkg.in/macaron.v1"
  9. )
  10. func RequestMetrics(handler string) macaron.Handler {
  11. return func(res http.ResponseWriter, req *http.Request, c *macaron.Context) {
  12. rw := res.(macaron.ResponseWriter)
  13. now := time.Now()
  14. c.Next()
  15. status := rw.Status()
  16. code := sanitizeCode(status)
  17. method := sanitizeMethod(req.Method)
  18. metrics.M_Http_Request_Total.WithLabelValues(handler, code, method).Inc()
  19. duration := time.Since(now).Nanoseconds() / int64(time.Millisecond)
  20. metrics.M_Http_Request_Summary.WithLabelValues(handler, code, method).Observe(float64(duration))
  21. if strings.HasPrefix(req.RequestURI, "/api/datasources/proxy") {
  22. countProxyRequests(status)
  23. } else if strings.HasPrefix(req.RequestURI, "/api/") {
  24. countApiRequests(status)
  25. } else {
  26. countPageRequests(status)
  27. }
  28. }
  29. }
  30. func countApiRequests(status int) {
  31. switch status {
  32. case 200:
  33. metrics.M_Api_Status.WithLabelValues("200").Inc()
  34. case 404:
  35. metrics.M_Api_Status.WithLabelValues("404").Inc()
  36. case 500:
  37. metrics.M_Api_Status.WithLabelValues("500").Inc()
  38. default:
  39. metrics.M_Api_Status.WithLabelValues("unknown").Inc()
  40. }
  41. }
  42. func countPageRequests(status int) {
  43. switch status {
  44. case 200:
  45. metrics.M_Page_Status.WithLabelValues("200").Inc()
  46. case 404:
  47. metrics.M_Page_Status.WithLabelValues("404").Inc()
  48. case 500:
  49. metrics.M_Page_Status.WithLabelValues("500").Inc()
  50. default:
  51. metrics.M_Page_Status.WithLabelValues("unknown").Inc()
  52. }
  53. }
  54. func countProxyRequests(status int) {
  55. switch status {
  56. case 200:
  57. metrics.M_Proxy_Status.WithLabelValues("200").Inc()
  58. case 404:
  59. metrics.M_Proxy_Status.WithLabelValues("400").Inc()
  60. case 500:
  61. metrics.M_Proxy_Status.WithLabelValues("500").Inc()
  62. default:
  63. metrics.M_Proxy_Status.WithLabelValues("unknown").Inc()
  64. }
  65. }
  66. func sanitizeMethod(m string) string {
  67. switch m {
  68. case "GET", "get":
  69. return "get"
  70. case "PUT", "put":
  71. return "put"
  72. case "HEAD", "head":
  73. return "head"
  74. case "POST", "post":
  75. return "post"
  76. case "DELETE", "delete":
  77. return "delete"
  78. case "CONNECT", "connect":
  79. return "connect"
  80. case "OPTIONS", "options":
  81. return "options"
  82. case "NOTIFY", "notify":
  83. return "notify"
  84. default:
  85. return strings.ToLower(m)
  86. }
  87. }
  88. // If the wrapped http.Handler has not set a status code, i.e. the value is
  89. // currently 0, santizeCode will return 200, for consistency with behavior in
  90. // the stdlib.
  91. func sanitizeCode(s int) string {
  92. switch s {
  93. case 100:
  94. return "100"
  95. case 101:
  96. return "101"
  97. case 200, 0:
  98. return "200"
  99. case 201:
  100. return "201"
  101. case 202:
  102. return "202"
  103. case 203:
  104. return "203"
  105. case 204:
  106. return "204"
  107. case 205:
  108. return "205"
  109. case 206:
  110. return "206"
  111. case 300:
  112. return "300"
  113. case 301:
  114. return "301"
  115. case 302:
  116. return "302"
  117. case 304:
  118. return "304"
  119. case 305:
  120. return "305"
  121. case 307:
  122. return "307"
  123. case 400:
  124. return "400"
  125. case 401:
  126. return "401"
  127. case 402:
  128. return "402"
  129. case 403:
  130. return "403"
  131. case 404:
  132. return "404"
  133. case 405:
  134. return "405"
  135. case 406:
  136. return "406"
  137. case 407:
  138. return "407"
  139. case 408:
  140. return "408"
  141. case 409:
  142. return "409"
  143. case 410:
  144. return "410"
  145. case 411:
  146. return "411"
  147. case 412:
  148. return "412"
  149. case 413:
  150. return "413"
  151. case 414:
  152. return "414"
  153. case 415:
  154. return "415"
  155. case 416:
  156. return "416"
  157. case 417:
  158. return "417"
  159. case 418:
  160. return "418"
  161. case 500:
  162. return "500"
  163. case 501:
  164. return "501"
  165. case 502:
  166. return "502"
  167. case 503:
  168. return "503"
  169. case 504:
  170. return "504"
  171. case 505:
  172. return "505"
  173. case 428:
  174. return "428"
  175. case 429:
  176. return "429"
  177. case 431:
  178. return "431"
  179. case 511:
  180. return "511"
  181. default:
  182. return strconv.Itoa(s)
  183. }
  184. }