package grpc_logrus_test import ( "time" "github.com/grpc-ecosystem/go-grpc-middleware" "github.com/grpc-ecosystem/go-grpc-middleware/logging/logrus" "github.com/grpc-ecosystem/go-grpc-middleware/tags" "github.com/grpc-ecosystem/go-grpc-middleware/tags/logrus" pb_testproto "github.com/grpc-ecosystem/go-grpc-middleware/testing/testproto" "github.com/sirupsen/logrus" "golang.org/x/net/context" "google.golang.org/grpc" ) var ( logrusLogger *logrus.Logger customFunc grpc_logrus.CodeToLevel ) // Initialization shows a relatively complex initialization sequence. func Example_initialization() { // Logrus entry is used, allowing pre-definition of certain fields by the user. logrusEntry := logrus.NewEntry(logrusLogger) // Shared options for the logger, with a custom gRPC code to log level function. opts := []grpc_logrus.Option{ grpc_logrus.WithLevels(customFunc), } // Make sure that log statements internal to gRPC library are logged using the logrus Logger as well. grpc_logrus.ReplaceGrpcLogger(logrusEntry) // Create a server, make sure we put the grpc_ctxtags context before everything else. _ = grpc.NewServer( grpc_middleware.WithUnaryServerChain( grpc_ctxtags.UnaryServerInterceptor(grpc_ctxtags.WithFieldExtractor(grpc_ctxtags.CodeGenRequestFieldExtractor)), grpc_logrus.UnaryServerInterceptor(logrusEntry, opts...), ), grpc_middleware.WithStreamServerChain( grpc_ctxtags.StreamServerInterceptor(grpc_ctxtags.WithFieldExtractor(grpc_ctxtags.CodeGenRequestFieldExtractor)), grpc_logrus.StreamServerInterceptor(logrusEntry, opts...), ), ) } func Example_initializationWithDurationFieldOverride() { // Logrus entry is used, allowing pre-definition of certain fields by the user. logrusEntry := logrus.NewEntry(logrusLogger) // Shared options for the logger, with a custom duration to log field function. opts := []grpc_logrus.Option{ grpc_logrus.WithDurationField(func(duration time.Duration) (key string, value interface{}) { return "grpc.time_ns", duration.Nanoseconds() }), } _ = grpc.NewServer( grpc_middleware.WithUnaryServerChain( grpc_ctxtags.UnaryServerInterceptor(), grpc_logrus.UnaryServerInterceptor(logrusEntry, opts...), ), grpc_middleware.WithStreamServerChain( grpc_ctxtags.StreamServerInterceptor(), grpc_logrus.StreamServerInterceptor(logrusEntry, opts...), ), ) } // Simple unary handler that adds custom fields to the requests's context. These will be used for all log statements. func ExampleExtract_unary() { _ = func(ctx context.Context, ping *pb_testproto.PingRequest) (*pb_testproto.PingResponse, error) { // Add fields the ctxtags of the request which will be added to all extracted loggers. grpc_ctxtags.Extract(ctx).Set("custom_tags.string", "something").Set("custom_tags.int", 1337) // Extract a single request-scoped logrus.Logger and log messages. l := ctx_logrus.Extract(ctx) l.Info("some ping") l.Info("another ping") return &pb_testproto.PingResponse{Value: ping.Value}, nil } } func ExampleWithDecider() { opts := []grpc_logrus.Option{ grpc_logrus.WithDecider(func(methodFullName string, err error) bool { // will not log gRPC calls if it was a call to healthcheck and no error was raised if err == nil && methodFullName == "blah.foo.healthcheck" { return false } // by default you will log all calls return true }), } _ = []grpc.ServerOption{ grpc_middleware.WithStreamServerChain( grpc_ctxtags.StreamServerInterceptor(), grpc_logrus.StreamServerInterceptor(logrus.NewEntry(logrus.New()), opts...)), grpc_middleware.WithUnaryServerChain( grpc_ctxtags.UnaryServerInterceptor(), grpc_logrus.UnaryServerInterceptor(logrus.NewEntry(logrus.New()), opts...)), } }