Skip to content

Commit 82be82a

Browse files
change metrics interceptor to measure bytes in/out
1 parent 299abd9 commit 82be82a

File tree

2 files changed

+90
-34
lines changed

2 files changed

+90
-34
lines changed

engine/client.go

+4-4
Original file line numberDiff line numberDiff line change
@@ -119,12 +119,12 @@ func (ec *EngineClient) CheckCapabilities(ctx context.Context, requiredMethods [
119119
return
120120
}
121121

122-
func observe(rpc string, start time.Time, err error) {
122+
func observe(method string, start time.Time, err error) {
123123
elapsed := time.Since(start)
124-
rpcCalls.WithLabelValues(rpc).Inc()
125-
rpcCallDuration.WithLabelValues(rpc).Observe(float64(elapsed.Milliseconds()))
124+
rpcCalls.WithLabelValues(method).Inc()
125+
rpcDuration.WithLabelValues(method).Observe(float64(elapsed.Milliseconds()))
126126
if err != nil {
127-
rpcErrors.WithLabelValues(rpc, reflect.TypeOf(err).String()).Inc()
127+
rpcErrors.WithLabelValues(method, reflect.TypeOf(err).String()).Inc()
128128
}
129129
}
130130

engine/metrics.go

+86-30
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
package engine
22

33
import (
4-
"fmt"
4+
"io"
55
"log"
66
"net/http"
77
"sync"
@@ -11,55 +11,72 @@ import (
1111
"github.com/prometheus/client_golang/prometheus/promhttp"
1212
)
1313

14+
const (
15+
namespace = "heimdall"
16+
subsystem = "engine"
17+
)
18+
1419
var (
15-
// For the HTTP transport
16-
httpRequests = prometheus.NewCounterVec(
20+
// Track inbound bytes partitioned by remote host
21+
inboundBytes = prometheus.NewCounterVec(
1722
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",
2027
},
21-
[]string{"method", "status_code"},
28+
[]string{"host"},
2229
)
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",
2838
},
29-
[]string{"method", "status_code"},
39+
[]string{"host"},
3040
)
3141

32-
// For specific RPC calls
42+
// Track calls by RPC method
3343
rpcCalls = prometheus.NewCounterVec(
3444
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",
3749
},
38-
[]string{"rpc"},
50+
[]string{"method"},
3951
)
4052

41-
rpcCallDuration = prometheus.NewHistogramVec(
53+
// Track call durations by RPC method
54+
rpcDuration = prometheus.NewHistogramVec(
4255
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,
4661
},
4762
[]string{"method"},
4863
)
64+
65+
// Track errors by RPC method and error type
4966
rpcErrors = prometheus.NewCounterVec(
5067
prometheus.CounterOpts{
51-
Name: "rpc_errors",
68+
Name: "errors",
5269
Help: "Total number of RPC errors encountered.",
5370
},
54-
[]string{"rpc", "error"},
71+
[]string{"method", "error"},
5572
)
5673
)
5774

5875
func init() {
59-
prometheus.MustRegister(httpRequests)
60-
prometheus.MustRegister(httpRequestDuration)
76+
prometheus.MustRegister(inboundBytes)
77+
prometheus.MustRegister(outboundBytes)
6178
prometheus.MustRegister(rpcCalls)
62-
prometheus.MustRegister(rpcCallDuration)
79+
prometheus.MustRegister(rpcDuration)
6380
prometheus.MustRegister(rpcErrors)
6481
}
6582

@@ -89,21 +106,60 @@ func startMetricsServer() {
89106
})
90107
}
91108

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+
92128
type MetricsTransport struct {
93129
Transport http.RoundTripper
94130
}
95131

96132
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
100138

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)
101150
if err != nil {
102151
return nil, err
103152
}
104153

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+
}
107163

108164
return resp, nil
109165
}

0 commit comments

Comments
 (0)