nrgrpc

package module
v1.3.2 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Mar 16, 2022 License: Apache-2.0 Imports: 11 Imported by: 0

README

v3/integrations/nrgrpc GoDoc

Package nrgrpc instruments https://github.com/grpc/grpc-go.

import "github.com/Easypay/go-agent/v3/integrations/nrgrpc"

For more information, see godocs.

Documentation

Overview

Package nrgrpc instruments https://github.com/grpc/grpc-go.

This package can be used to instrument gRPC servers and gRPC clients.

Server

To instrument a gRPC server, use UnaryServerInterceptor and StreamServerInterceptor with your newrelic.Application to create server 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.

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 using newrelic.FromContext.

// handler is your gRPC server handler. Access the currently running
// transaction using newrelic.FromContext.
func (s *Server) handler(ctx context.Context, msg *pb.Message) (*pb.Message, error) {
	if err := processMsg(msg); err != nil {
		txn := newrelic.FromContext(ctx)
		txn.NoticeError(err)
		return nil, err
	}
	return &pb.Message{Text: "Hello World!"}, nil
}

Full server example: https://github.com/Easypay/go-agent/blob/master/v3/integrations/nrgrpc/example/server/server.go

Client

To instrument a gRPC client, follow these two steps:

1. Use UnaryClientInterceptor and StreamClientInterceptor when creating a grpc.ClientConn. Example:

conn, err := grpc.Dial(
	"localhost:8080",
	grpc.WithUnaryInterceptor(nrgrpc.UnaryClientInterceptor),
	grpc.WithStreamInterceptor(nrgrpc.StreamClientInterceptor),
)

2. Ensure that calls made with this grpc.ClientConn are done with a context which contains a newrelic.Transaction.

// Add the currently running transaction to the context before making a
// client call.
ctx := newrelic.NewContext(context.Background(), txn)
msg, err := client.handler(ctx, &pb.Message{"Hello World"})

Full client example: https://github.com/Easypay/go-agent/blob/master/v3/integrations/nrgrpc/example/client/client.go

Index

Constants

This section is empty.

Variables

View Source
var DefaultInterceptorStatusHandler = InfoInterceptorStatusHandler

DefaultInterceptorStatusHandler indicates which of our standard handlers will be used for any status code which is not explicitly assigned a handler.

Functions

func Configure

func Configure(options ...HandlerOption)

Configure takes a list of WithStatusHandler options and sets them as the new default handlers for the specified gRPC status codes, in the same way as if WithStatusHandler were given to the StreamServiceInterceptor or UnaryServiceInterceptor functions (q.v.); however, in this case the new handlers become the default for any subsequent interceptors created by the above functions.

func ErrorInterceptorStatusHandler

func ErrorInterceptorStatusHandler(ctx context.Context, txn *newrelic.Transaction, s *status.Status)

ErrorInterceptorStatusHandler is our standard handler for gRPC statuses which we want to report as being errors, with the relevant error messages and contextual information gleaned from the error value received from the RPC call.

func IgnoreInterceptorStatusHandler

func IgnoreInterceptorStatusHandler(_ context.Context, _ *newrelic.Transaction, _ *status.Status)

IgnoreInterceptorStatusHandler is our standard handler for gRPC statuses which we want to ignore (in terms of any gRPC-specific reporting on the transaction).

func InfoInterceptorStatusHandler

func InfoInterceptorStatusHandler(ctx context.Context, txn *newrelic.Transaction, s *status.Status)

InfoInterceptorStatusHandler is our standard handler for gRPC statuses which we want to report as informational messages only.

Reports the transaction's status with attributes containing information gleaned from the error value returned, but does not count this as an error.

func OKInterceptorStatusHandler

func OKInterceptorStatusHandler(ctx context.Context, txn *newrelic.Transaction, s *status.Status)

OKInterceptorStatusHandler is our standard handler for gRPC statuses which we want to report as being successful, as with the status code OK.

This adds no additional attributes on the transaction other than the fact that it was successful.

func StreamClientInterceptor

func StreamClientInterceptor(ctx context.Context, desc *grpc.StreamDesc, cc *grpc.ClientConn, method string, streamer grpc.Streamer, opts ...grpc.CallOption) (grpc.ClientStream, error)

StreamClientInterceptor instruments client streaming RPCs. This interceptor records streaming each call with an external segment. Using it requires two steps:

1. Use this function with grpc.WithChainStreamInterceptor or grpc.WithStreamInterceptor when creating a grpc.ClientConn. Example:

conn, err := grpc.Dial(
	"localhost:8080",
	grpc.WithUnaryInterceptor(nrgrpc.UnaryClientInterceptor),
	grpc.WithStreamInterceptor(nrgrpc.StreamClientInterceptor),
)

2. Ensure that calls made with this grpc.ClientConn are done with a context which contains a newrelic.Transaction.

Full example: https://github.com/Easypay/go-agent/blob/master/v3/integrations/nrgrpc/example/client/client.go

This interceptor only instruments streaming calls. You must use both UnaryClientInterceptor and StreamClientInterceptor to instrument unary and streaming calls. These interceptors add headers to the call metadata if distributed tracing is enabled.

func StreamServerInterceptor

func StreamServerInterceptor(app *newrelic.Application, options ...HandlerOption) grpc.StreamServerInterceptor

