svakili
svakili

Reputation: 2189

Access information about the request and response payloads in grpc-go's stat/HandleRPC

I am using stats/HandleRPC() to emit some metrics about the RPC duration, when I receive the stats/End data, and I want to tag the metrics with some information that can be extracted from the incoming and outgoing payloads. What would be the best way to achieve this?

func (h *myStatsHandler) HandleRPC(ctx context.Context, rpcStats stats.RPCStats) {
    switch stat := rpcStats.(type) {
    case *stats.End:
        durationMs := stat.EndTime.Sub(stat.BeginTime).Seconds() * 1000.0
        // Now before sending this value, I need to know, for example the value of a specific key in the request payload, or whether the response is nil or not 
    }
}

Upvotes: 2

Views: 496

Answers (1)

Jared
Jared

Reputation: 149

In your implementation of TagRPC, you can create a struct and add a pointer to it to the context. Then add information in it over the successive calls to HandleRPC. So if you need something from the Payload that's only available in the *stats.InPayload invocation, you can pull it out and store it in the struct you added to the context, and then access it later when HandleRPC is called again with *stats.End

type recorderCtxKey struct{}

type recorder struct {
    size   int64
}

func (sl *statsHandler) TagRPC(ctx context.Context, info *stats.RPCTagInfo) context.Context {
    return context.WithValue(ctx, rpcStatCtxKey{}, &recorder{})
}

func (h *statsHandler) HandleRPC(ctx context.Context, rpcStats stats.RPCStats) {
    switch stat := rpcStats.(type) {
    case *stats.InPayload:
        r, _ := ctx.Value(recorderContextKey{}).(*Recorder)
        r.size += stat.WireLength
    case *stats.End:
        durationMs := stat.EndTime.Sub(stat.BeginTime).Seconds() * 1000.0
        r, _ := ctx.Value(recorderContextKey{}).(*Recorder)
        # use r.size #
    }
}

Upvotes: 1

Related Questions