blob: 14f7da0fea70cebe4055d8956ccb9faeb61aa4a8 [file] [log] [blame]
khenaidoo59ce9dd2019-11-11 13:05:32 -05001// 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
15package v2http
16
17import (
18 "strconv"
19 "time"
20
21 "net/http"
22
23 "go.etcd.io/etcd/etcdserver/api/v2error"
24 "go.etcd.io/etcd/etcdserver/api/v2http/httptypes"
25 "go.etcd.io/etcd/etcdserver/etcdserverpb"
26
27 "github.com/prometheus/client_golang/prometheus"
28)
29
30var (
31 incomingEvents = prometheus.NewCounterVec(
32 prometheus.CounterOpts{
33 Namespace: "etcd",
34 Subsystem: "http",
35 Name: "received_total",
36 Help: "Counter of requests received into the system (successfully parsed and authd).",
37 }, []string{"method"})
38
39 failedEvents = prometheus.NewCounterVec(
40 prometheus.CounterOpts{
41 Namespace: "etcd",
42 Subsystem: "http",
43 Name: "failed_total",
44 Help: "Counter of handle failures of requests (non-watches), by method (GET/PUT etc.) and code (400, 500 etc.).",
45 }, []string{"method", "code"})
46
47 successfulEventsHandlingSec = prometheus.NewHistogramVec(
48 prometheus.HistogramOpts{
49 Namespace: "etcd",
50 Subsystem: "http",
51 Name: "successful_duration_seconds",
52 Help: "Bucketed histogram of processing time (s) of successfully handled requests (non-watches), by method (GET/PUT etc.).",
53
54 // lowest bucket start of upper bound 0.0005 sec (0.5 ms) with factor 2
55 // highest bucket start of 0.0005 sec * 2^12 == 2.048 sec
56 Buckets: prometheus.ExponentialBuckets(0.0005, 2, 13),
57 }, []string{"method"})
58)
59
60func init() {
61 prometheus.MustRegister(incomingEvents)
62 prometheus.MustRegister(failedEvents)
63 prometheus.MustRegister(successfulEventsHandlingSec)
64}
65
66func reportRequestReceived(request etcdserverpb.Request) {
67 incomingEvents.WithLabelValues(methodFromRequest(request)).Inc()
68}
69
70func reportRequestCompleted(request etcdserverpb.Request, startTime time.Time) {
71 method := methodFromRequest(request)
72 successfulEventsHandlingSec.WithLabelValues(method).Observe(time.Since(startTime).Seconds())
73}
74
75func reportRequestFailed(request etcdserverpb.Request, err error) {
76 method := methodFromRequest(request)
77 failedEvents.WithLabelValues(method, strconv.Itoa(codeFromError(err))).Inc()
78}
79
80func methodFromRequest(request etcdserverpb.Request) string {
81 if request.Method == "GET" && request.Quorum {
82 return "QGET"
83 }
84 return request.Method
85}
86
87func codeFromError(err error) int {
88 if err == nil {
89 return http.StatusInternalServerError
90 }
91 switch e := err.(type) {
92 case *v2error.Error:
93 return e.StatusCode()
94 case *httptypes.HTTPError:
95 return e.Code
96 default:
97 return http.StatusInternalServerError
98 }
99}