metrics.go 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899
  1. // Copyright 2015 The etcd Authors
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. //
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. package v2http
  15. import (
  16. "strconv"
  17. "time"
  18. "net/http"
  19. "go.etcd.io/etcd/etcdserver/api/v2error"
  20. "go.etcd.io/etcd/etcdserver/api/v2http/httptypes"
  21. "go.etcd.io/etcd/etcdserver/etcdserverpb"
  22. "github.com/prometheus/client_golang/prometheus"
  23. )
  24. var (
  25. incomingEvents = prometheus.NewCounterVec(
  26. prometheus.CounterOpts{
  27. Namespace: "etcd",
  28. Subsystem: "http",
  29. Name: "received_total",
  30. Help: "Counter of requests received into the system (successfully parsed and authd).",
  31. }, []string{"method"})
  32. failedEvents = prometheus.NewCounterVec(
  33. prometheus.CounterOpts{
  34. Namespace: "etcd",
  35. Subsystem: "http",
  36. Name: "failed_total",
  37. Help: "Counter of handle failures of requests (non-watches), by method (GET/PUT etc.) and code (400, 500 etc.).",
  38. }, []string{"method", "code"})
  39. successfulEventsHandlingSec = prometheus.NewHistogramVec(
  40. prometheus.HistogramOpts{
  41. Namespace: "etcd",
  42. Subsystem: "http",
  43. Name: "successful_duration_seconds",
  44. Help: "Bucketed histogram of processing time (s) of successfully handled requests (non-watches), by method (GET/PUT etc.).",
  45. // lowest bucket start of upper bound 0.0005 sec (0.5 ms) with factor 2
  46. // highest bucket start of 0.0005 sec * 2^12 == 2.048 sec
  47. Buckets: prometheus.ExponentialBuckets(0.0005, 2, 13),
  48. }, []string{"method"})
  49. )
  50. func init() {
  51. prometheus.MustRegister(incomingEvents)
  52. prometheus.MustRegister(failedEvents)
  53. prometheus.MustRegister(successfulEventsHandlingSec)
  54. }
  55. func reportRequestReceived(request etcdserverpb.Request) {
  56. incomingEvents.WithLabelValues(methodFromRequest(request)).Inc()
  57. }
  58. func reportRequestCompleted(request etcdserverpb.Request, startTime time.Time) {
  59. method := methodFromRequest(request)
  60. successfulEventsHandlingSec.WithLabelValues(method).Observe(time.Since(startTime).Seconds())
  61. }
  62. func reportRequestFailed(request etcdserverpb.Request, err error) {
  63. method := methodFromRequest(request)
  64. failedEvents.WithLabelValues(method, strconv.Itoa(codeFromError(err))).Inc()
  65. }
  66. func methodFromRequest(request etcdserverpb.Request) string {
  67. if request.Method == "GET" && request.Quorum {
  68. return "QGET"
  69. }
  70. return request.Method
  71. }
  72. func codeFromError(err error) int {
  73. if err == nil {
  74. return http.StatusInternalServerError
  75. }
  76. switch e := err.(type) {
  77. case *v2error.Error:
  78. return e.StatusCode()
  79. case *httptypes.HTTPError:
  80. return e.Code
  81. default:
  82. return http.StatusInternalServerError
  83. }
  84. }