Documentation ¶
Overview ¶
`grpc_logrus` is a gRPC logging middleware backed by Logrus loggers
It accepts a user-configured `logrus.Entry` that will be used for logging completed gRPC calls. The same `logrus.Entry` will be used for logging completed gRPC calls, and be populated into the `context.Context` passed into gRPC handler code.
You can use `Extract` to log into a request-scoped `logrus.Entry` instance in your handler code. The fields set on the logger correspond to the grpc_ctxtags.Tags attached to the context.
This package also implements request and response *payload* logging, both for server-side and client-side. These will be logged as structured `jsonbp` fields for every message received/sent (both unary and streaming). For that please use `Payload*Interceptor` functions for that. Please note that the user-provided function that determines whetether to log the full request/response payload needs to be written with care, this can significantly slow down gRPC.
Logrus can also be made as a backend for gRPC library internals. For that use `ReplaceGrpcLogger`.
Please see examples and tests for examples of use.
Example (HandlerUsageUnaryPing) ¶
Simple unary handler that adds custom fields to the requests's context. These will be used for all log statements.
package main import ( "time" "github.com/grpc-ecosystem/go-grpc-middleware/logging/logrus" "github.com/sirupsen/logrus" "github.com/grpc-ecosystem/go-grpc-middleware" "github.com/grpc-ecosystem/go-grpc-middleware/tags" pb_testproto "github.com/grpc-ecosystem/go-grpc-middleware/testing/testproto" "golang.org/x/net/context" "google.golang.org/grpc" ) // Initialization shows a relatively complex initialization sequence. func main(logrusLogger *logrus.Logger, customFunc grpc_logrus.CodeToLevel) *grpc.Server { // 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 zapLogger as well. grpc_logrus.ReplaceGrpcLogger(logrusEntry) // Create a server, make sure we put the grpc_ctxtags context before everything else. server := 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...), ), ) return server } func main(logrusLogger *logrus.Logger) *grpc.Server { // 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() }), } server := grpc.NewServer( grpc_middleware.WithUnaryServerChain( grpc_ctxtags.UnaryServerInterceptor(), grpc_logrus.UnaryServerInterceptor(logrusEntry, opts...), ), grpc_middleware.WithStreamServerChain( grpc_ctxtags.StreamServerInterceptor(), grpc_logrus.StreamServerInterceptor(logrusEntry, opts...), ), ) return server } // Simple unary handler that adds custom fields to the requests's context. These will be used for all log statements. func main() interface{} { x := 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 request-scoped zap.Logger and log a message. grpc_logrus.Extract(ctx).Info("some ping") return &pb_testproto.PingResponse{Value: ping.Value}, nil } return x }
Output:
Index ¶
- Variables
- func DefaultClientCodeToLevel(code codes.Code) logrus.Level
- func DefaultCodeToLevel(code codes.Code) logrus.Level
- func DurationToDurationField(duration time.Duration) (key string, value interface{})
- func DurationToTimeMillisField(duration time.Duration) (key string, value interface{})
- func Extract(ctx context.Context) *logrus.Entry
- func PayloadStreamClientInterceptor(entry *logrus.Entry, decider grpc_logging.ClientPayloadLoggingDecider) grpc.StreamClientInterceptor
- func PayloadStreamServerInterceptor(entry *logrus.Entry, decider grpc_logging.ServerPayloadLoggingDecider) grpc.StreamServerInterceptor
- func PayloadUnaryClientInterceptor(entry *logrus.Entry, decider grpc_logging.ClientPayloadLoggingDecider) grpc.UnaryClientInterceptor
- func PayloadUnaryServerInterceptor(entry *logrus.Entry, decider grpc_logging.ServerPayloadLoggingDecider) grpc.UnaryServerInterceptor
- func ReplaceGrpcLogger(logger *logrus.Entry)
- func StreamClientInterceptor(entry *logrus.Entry, opts ...Option) grpc.StreamClientInterceptor
- func StreamServerInterceptor(entry *logrus.Entry, opts ...Option) grpc.StreamServerInterceptor
- func UnaryClientInterceptor(entry *logrus.Entry, opts ...Option) grpc.UnaryClientInterceptor
- func UnaryServerInterceptor(entry *logrus.Entry, opts ...Option) grpc.UnaryServerInterceptor
- type CodeToLevel
- type DurationToField
- type Option
Examples ¶
Constants ¶
This section is empty.
Variables ¶
var ( // SystemField is used in every log statement made through grpc_logrus. Can be overwritten before any initialization code. SystemField = "system" // KindField describes the log gield used to incicate whether this is a server or a client log statment. KindField = "span.kind" )
var DefaultDurationToField = DurationToTimeMillisField
DefaultDurationToField is the default implementation of converting request duration to a log field (key and value).
var ( // JsonPBMarshaller is the marshaller used for serializing protobuf messages. JsonPbMarshaller = &jsonpb.Marshaler{} )
Functions ¶
func DefaultClientCodeToLevel ¶
DefaultClientCodeToLevel is the default implementation of gRPC return codes to log levels for client side.
func DefaultCodeToLevel ¶
DefaultCodeToLevel is the default implementation of gRPC return codes to log levels for server side.
func DurationToDurationField ¶
DurationToDurationField uses the duration value to log the request duration.
func DurationToTimeMillisField ¶
DurationToTimeMillisField converts the duration to milliseconds and uses the key `grpc.time_ms`.
func Extract ¶
Extract takes the call-scoped logrus.Entry from grpc_logrus middleware.
If the grpc_logrus middleware wasn't used, a no-op `logrus.Entry` is returned. This makes it safe to use regardless.
func PayloadStreamClientInterceptor ¶
func PayloadStreamClientInterceptor(entry *logrus.Entry, decider grpc_logging.ClientPayloadLoggingDecider) grpc.StreamClientInterceptor
PayloadStreamServerInterceptor returns a new streaming client interceptor that logs the paylods of requests and responses.
func PayloadStreamServerInterceptor ¶
func PayloadStreamServerInterceptor(entry *logrus.Entry, decider grpc_logging.ServerPayloadLoggingDecider) grpc.StreamServerInterceptor
PayloadUnaryServerInterceptor returns a new server server interceptors that logs the payloads of requests.
This *only* works when placed *after* the `grpc_logrus.StreamServerInterceptor`. However, the logging can be done to a separate instance of the logger.
func PayloadUnaryClientInterceptor ¶
func PayloadUnaryClientInterceptor(entry *logrus.Entry, decider grpc_logging.ClientPayloadLoggingDecider) grpc.UnaryClientInterceptor
PayloadUnaryClientInterceptor returns a new unary client interceptor that logs the paylods of requests and responses.
func PayloadUnaryServerInterceptor ¶
func PayloadUnaryServerInterceptor(entry *logrus.Entry, decider grpc_logging.ServerPayloadLoggingDecider) grpc.UnaryServerInterceptor
PayloadUnaryServerInterceptor returns a new unary server interceptors that logs the payloads of requests.
This *only* works when placed *after* the `grpc_logrus.UnaryServerInterceptor`. However, the logging can be done to a separate instance of the logger.
func ReplaceGrpcLogger ¶
ReplaceGrpcLogger sets the given logrus.Logger as a gRPC-level logger. This should be called *before* any other initialization, preferably from init() functions.
func StreamClientInterceptor ¶
func StreamClientInterceptor(entry *logrus.Entry, opts ...Option) grpc.StreamClientInterceptor
StreamServerInterceptor returns a new streaming client interceptor that optionally logs the execution of external gRPC calls.
func StreamServerInterceptor ¶
func StreamServerInterceptor(entry *logrus.Entry, opts ...Option) grpc.StreamServerInterceptor
StreamServerInterceptor returns a new streaming server interceptor that adds logrus.Entry to the context.
func UnaryClientInterceptor ¶
func UnaryClientInterceptor(entry *logrus.Entry, opts ...Option) grpc.UnaryClientInterceptor
UnaryClientInterceptor returns a new unary client interceptor that optionally logs the execution of external gRPC calls.
func UnaryServerInterceptor ¶
func UnaryServerInterceptor(entry *logrus.Entry, opts ...Option) grpc.UnaryServerInterceptor
PayloadUnaryServerInterceptor returns a new unary server interceptors that adds logrus.Entry to the context.
Types ¶
type CodeToLevel ¶
CodeToLevel function defines the mapping between gRPC return codes and interceptor log level.
type DurationToField ¶
DurationToField function defines how to produce duration fields for logging
type Option ¶
type Option func(*options)
func WithCodes ¶
func WithCodes(f grpc_logging.ErrorToCode) Option
WithCodes customizes the function for mapping errors to error codes.
func WithDurationField ¶
func WithDurationField(f DurationToField) Option
WithDurationField customizes the function for mapping request durations to log fields.
func WithLevels ¶
func WithLevels(f CodeToLevel) Option
WithLevels customizes the function for mapping gRPC return codes and interceptor log level statements.