Skip to content

Commit

Permalink
Merge pull request #338 from nr-swilloughby/331_grpc_errors
Browse files Browse the repository at this point in the history
Enhanced handling of grpc errors (issue #331)
  • Loading branch information
nr-swilloughby authored Jul 12, 2021
2 parents 91068fa + b5d08f3 commit afea37e
Show file tree
Hide file tree
Showing 4 changed files with 357 additions and 135 deletions.
52 changes: 26 additions & 26 deletions v3/integrations/nrgrpc/nrgrpc_client_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -95,15 +95,15 @@ func TestUnaryClientInterceptor(t *testing.T) {

client := testapp.NewTestApplicationClient(conn)
resp, err := client.DoUnaryUnary(ctx, &testapp.Message{})
if nil != err {
if err != nil {
t.Fatal("client call to DoUnaryUnary failed", err)
}
var hdrs map[string][]string
err = json.Unmarshal([]byte(resp.Text), &hdrs)
if nil != err {
if err != nil {
t.Fatal("cannot unmarshall client response", err)
}
if hdr, ok := hdrs["newrelic"]; !ok || len(hdr) != 1 || "" == hdr[0] {
if hdr, ok := hdrs["newrelic"]; !ok || len(hdr) != 1 || hdr[0] == "" {
t.Error("distributed trace header not sent", hdrs)
}
txn.End()
Expand Down Expand Up @@ -175,7 +175,7 @@ func TestUnaryStreamClientInterceptor(t *testing.T) {

client := testapp.NewTestApplicationClient(conn)
stream, err := client.DoUnaryStream(ctx, &testapp.Message{})
if nil != err {
if err != nil {
t.Fatal("client call to DoUnaryStream failed", err)
}
var recved int
Expand All @@ -184,15 +184,15 @@ func TestUnaryStreamClientInterceptor(t *testing.T) {
if err == io.EOF {
break
}
if nil != err {
if err != nil {
t.Fatal("error receiving message", err)
}
var hdrs map[string][]string
err = json.Unmarshal([]byte(msg.Text), &hdrs)
if nil != err {
if err != nil {
t.Fatal("cannot unmarshall client response", err)
}
if hdr, ok := hdrs["newrelic"]; !ok || len(hdr) != 1 || "" == hdr[0] {
if hdr, ok := hdrs["newrelic"]; !ok || len(hdr) != 1 || hdr[0] == "" {
t.Error("distributed trace header not sent", hdrs)
}
recved++
Expand Down Expand Up @@ -269,27 +269,27 @@ func TestStreamUnaryClientInterceptor(t *testing.T) {

client := testapp.NewTestApplicationClient(conn)
stream, err := client.DoStreamUnary(ctx)
if nil != err {
if err != nil {
t.Fatal("client call to DoStreamUnary failed", err)
}
for i := 0; i < 3; i++ {
if err := stream.Send(&testapp.Message{Text: "Hello DoStreamUnary"}); nil != err {
if err := stream.Send(&testapp.Message{Text: "Hello DoStreamUnary"}); err != nil {
if err == io.EOF {
break
}
t.Fatal("failure to Send", err)
}
}
msg, err := stream.CloseAndRecv()
if nil != err {
if err != nil {
t.Fatal("failure to CloseAndRecv", err)
}
var hdrs map[string][]string
err = json.Unmarshal([]byte(msg.Text), &hdrs)
if nil != err {
if err != nil {
t.Fatal("cannot unmarshall client response", err)
}
if hdr, ok := hdrs["newrelic"]; !ok || len(hdr) != 1 || "" == hdr[0] {
if hdr, ok := hdrs["newrelic"]; !ok || len(hdr) != 1 || hdr[0] == "" {
t.Error("distributed trace header not sent", hdrs)
}
txn.End()
Expand Down Expand Up @@ -361,7 +361,7 @@ func TestStreamStreamClientInterceptor(t *testing.T) {

client := testapp.NewTestApplicationClient(conn)
stream, err := client.DoStreamStream(ctx)
if nil != err {
if err != nil {
t.Fatal("client call to DoStreamStream failed", err)
}
waitc := make(chan struct{})
Expand All @@ -378,10 +378,10 @@ func TestStreamStreamClientInterceptor(t *testing.T) {
}
var hdrs map[string][]string
err = json.Unmarshal([]byte(msg.Text), &hdrs)
if nil != err {
if err != nil {
t.Fatal("cannot unmarshall client response", err)
}
if hdr, ok := hdrs["newrelic"]; !ok || len(hdr) != 1 || "" == hdr[0] {
if hdr, ok := hdrs["newrelic"]; !ok || len(hdr) != 1 || hdr[0] == "" {
t.Error("distributed trace header not sent", hdrs)
}
recved++
Expand Down Expand Up @@ -473,18 +473,18 @@ func TestClientUnaryMetadata(t *testing.T) {

client := testapp.NewTestApplicationClient(conn)
resp, err := client.DoUnaryUnary(ctx, &testapp.Message{})
if nil != err {
if err != nil {
t.Fatal("client call to DoUnaryUnary failed", err)
}
var hdrs map[string][]string
err = json.Unmarshal([]byte(resp.Text), &hdrs)
if nil != err {
if err != nil {
t.Fatal("cannot unmarshall client response", err)
}
if hdr, ok := hdrs["newrelic"]; !ok || len(hdr) != 1 || "" == hdr[0] || "payload" == hdr[0] {
if hdr, ok := hdrs["newrelic"]; !ok || len(hdr) != 1 || hdr[0] == "" || hdr[0] == "payload" {
t.Error("distributed trace header not sent", hdrs)
}
if hdr, ok := hdrs["testing"]; !ok || len(hdr) != 1 || "hello world" != hdr[0] {
if hdr, ok := hdrs["testing"]; !ok || len(hdr) != 1 || hdr[0] != "hello world" {
t.Error("testing header not sent", hdrs)
}
}
Expand All @@ -496,12 +496,12 @@ func TestNilTxnClientUnary(t *testing.T) {

client := testapp.NewTestApplicationClient(conn)
resp, err := client.DoUnaryUnary(context.Background(), &testapp.Message{})
if nil != err {
if err != nil {
t.Fatal("client call to DoUnaryUnary failed", err)
}
var hdrs map[string][]string
err = json.Unmarshal([]byte(resp.Text), &hdrs)
if nil != err {
if err != nil {
t.Fatal("cannot unmarshall client response", err)
}
if _, ok := hdrs["newrelic"]; ok {
Expand All @@ -516,24 +516,24 @@ func TestNilTxnClientStreaming(t *testing.T) {

client := testapp.NewTestApplicationClient(conn)
stream, err := client.DoStreamUnary(context.Background())
if nil != err {
if err != nil {
t.Fatal("client call to DoStreamUnary failed", err)
}
for i := 0; i < 3; i++ {
if err := stream.Send(&testapp.Message{Text: "Hello DoStreamUnary"}); nil != err {
if err := stream.Send(&testapp.Message{Text: "Hello DoStreamUnary"}); err != nil {
if err == io.EOF {
break
}
t.Fatal("failure to Send", err)
}
}
msg, err := stream.CloseAndRecv()
if nil != err {
if err != nil {
t.Fatal("failure to CloseAndRecv", err)
}
var hdrs map[string][]string
err = json.Unmarshal([]byte(msg.Text), &hdrs)
if nil != err {
if err != nil {
t.Fatal("cannot unmarshall client response", err)
}
if _, ok := hdrs["newrelic"]; ok {
Expand All @@ -557,7 +557,7 @@ func TestClientStreamingError(t *testing.T) {
defer cancel()
ctx = newrelic.NewContext(ctx, txn)
_, err := client.DoUnaryStream(ctx, &testapp.Message{})
if nil == err {
if err == nil {
t.Fatal("client call to DoUnaryStream did not return error")
}
txn.End()
Expand Down
61 changes: 51 additions & 10 deletions v3/integrations/nrgrpc/nrgrpc_doc.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
// Copyright 2020 New Relic Corporation. All rights reserved.
// SPDX-License-Identifier: Apache-2.0

//
// Package nrgrpc instruments https://github.com/grpc/grpc-go.
//
// This package can be used to instrument gRPC servers and gRPC clients.
Expand All @@ -9,18 +10,58 @@
//
// To instrument a gRPC server, use UnaryServerInterceptor and
// StreamServerInterceptor with your newrelic.Application to create server
// interceptors to pass to grpc.NewServer. Example:
// interceptors to pass to grpc.NewServer.
//
// The results of these calls are reported as errors or as informational
// messages (of levels OK, Info, Warning, or Error) based on the gRPC status
// code they return.
//
// app, _ := newrelic.NewApplication(
// newrelic.ConfigAppName("gRPC Server"),
// newrelic.ConfigLicense(os.Getenv("NEW_RELIC_LICENSE_KEY")),
// newrelic.ConfigDebugLogger(os.Stdout),
// )
// server := grpc.NewServer(
// grpc.UnaryInterceptor(nrgrpc.UnaryServerInterceptor(app)),
// grpc.StreamInterceptor(nrgrpc.StreamServerInterceptor(app)),
// )
// In the simplest case, simply add interceptors as in the following example:
//
// app, _ := newrelic.NewApplication(
// newrelic.ConfigAppName("gRPC Server"),
// newrelic.ConfigLicense(os.Getenv("NEW_RELIC_LICENSE_KEY")),
// newrelic.ConfigDebugLogger(os.Stdout),
// )
// server := grpc.NewServer(
// grpc.UnaryInterceptor(nrgrpc.UnaryServerInterceptor(app)),
// grpc.StreamInterceptor(nrgrpc.StreamServerInterceptor(app)),
// )
//
// The disposition of each, in terms of how to report each of the various
// gRPC status codes, is determined by a built-in set of defaults:
// OK OK
// Info AlreadyExists, Canceled, InvalidArgument, NotFound,
// Unauthenticated
// Warning Aborted, DeadlineExceeded, FailedPrecondition, OutOfRange,
// PermissionDenied, ResourceExhausted, Unavailable
// Error DataLoss, Internal, Unknown, Unimplemented
//
// These
// may be overridden on a case-by-case basis using `WithStatusHandler()`
// options to each `UnaryServerInterceptor()` or `StreamServerInterceptor()`
// call, or globally via the `Configure()` function.
//
// For example, to report DeadlineExceeded as an error and NotFound
// as a warning, for the UnaryInterceptor only:
// server := grpc.NewServer(
// grpc.UnaryInterceptor(nrgrpc.UnaryServerInterceptor(app,
// nrgrpc.WithStatusHandler(codes.DeadlineExceeded, nrgrpc.ErrorInterceptorStatusHandler),
// nrgrpc.WithStatusHandler(codes.NotFound, nrgrpc.WarningInterceptorStatusHandler)),
// grpc.StreamInterceptor(nrgrpc.StreamServerInterceptor(app)),
// )
//
// If you wanted to make those two changes to the overall default behavior, so they
// apply to all subsequently declared interceptors:
// nrgrpc.Configure(
// nrgrpc.WithStatusHandler(codes.DeadlineExceeded, nrgrpc.ErrorInterceptorStatusHandler),
// nrgrpc.WithStatusHandler(codes.NotFound, nrgrpc.WarningInterceptorStatusHandler),
// )
// server := grpc.NewServer(
// grpc.UnaryInterceptor(nrgrpc.UnaryServerInterceptor(app)),
// grpc.StreamInterceptor(nrgrpc.StreamServerInterceptor(app)),
// )
// In this case the new behavior for those two status codes applies to both interceptors.
//
// These interceptors create transactions for inbound calls. The transaction is
// added to the call context and can be accessed in your method handlers
Expand Down
Loading

0 comments on commit afea37e

Please sign in to comment.