1
1
package main
2
2
3
3
import (
4
+ "fmt"
4
5
"math/rand"
5
6
"net/http"
6
7
_ "net/http/pprof"
7
8
"time"
9
+
10
+ "github.com/prometheus/client_golang/prometheus"
11
+ )
12
+
13
+ var (
14
+ namespace = "codelab"
15
+ subsystem = "api"
16
+
17
+ requestHistogram = prometheus .NewHistogramVec (
18
+ prometheus.HistogramOpts {
19
+ Namespace : namespace ,
20
+ Subsystem : subsystem ,
21
+ Name : "request_duration_seconds" ,
22
+ Help : "A histogram of the API HTTP request durations in seconds." ,
23
+ Buckets : prometheus .ExponentialBuckets (0.0001 , 1.5 , 25 ),
24
+ },
25
+ []string {"method" , "path" , "status" },
26
+ )
27
+ requestsInProgress = prometheus .NewGauge (
28
+ prometheus.GaugeOpts {
29
+ Namespace : namespace ,
30
+ Subsystem : subsystem ,
31
+ Name : "http_requests_in_progress" ,
32
+ Help : "The current number of API HTTP requests in progress." ,
33
+ })
8
34
)
9
35
36
+ func init () {
37
+ prometheus .MustRegister (requestHistogram )
38
+ prometheus .MustRegister (requestsInProgress )
39
+ }
40
+
10
41
type responseOpts struct {
11
42
baseLatency time.Duration
12
43
errorRatio float64
@@ -47,14 +78,29 @@ var opts = map[string]map[string]responseOpts{
47
78
}
48
79
49
80
func handleAPI (w http.ResponseWriter , r * http.Request ) {
81
+ begun := time .Now ()
82
+ requestsInProgress .Inc ()
83
+ status := http .StatusOK
84
+
85
+ defer func () {
86
+ requestsInProgress .Dec ()
87
+ requestHistogram .With (prometheus.Labels {
88
+ "method" : r .Method ,
89
+ "path" : r .URL .Path ,
90
+ "status" : fmt .Sprint (status ),
91
+ }).Observe (time .Since (begun ).Seconds ())
92
+ }()
93
+
50
94
pathOpts , ok := opts [r .URL .Path ]
51
95
if ! ok {
52
- http .Error (w , "Not Found" , http .StatusNotFound )
96
+ status = http .StatusNotFound
97
+ http .Error (w , fmt .Sprintf ("Path %q not found." , r .URL .Path ), status )
53
98
return
54
99
}
55
100
methodOpts , ok := pathOpts [r .Method ]
56
101
if ! ok {
57
- http .Error (w , "Method not Allowed" , http .StatusMethodNotAllowed )
102
+ status = http .StatusMethodNotAllowed
103
+ http .Error (w , fmt .Sprintf ("Method %q not allowed." , r .Method ), status )
58
104
return
59
105
}
60
106
@@ -68,6 +114,7 @@ func handleAPI(w http.ResponseWriter, r *http.Request) {
68
114
(methodOpts .baseLatency + time .Duration (rand .NormFloat64 ()* float64 (methodOpts .baseLatency )/ 10 )) * latencyFactor ,
69
115
)
70
116
if rand .Float64 () <= methodOpts .errorRatio * errorFactor {
71
- http .Error (w , "Internal Server Error" , http .StatusInternalServerError )
117
+ status = http .StatusInternalServerError
118
+ http .Error (w , "Fake error to test monitoring." , status )
72
119
}
73
120
}
0 commit comments