/
stats.go
93 lines (76 loc) · 1.94 KB
/
stats.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
package rpc
import (
"context"
"sync/atomic"
"time"
"google.golang.org/grpc/stats"
)
type statsctxKey struct{}
type Stats struct {
Duration time.Duration
respSize int64
reqSize int64
}
func (s *Stats) RespSize() int64 {
return atomic.LoadInt64(&s.respSize)
}
func (s *Stats) ReqSize() int64 {
return atomic.LoadInt64(&s.reqSize)
}
// this method is based on
// https://github.com/cockroachdb/cockroach/blob/master/pkg/rpc/stats_handler.go
func (s *Stats) record(rpcStats stats.RPCStats) {
switch v := rpcStats.(type) {
case *stats.InHeader:
atomic.AddInt64(&s.respSize, int64(v.WireLength))
case *stats.InPayload:
atomic.AddInt64(&s.respSize, int64(v.WireLength))
case *stats.InTrailer:
atomic.AddInt64(&s.respSize, int64(v.WireLength))
case *stats.OutHeader:
// No wire length.
case *stats.OutPayload:
atomic.AddInt64(&s.reqSize, int64(v.WireLength))
case *stats.OutTrailer:
atomic.AddInt64(&s.reqSize, int64(v.WireLength))
case *stats.End:
s.Duration = v.EndTime.Sub(v.BeginTime)
}
}
type statsHandler struct{}
func newStatsHanler() stats.Handler {
return &statsHandler{}
}
func (cs *statsHandler) TagRPC(ctx context.Context, rti *stats.RPCTagInfo) context.Context {
return ctx
}
func (cs *statsHandler) HandleRPC(ctx context.Context, rpcStats stats.RPCStats) {
stats := ExtractRpcStats(ctx)
if stats != nil {
stats.record(rpcStats)
}
}
func (cs *statsHandler) TagConn(ctx context.Context, cti *stats.ConnTagInfo) context.Context {
return ctx
}
func (cs *statsHandler) HandleConn(context.Context, stats.ConnStats) {
}
func WithStatsCtx(parentCtx context.Context) context.Context {
stats := ExtractRpcStats(parentCtx)
if stats == nil {
stats = &Stats{}
return context.WithValue(parentCtx, statsctxKey{}, stats)
}
return parentCtx
}
func ExtractRpcStats(ctx context.Context) *Stats {
val := ctx.Value(statsctxKey{})
if val == nil {
return nil
}
stats, ok := val.(*Stats)
if !ok {
return nil
}
return stats
}