Files
fn-serverless/vendor/github.com/grpc-ecosystem/go-grpc-middleware/logging/logrus/options.go
Andrea Rosa e637661ea2 Adding a way to inject a request ID (#1046)
* Adding a way to inject a request ID

It is very useful to associate a request ID to each incoming request,
this change allows to provide a function to do that via Server Option.
The change comes with a default function which will generate a new
request ID. The request ID is put in the request context along with a
common logger which always logs the request-id

We add gRPC interceptors to the server so it can get the request ID out
of the gRPC metadata and put it in the common logger stored in the
context so as all the log lines using the common logger from the context
will have the request ID logged
2018-06-14 10:40:55 +01:00

186 lines
5.0 KiB
Go

// Copyright 2017 Michal Witkowski. All Rights Reserved.
// See LICENSE for licensing terms.
package grpc_logrus
import (
"time"
"github.com/grpc-ecosystem/go-grpc-middleware/logging"
"github.com/sirupsen/logrus"
"google.golang.org/grpc/codes"
)
var (
defaultOptions = &options{
levelFunc: nil,
shouldLog: grpc_logging.DefaultDeciderMethod,
codeFunc: grpc_logging.DefaultErrorToCode,
durationFunc: DefaultDurationToField,
}
)
type options struct {
levelFunc CodeToLevel
shouldLog grpc_logging.Decider
codeFunc grpc_logging.ErrorToCode
durationFunc DurationToField
}
func evaluateServerOpt(opts []Option) *options {
optCopy := &options{}
*optCopy = *defaultOptions
optCopy.levelFunc = DefaultCodeToLevel
for _, o := range opts {
o(optCopy)
}
return optCopy
}
func evaluateClientOpt(opts []Option) *options {
optCopy := &options{}
*optCopy = *defaultOptions
optCopy.levelFunc = DefaultClientCodeToLevel
for _, o := range opts {
o(optCopy)
}
return optCopy
}
type Option func(*options)
// CodeToLevel function defines the mapping between gRPC return codes and interceptor log level.
type CodeToLevel func(code codes.Code) logrus.Level
// DurationToField function defines how to produce duration fields for logging
type DurationToField func(duration time.Duration) (key string, value interface{})
// WithDecider customizes the function for deciding if the gRPC interceptor logs should log.
func WithDecider(f grpc_logging.Decider) Option {
return func(o *options) {
o.shouldLog = f
}
}
// WithLevels customizes the function for mapping gRPC return codes and interceptor log level statements.
func WithLevels(f CodeToLevel) Option {
return func(o *options) {
o.levelFunc = f
}
}
// WithCodes customizes the function for mapping errors to error codes.
func WithCodes(f grpc_logging.ErrorToCode) Option {
return func(o *options) {
o.codeFunc = f
}
}
// WithDurationField customizes the function for mapping request durations to log fields.
func WithDurationField(f DurationToField) Option {
return func(o *options) {
o.durationFunc = f
}
}
// DefaultCodeToLevel is the default implementation of gRPC return codes to log levels for server side.
func DefaultCodeToLevel(code codes.Code) logrus.Level {
switch code {
case codes.OK:
return logrus.InfoLevel
case codes.Canceled:
return logrus.InfoLevel
case codes.Unknown:
return logrus.ErrorLevel
case codes.InvalidArgument:
return logrus.InfoLevel
case codes.DeadlineExceeded:
return logrus.WarnLevel
case codes.NotFound:
return logrus.InfoLevel
case codes.AlreadyExists:
return logrus.InfoLevel
case codes.PermissionDenied:
return logrus.WarnLevel
case codes.Unauthenticated:
return logrus.InfoLevel // unauthenticated requests can happen
case codes.ResourceExhausted:
return logrus.WarnLevel
case codes.FailedPrecondition:
return logrus.WarnLevel
case codes.Aborted:
return logrus.WarnLevel
case codes.OutOfRange:
return logrus.WarnLevel
case codes.Unimplemented:
return logrus.ErrorLevel
case codes.Internal:
return logrus.ErrorLevel
case codes.Unavailable:
return logrus.WarnLevel
case codes.DataLoss:
return logrus.ErrorLevel
default:
return logrus.ErrorLevel
}
}
// DefaultClientCodeToLevel is the default implementation of gRPC return codes to log levels for client side.
func DefaultClientCodeToLevel(code codes.Code) logrus.Level {
switch code {
case codes.OK:
return logrus.DebugLevel
case codes.Canceled:
return logrus.DebugLevel
case codes.Unknown:
return logrus.InfoLevel
case codes.InvalidArgument:
return logrus.DebugLevel
case codes.DeadlineExceeded:
return logrus.InfoLevel
case codes.NotFound:
return logrus.DebugLevel
case codes.AlreadyExists:
return logrus.DebugLevel
case codes.PermissionDenied:
return logrus.InfoLevel
case codes.Unauthenticated:
return logrus.InfoLevel // unauthenticated requests can happen
case codes.ResourceExhausted:
return logrus.DebugLevel
case codes.FailedPrecondition:
return logrus.DebugLevel
case codes.Aborted:
return logrus.DebugLevel
case codes.OutOfRange:
return logrus.DebugLevel
case codes.Unimplemented:
return logrus.WarnLevel
case codes.Internal:
return logrus.WarnLevel
case codes.Unavailable:
return logrus.WarnLevel
case codes.DataLoss:
return logrus.WarnLevel
default:
return logrus.InfoLevel
}
}
// DefaultDurationToField is the default implementation of converting request duration to a log field (key and value).
var DefaultDurationToField = DurationToTimeMillisField
// DurationToTimeMillisField converts the duration to milliseconds and uses the key `grpc.time_ms`.
func DurationToTimeMillisField(duration time.Duration) (key string, value interface{}) {
return "grpc.time_ms", durationToMilliseconds(duration)
}
// DurationToDurationField uses the duration value to log the request duration.
func DurationToDurationField(duration time.Duration) (key string, value interface{}) {
return "grpc.duration", duration
}
func durationToMilliseconds(duration time.Duration) float32 {
return float32(duration.Nanoseconds()/1000) / 1000
}