mirror of https://github.com/grpc/grpc-go.git
stats: add Trailer to client-side stats.End (#2639)
Currently, it is not possible to access trailers from within a stats.Handler. The reason is that both stats.Handler and ClientStream.Trailer require a lock on the ClientStream. A workaround would be to start a separate goroutine that will call ClientStream.Trailer asynchronously, but that requires careful coordination and we can quite easily make the trailer metadata available to the stats.Handler directly. Use case: an interceptor that processes trailer metadata for each streaming RPC after the stream has finished. Note that a StreamClientInterceptor returns immediately, before the stream has finished and before the trailer metadata is available.
This commit is contained in:
parent
d3f95b277a
commit
9c3a959569
|
|
@ -27,6 +27,8 @@ import (
|
|||
"context"
|
||||
"net"
|
||||
"time"
|
||||
|
||||
"google.golang.org/grpc/metadata"
|
||||
)
|
||||
|
||||
// RPCStats contains stats information about RPCs.
|
||||
|
|
@ -172,6 +174,9 @@ type End struct {
|
|||
BeginTime time.Time
|
||||
// EndTime is the time when the RPC ends.
|
||||
EndTime time.Time
|
||||
// Trailer contains the trailer metadata received from the server. This
|
||||
// field is only valid if this End is from the client side.
|
||||
Trailer metadata.MD
|
||||
// Error is the error the RPC ended with. It is an error generated from
|
||||
// status.Status and can be converted back to status.Status using
|
||||
// status.FromError if non-nil.
|
||||
|
|
|
|||
|
|
@ -652,6 +652,16 @@ func checkEnd(t *testing.T, d *gotData, e *expectedData) {
|
|||
if actual.Code() != expectedStatus.Code() || actual.Message() != expectedStatus.Message() {
|
||||
t.Fatalf("st.Error = %v, want %v", st.Error, e.err)
|
||||
}
|
||||
|
||||
if st.Client {
|
||||
if !reflect.DeepEqual(st.Trailer, testTrailerMetadata) {
|
||||
t.Fatalf("st.Trailer = %v, want %v", st.Trailer, testTrailerMetadata)
|
||||
}
|
||||
} else {
|
||||
if st.Trailer != nil {
|
||||
t.Fatalf("st.Trailer = %v, want nil", st.Trailer)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func checkConnBegin(t *testing.T, d *gotData, e *expectedData) {
|
||||
|
|
|
|||
|
|
@ -915,16 +915,16 @@ func (a *csAttempt) finish(err error) {
|
|||
// Ending a stream with EOF indicates a success.
|
||||
err = nil
|
||||
}
|
||||
var tr metadata.MD
|
||||
if a.s != nil {
|
||||
a.t.CloseStream(a.s, err)
|
||||
tr = a.s.Trailer()
|
||||
}
|
||||
|
||||
if a.done != nil {
|
||||
br := false
|
||||
var tr metadata.MD
|
||||
if a.s != nil {
|
||||
br = a.s.BytesReceived()
|
||||
tr = a.s.Trailer()
|
||||
}
|
||||
a.done(balancer.DoneInfo{
|
||||
Err: err,
|
||||
|
|
@ -938,6 +938,7 @@ func (a *csAttempt) finish(err error) {
|
|||
Client: true,
|
||||
BeginTime: a.cs.beginTime,
|
||||
EndTime: time.Now(),
|
||||
Trailer: tr,
|
||||
Error: err,
|
||||
}
|
||||
a.statsHandler.HandleRPC(a.cs.ctx, end)
|
||||
|
|
|
|||
Loading…
Reference in New Issue