1
1
package engine
2
2
3
3
import (
4
- "fmt "
4
+ "io "
5
5
"log"
6
6
"net/http"
7
7
"sync"
@@ -11,55 +11,72 @@ import (
11
11
"github.com/prometheus/client_golang/prometheus/promhttp"
12
12
)
13
13
14
+ const (
15
+ namespace = "heimdall"
16
+ subsystem = "engine"
17
+ )
18
+
14
19
var (
15
- // For the HTTP transport
16
- httpRequests = prometheus .NewCounterVec (
20
+ // Track inbound bytes partitioned by remote host
21
+ inboundBytes = prometheus .NewCounterVec (
17
22
prometheus.CounterOpts {
18
- Name : "http_requests" ,
19
- Help : "Total number of HTTP requests made." ,
23
+ Namespace : namespace ,
24
+ Subsystem : subsystem ,
25
+ Name : "bytes_in" ,
26
+ Help : "Total bytes inbound" ,
20
27
},
21
- []string {"method" , "status_code " },
28
+ []string {"host " },
22
29
)
23
- httpRequestDuration = prometheus .NewHistogramVec (
24
- prometheus.HistogramOpts {
25
- Name : "http_request_duration_ms" ,
26
- Help : "Histogram of HTTP request durations." ,
27
- Buckets : prometheus .DefBuckets ,
30
+
31
+ // Track outbound bytes partitioned by remote host
32
+ outboundBytes = prometheus .NewCounterVec (
33
+ prometheus.CounterOpts {
34
+ Namespace : namespace ,
35
+ Subsystem : subsystem ,
36
+ Name : "bytes_out" ,
37
+ Help : "Total bytes outbound" ,
28
38
},
29
- []string {"method" , "status_code " },
39
+ []string {"host " },
30
40
)
31
41
32
- // For specific RPC calls
42
+ // Track calls by RPC method
33
43
rpcCalls = prometheus .NewCounterVec (
34
44
prometheus.CounterOpts {
35
- Name : "rpc_calls" ,
36
- Help : "Total number of RPC calls made." ,
45
+ Namespace : namespace ,
46
+ Subsystem : subsystem ,
47
+ Name : "calls" ,
48
+ Help : "Total number of RPC calls" ,
37
49
},
38
- []string {"rpc " },
50
+ []string {"method " },
39
51
)
40
52
41
- rpcCallDuration = prometheus .NewHistogramVec (
53
+ // Track call durations by RPC method
54
+ rpcDuration = prometheus .NewHistogramVec (
42
55
prometheus.HistogramOpts {
43
- Name : "rpc_call_duration_ms" ,
44
- Help : "Histogram of HTTP request durations." ,
45
- Buckets : prometheus .DefBuckets ,
56
+ Namespace : namespace ,
57
+ Subsystem : subsystem ,
58
+ Name : "duration" ,
59
+ Help : "Histogram of RPC request durations" ,
60
+ Buckets : prometheus .DefBuckets ,
46
61
},
47
62
[]string {"method" },
48
63
)
64
+
65
+ // Track errors by RPC method and error type
49
66
rpcErrors = prometheus .NewCounterVec (
50
67
prometheus.CounterOpts {
51
- Name : "rpc_errors " ,
68
+ Name : "errors " ,
52
69
Help : "Total number of RPC errors encountered." ,
53
70
},
54
- []string {"rpc " , "error" },
71
+ []string {"method " , "error" },
55
72
)
56
73
)
57
74
58
75
func init () {
59
- prometheus .MustRegister (httpRequests )
60
- prometheus .MustRegister (httpRequestDuration )
76
+ prometheus .MustRegister (inboundBytes )
77
+ prometheus .MustRegister (outboundBytes )
61
78
prometheus .MustRegister (rpcCalls )
62
- prometheus .MustRegister (rpcCallDuration )
79
+ prometheus .MustRegister (rpcDuration )
63
80
prometheus .MustRegister (rpcErrors )
64
81
}
65
82
@@ -89,21 +106,60 @@ func startMetricsServer() {
89
106
})
90
107
}
91
108
109
+ type IOBytesMetrics struct {
110
+ rc io.ReadCloser
111
+ onClose func (totalBytes int64 )
112
+ totalBytes int64
113
+ }
114
+
115
+ func (m * IOBytesMetrics ) Read (p []byte ) (int , error ) {
116
+ n , err := m .rc .Read (p )
117
+ m .totalBytes += int64 (n )
118
+ return n , err
119
+ }
120
+
121
+ func (m * IOBytesMetrics ) Close () error {
122
+ if m .onClose != nil {
123
+ m .onClose (m .totalBytes )
124
+ }
125
+ return m .rc .Close ()
126
+ }
127
+
92
128
type MetricsTransport struct {
93
129
Transport http.RoundTripper
94
130
}
95
131
96
132
func (mt * MetricsTransport ) RoundTrip (req * http.Request ) (* http.Response , error ) {
97
- start := time .Now ()
98
- resp , err := mt .Transport .RoundTrip (req )
99
- duration := time .Since (start ).Milliseconds ()
133
+ if mt .Transport == nil {
134
+ mt .Transport = http .DefaultTransport
135
+ }
136
+
137
+ host := req .URL .Host
100
138
139
+ if req .Body != nil {
140
+ rc := req .Body
141
+ req .Body = & IOBytesMetrics {
142
+ rc : rc ,
143
+ onClose : func (totalBytes int64 ) {
144
+ outboundBytes .WithLabelValues (host ).Add (float64 (totalBytes ))
145
+ },
146
+ }
147
+ }
148
+
149
+ resp , err := mt .Transport .RoundTrip (req )
101
150
if err != nil {
102
151
return nil , err
103
152
}
104
153
105
- httpRequests .WithLabelValues (req .Method , fmt .Sprintf ("%d" , resp .StatusCode )).Inc ()
106
- httpRequestDuration .WithLabelValues (req .Method , fmt .Sprintf ("%d" , resp .StatusCode )).Observe (float64 (duration ))
154
+ if resp .Body != nil {
155
+ rc := resp .Body
156
+ resp .Body = & IOBytesMetrics {
157
+ rc : rc ,
158
+ onClose : func (totalBytes int64 ) {
159
+ inboundBytes .WithLabelValues (host ).Add (float64 (totalBytes ))
160
+ },
161
+ }
162
+ }
107
163
108
164
return resp , nil
109
165
}
0 commit comments