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 ¶
- Variables
- func Configure(options ...HandlerOption)
- func ErrorInterceptorStatusHandler(ctx context.Context, txn *newrelic.Transaction, s *status.Status)
- func IgnoreInterceptorStatusHandler(_ context.Context, _ *newrelic.Transaction, _ *status.Status)
- func InfoInterceptorStatusHandler(ctx context.Context, txn *newrelic.Transaction, s *status.Status)
- func OKInterceptorStatusHandler(ctx context.Context, txn *newrelic.Transaction, s *status.Status)
- func StreamClientInterceptor(ctx context.Context, desc *grpc.StreamDesc, cc *grpc.ClientConn, method string, ...) (grpc.ClientStream, error)
- func StreamServerInterceptor(app *newrelic.Application, options ...HandlerOption) grpc.StreamServerInterceptor
- func UnaryClientInterceptor(ctx context.Context, method string, req, reply interface{}, ...) error
- func UnaryServerInterceptor(app *newrelic.Application, options ...HandlerOption) grpc.UnaryServerInterceptor
- func WarningInterceptorStatusHandler(ctx context.Context, txn *newrelic.Transaction, s *status.Status)
- type ErrorHandler
- type HandlerOption
Constants ¶
This section is empty.
Variables ¶
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 ¶
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 ¶
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 ¶
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 ¶
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.