...
1 package kit
2
3 import (
4 "time"
5
6 "github.com/go-kit/log"
7 "github.com/go-kit/log/level"
8 grpc_logging "github.com/grpc-ecosystem/go-grpc-middleware/logging"
9 "google.golang.org/grpc/codes"
10 )
11
12 var (
13 defaultOptions = &options{
14 shouldLog: grpc_logging.DefaultDeciderMethod,
15 codeFunc: grpc_logging.DefaultErrorToCode,
16 durationFunc: DefaultDurationToField,
17 timestampFormat: time.RFC3339,
18 }
19 )
20
21 type options struct {
22 levelFunc CodeToLevel
23 shouldLog grpc_logging.Decider
24 codeFunc grpc_logging.ErrorToCode
25 durationFunc DurationToField
26 timestampFormat string
27 }
28
29 type Option func(*options)
30
31
32 type CodeToLevel func(code codes.Code, logger log.Logger) log.Logger
33
34
35 type DurationToField func(duration time.Duration) []interface{}
36
37 func evaluateServerOpt(opts []Option) *options {
38 optCopy := &options{}
39 *optCopy = *defaultOptions
40 optCopy.levelFunc = DefaultCodeToLevel
41 for _, o := range opts {
42 o(optCopy)
43 }
44 return optCopy
45 }
46
47 func evaluateClientOpt(opts []Option) *options {
48 optCopy := &options{}
49 *optCopy = *defaultOptions
50 optCopy.levelFunc = DefaultClientCodeToLevel
51 for _, o := range opts {
52 o(optCopy)
53 }
54 return optCopy
55 }
56
57
58 func WithDecider(f grpc_logging.Decider) Option {
59 return func(o *options) {
60 o.shouldLog = f
61 }
62 }
63
64
65 func WithLevels(f CodeToLevel) Option {
66 return func(o *options) {
67 o.levelFunc = f
68 }
69 }
70
71
72 func WithCodes(f grpc_logging.ErrorToCode) Option {
73 return func(o *options) {
74 o.codeFunc = f
75 }
76 }
77
78
79 func WithDurationField(f DurationToField) Option {
80 return func(o *options) {
81 o.durationFunc = f
82 }
83 }
84
85
86 func WithTimestampFormat(format string) Option {
87 return func(o *options) {
88 o.timestampFormat = format
89 }
90 }
91
92
93 func DefaultCodeToLevel(code codes.Code, logger log.Logger) log.Logger {
94 switch code {
95 case codes.OK, codes.Canceled, codes.InvalidArgument, codes.NotFound, codes.AlreadyExists, codes.Unauthenticated:
96 return level.Info(logger)
97 case codes.DeadlineExceeded, codes.PermissionDenied, codes.ResourceExhausted, codes.FailedPrecondition, codes.Aborted, codes.OutOfRange, codes.Unavailable:
98 return level.Warn(logger)
99 case codes.Unknown, codes.Unimplemented, codes.Internal, codes.DataLoss:
100 return level.Error(logger)
101 default:
102 return level.Error(logger)
103 }
104 }
105
106
107 func DefaultClientCodeToLevel(code codes.Code, logger log.Logger) log.Logger {
108 switch code {
109 case codes.OK, codes.Canceled, codes.InvalidArgument, codes.NotFound, codes.AlreadyExists, codes.ResourceExhausted, codes.FailedPrecondition, codes.Aborted, codes.OutOfRange:
110 return level.Debug(logger)
111 case codes.Unknown, codes.DeadlineExceeded, codes.PermissionDenied, codes.Unauthenticated:
112 return level.Info(logger)
113 case codes.Unimplemented, codes.Internal, codes.Unavailable, codes.DataLoss:
114 return level.Warn(logger)
115 default:
116 return level.Info(logger)
117 }
118 }
119
120
121 var DefaultDurationToField = DurationToTimeMillisField
122
123
124 func DurationToTimeMillisField(duration time.Duration) []interface{} {
125 return []interface{}{"grpc.time_ms", durationToMilliseconds(duration)}
126 }
127
128
129
130 func DurationToDurationField(duration time.Duration) []interface{} {
131 return []interface{}{"grpc.duration", duration}
132 }
133
134 func durationToMilliseconds(duration time.Duration) float32 {
135 return float32(duration.Nanoseconds()/1000) / 1000
136 }
137
View as plain text