StreamServerInterceptor instruments server streaming RPCs.

Use this function with grpc.StreamInterceptor and a newrelic.Application to create a grpc.ServerOption to pass to grpc.NewServer. This interceptor records each streaming call with a transaction. You must use both UnaryServerInterceptor and StreamServerInterceptor to instrument unary and streaming calls.

See the notes and examples for the UnaryServerInterceptor function.

func UnaryClientInterceptor

func UnaryClientInterceptor(ctx context.Context, method string, req, reply interface{}, cc *grpc.ClientConn, invoker grpc.UnaryInvoker, opts ...grpc.CallOption) error

UnaryClientInterceptor instruments client unary RPCs. This interceptor records each unary call with an external segment. Using it requires two steps:

1. Use this function with grpc.WithChainUnaryInterceptor or grpc.WithUnaryInterceptor when creating a grpc.ClientConn. Example:

conn, err := grpc.Dial(
	"localhost:8080",
	grpc.WithUnaryInterceptor(nrgrpc.UnaryClientInterceptor),
	grpc.WithStreamInterceptor(nrgrpc.StreamClientInterceptor),
)

2. Ensure that calls made with this grpc.ClientConn are done with a context which contains a newrelic.Transaction.

Full example: https://github.com/Easypay/go-agent/blob/master/v3/integrations/nrgrpc/example/client/client.go

This interceptor only instruments unary calls. You must use both UnaryClientInterceptor and StreamClientInterceptor to instrument unary and streaming calls. These interceptors add headers to the call metadata if distributed tracing is enabled.

func UnaryServerInterceptor

func UnaryServerInterceptor(app *newrelic.Application, options ...HandlerOption) grpc.UnaryServerInterceptor

UnaryServerInterceptor instruments server unary RPCs.

Use this function with grpc.UnaryInterceptor and a newrelic.Application to create a grpc.ServerOption to pass to grpc.NewServer. This interceptor records each unary call with a transaction. You must use both UnaryServerInterceptor and StreamServerInterceptor to instrument unary and streaming calls.

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)),
)

These interceptors add the transaction to the call context so it may be accessed in your method handlers using newrelic.FromContext.

The nrgrpc integration has a built-in set of handlers for each gRPC status code encountered. Serious errors are reported as error traces à la the newrelic.NoticeError function, while the others are reported but not counted as errors.

If you wish to change this behavior, you may do so at a global level for all intercepted functions by calling the Configure function, passing any number of WithStatusHandler(code, handler) functions as parameters.

You can specify a custom set of handlers with each interceptor creation by adding WithStatusHandler calls at the end of the <type>StreamInterceptor call's parameter list, like so:

grpc.UnaryInterceptor(nrgrpc.UnaryServerInterceptor(app,
  nrgrpc.WithStatusHandler(codes.OutOfRange, nrgrpc.WarningInterceptorStatusHandler),
  nrgrpc.WithStatusHandler(codes.Unimplemented, nrgrpc.InfoInterceptorStatusHandler)))

In this case, those two handlers are used (along with the current defaults for the other status codes) only for that interceptor.

func WarningInterceptorStatusHandler

func WarningInterceptorStatusHandler(ctx context.Context, txn *newrelic.Transaction, s *status.Status)

WarningInterceptorStatusHandler is our standard handler for gRPC statuses which we want to report as warnings.

Reports the transaction's status with attributes containing information gleaned from the error value returned, but does not count this as an error.

Types

type ErrorHandler

type ErrorHandler func(context.Context, *newrelic.Transaction, *status.Status)

ErrorHandler is the type of a gRPC status handler function. Normally the supplied set of ErrorHandler functions will suffice, but a custom handler may be crafted by the user and installed as a handler if needed.

type HandlerOption

type HandlerOption func(statusHandlerMap)

HandlerOption is the type for options passed to the interceptor functions to specify gRPC status handlers.

func WithStatusHandler

func WithStatusHandler(c codes.Code, h ErrorHandler) HandlerOption

WithStatusHandler indicates a handler function to be used to report the indicated gRPC status. Zero or more of these may be given to the Configure, StreamServiceInterceptor, or UnaryServiceInterceptor functions.

The ErrorHandler parameter is generally one of the provided standard reporting functions:

OKInterceptorStatusHandler      // report the operation as successful
ErrorInterceptorStatusHandler   // report the operation as an error
WarningInterceptorStatusHandler // report the operation as a warning
InfoInterceptorStatusHandler    // report the operation as an informational message

The following reporting function should only be used if you know for sure you want this. It does not report the error in any way at all, but completely ignores it.

IgnoreInterceptorStatusHandler  // report the operation as successful

Finally, if you have a custom reporting need that isn't covered by the standard handler functions, you can create your own handler function as

func myHandler(ctx context.Context, txn *newrelic.Transaction, s *status.Status) {
   ...
}

Within the function, do whatever you need to do with the txn parameter to report the gRPC status passed as s. If needed, the context is also passed to your function.

If you wish to use your custom handler for a code such as codes.NotFound, you would include the parameter

WithStatusHandler(codes.NotFound, myHandler)

to your Configure, StreamServiceInterceptor, or UnaryServiceInterceptor function.

Directories

Path Synopsis
example

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL