...

Source file src/github.com/grpc-ecosystem/go-grpc-middleware/logging/logrus/options.go

Documentation: github.com/grpc-ecosystem/go-grpc-middleware/logging/logrus

     1  // Copyright 2017 Michal Witkowski. All Rights Reserved.
     2  // See LICENSE for licensing terms.
     3  
     4  package grpc_logrus
     5  
     6  import (
     7  	"context"
     8  	"time"
     9  
    10  	grpc_logging "github.com/grpc-ecosystem/go-grpc-middleware/logging"
    11  	"github.com/grpc-ecosystem/go-grpc-middleware/logging/logrus/ctxlogrus"
    12  	"github.com/sirupsen/logrus"
    13  	"google.golang.org/grpc/codes"
    14  )
    15  
    16  var (
    17  	defaultOptions = &options{
    18  		levelFunc:       nil,
    19  		shouldLog:       grpc_logging.DefaultDeciderMethod,
    20  		codeFunc:        grpc_logging.DefaultErrorToCode,
    21  		durationFunc:    DefaultDurationToField,
    22  		messageFunc:     DefaultMessageProducer,
    23  		timestampFormat: time.RFC3339,
    24  	}
    25  )
    26  
    27  type options struct {
    28  	levelFunc       CodeToLevel
    29  	shouldLog       grpc_logging.Decider
    30  	codeFunc        grpc_logging.ErrorToCode
    31  	durationFunc    DurationToField
    32  	messageFunc     MessageProducer
    33  	timestampFormat string
    34  }
    35  
    36  func evaluateServerOpt(opts []Option) *options {
    37  	optCopy := &options{}
    38  	*optCopy = *defaultOptions
    39  	optCopy.levelFunc = DefaultCodeToLevel
    40  	for _, o := range opts {
    41  		o(optCopy)
    42  	}
    43  	return optCopy
    44  }
    45  
    46  func evaluateClientOpt(opts []Option) *options {
    47  	optCopy := &options{}
    48  	*optCopy = *defaultOptions
    49  	optCopy.levelFunc = DefaultClientCodeToLevel
    50  	for _, o := range opts {
    51  		o(optCopy)
    52  	}
    53  	return optCopy
    54  }
    55  
    56  type Option func(*options)
    57  
    58  // CodeToLevel function defines the mapping between gRPC return codes and interceptor log level.
    59  type CodeToLevel func(code codes.Code) logrus.Level
    60  
    61  // DurationToField function defines how to produce duration fields for logging
    62  type DurationToField func(duration time.Duration) (key string, value interface{})
    63  
    64  // WithDecider customizes the function for deciding if the gRPC interceptor logs should log.
    65  func WithDecider(f grpc_logging.Decider) Option {
    66  	return func(o *options) {
    67  		o.shouldLog = f
    68  	}
    69  }
    70  
    71  // WithLevels customizes the function for mapping gRPC return codes and interceptor log level statements.
    72  func WithLevels(f CodeToLevel) Option {
    73  	return func(o *options) {
    74  		o.levelFunc = f
    75  	}
    76  }
    77  
    78  // WithCodes customizes the function for mapping errors to error codes.
    79  func WithCodes(f grpc_logging.ErrorToCode) Option {
    80  	return func(o *options) {
    81  		o.codeFunc = f
    82  	}
    83  }
    84  
    85  // WithDurationField customizes the function for mapping request durations to log fields.
    86  func WithDurationField(f DurationToField) Option {
    87  	return func(o *options) {
    88  		o.durationFunc = f
    89  	}
    90  }
    91  
    92  // WithMessageProducer customizes the function for message formation.
    93  func WithMessageProducer(f MessageProducer) Option {
    94  	return func(o *options) {
    95  		o.messageFunc = f
    96  	}
    97  }
    98  
    99  // WithTimestampFormat customizes the timestamps emitted in the log fields.
   100  func WithTimestampFormat(format string) Option {
   101  	return func(o *options) {
   102  		o.timestampFormat = format
   103  	}
   104  }
   105  
   106  // DefaultCodeToLevel is the default implementation of gRPC return codes to log levels for server side.
   107  func DefaultCodeToLevel(code codes.Code) logrus.Level {
   108  	switch code {
   109  	case codes.OK:
   110  		return logrus.InfoLevel
   111  	case codes.Canceled:
   112  		return logrus.InfoLevel
   113  	case codes.Unknown:
   114  		return logrus.ErrorLevel
   115  	case codes.InvalidArgument:
   116  		return logrus.InfoLevel
   117  	case codes.DeadlineExceeded:
   118  		return logrus.WarnLevel
   119  	case codes.NotFound:
   120  		return logrus.InfoLevel
   121  	case codes.AlreadyExists:
   122  		return logrus.InfoLevel
   123  	case codes.PermissionDenied:
   124  		return logrus.WarnLevel
   125  	case codes.Unauthenticated:
   126  		return logrus.InfoLevel // unauthenticated requests can happen
   127  	case codes.ResourceExhausted:
   128  		return logrus.WarnLevel
   129  	case codes.FailedPrecondition:
   130  		return logrus.WarnLevel
   131  	case codes.Aborted:
   132  		return logrus.WarnLevel
   133  	case codes.OutOfRange:
   134  		return logrus.WarnLevel
   135  	case codes.Unimplemented:
   136  		return logrus.ErrorLevel
   137  	case codes.Internal:
   138  		return logrus.ErrorLevel
   139  	case codes.Unavailable:
   140  		return logrus.WarnLevel
   141  	case codes.DataLoss:
   142  		return logrus.ErrorLevel
   143  	default:
   144  		return logrus.ErrorLevel
   145  	}
   146  }
   147  
   148  // DefaultClientCodeToLevel is the default implementation of gRPC return codes to log levels for client side.
   149  func DefaultClientCodeToLevel(code codes.Code) logrus.Level {
   150  	switch code {
   151  	case codes.OK:
   152  		return logrus.DebugLevel
   153  	case codes.Canceled:
   154  		return logrus.DebugLevel
   155  	case codes.Unknown:
   156  		return logrus.InfoLevel
   157  	case codes.InvalidArgument:
   158  		return logrus.DebugLevel
   159  	case codes.DeadlineExceeded:
   160  		return logrus.InfoLevel
   161  	case codes.NotFound:
   162  		return logrus.DebugLevel
   163  	case codes.AlreadyExists:
   164  		return logrus.DebugLevel
   165  	case codes.PermissionDenied:
   166  		return logrus.InfoLevel
   167  	case codes.Unauthenticated:
   168  		return logrus.InfoLevel // unauthenticated requests can happen
   169  	case codes.ResourceExhausted:
   170  		return logrus.DebugLevel
   171  	case codes.FailedPrecondition:
   172  		return logrus.DebugLevel
   173  	case codes.Aborted:
   174  		return logrus.DebugLevel
   175  	case codes.OutOfRange:
   176  		return logrus.DebugLevel
   177  	case codes.Unimplemented:
   178  		return logrus.WarnLevel
   179  	case codes.Internal:
   180  		return logrus.WarnLevel
   181  	case codes.Unavailable:
   182  		return logrus.WarnLevel
   183  	case codes.DataLoss:
   184  		return logrus.WarnLevel
   185  	default:
   186  		return logrus.InfoLevel
   187  	}
   188  }
   189  
   190  // DefaultDurationToField is the default implementation of converting request duration to a log field (key and value).
   191  var DefaultDurationToField = DurationToTimeMillisField
   192  
   193  // DurationToTimeMillisField converts the duration to milliseconds and uses the key `grpc.time_ms`.
   194  func DurationToTimeMillisField(duration time.Duration) (key string, value interface{}) {
   195  	return "grpc.time_ms", durationToMilliseconds(duration)
   196  }
   197  
   198  // DurationToDurationField uses the duration value to log the request duration.
   199  func DurationToDurationField(duration time.Duration) (key string, value interface{}) {
   200  	return "grpc.duration", duration
   201  }
   202  
   203  func durationToMilliseconds(duration time.Duration) float32 {
   204  	return float32(duration.Nanoseconds()/1000) / 1000
   205  }
   206  
   207  // MessageProducer produces a user defined log message
   208  type MessageProducer func(ctx context.Context, format string, level logrus.Level, code codes.Code, err error, fields logrus.Fields)
   209  
   210  // DefaultMessageProducer writes the default message
   211  func DefaultMessageProducer(ctx context.Context, format string, level logrus.Level, code codes.Code, err error, fields logrus.Fields) {
   212  	if err != nil {
   213  		fields[logrus.ErrorKey] = err
   214  	}
   215  	entry := ctxlogrus.Extract(ctx).WithContext(ctx).WithFields(fields)
   216  	switch level {
   217  	case logrus.DebugLevel:
   218  		entry.Debugf(format)
   219  	case logrus.InfoLevel:
   220  		entry.Infof(format)
   221  	case logrus.WarnLevel:
   222  		entry.Warningf(format)
   223  	case logrus.ErrorLevel:
   224  		entry.Errorf(format)
   225  	case logrus.FatalLevel:
   226  		entry.Fatalf(format)
   227  	case logrus.PanicLevel:
   228  		entry.Panicf(format)
   229  	}
   230  }
   231  

View as plain text