-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathrequest_logger.go
97 lines (80 loc) · 2.71 KB
/
request_logger.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
package hrpc
import (
"context"
"fmt"
"time"
grpc_logging "github.com/grpc-ecosystem/go-grpc-middleware/logging"
"github.com/kamva/hexa"
"github.com/kamva/hexa/hlog"
"google.golang.org/grpc"
)
//-------------------------------------------
// Inspired from gRPC-ecosystem and kit logger
//--------------------------------------------
// RequestLogger implements gRPC interceptor to log each request
type RequestLogger struct {
logger hlog.Logger
logRequest bool
logResponse bool
}
// DurationFormatter get a duration and return formatted duration as
// key (name of field that should log) and value(formatted time)
type DurationFormatter func(duration time.Duration) hexa.Map
type LoggerOptions struct {
ErrorToCode grpc_logging.ErrorToCode
ShouldLog grpc_logging.Decider
DurationFormatter DurationFormatter
LogRequest bool
LogResponse bool
}
func DefaultLoggerOptions(logRequestResponse bool) LoggerOptions {
return LoggerOptions{
ErrorToCode: grpc_logging.DefaultErrorToCode,
ShouldLog: grpc_logging.DefaultDeciderMethod,
DurationFormatter: DurationToTimeMillisFormatter,
LogRequest: logRequestResponse,
LogResponse: logRequestResponse,
}
}
// DurationToTimeMillisFormatter converts the duration to milliseconds.
func DurationToTimeMillisFormatter(duration time.Duration) hexa.Map {
return hexa.Map{"grpc.time_ms": fmt.Sprint(durationToMilliseconds(duration))}
}
func durationToMilliseconds(duration time.Duration) float32 {
return float32(duration.Nanoseconds()/1000) / 1000
}
func (l *RequestLogger) UnaryServerInterceptor(o LoggerOptions) grpc.UnaryServerInterceptor {
return func(ctx context.Context, req interface{}, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (resp interface{}, err error) {
startTime := time.Now()
resp, err = handler(ctx, req)
if !o.ShouldLog(info.FullMethod, err) {
return resp, err
}
code := o.ErrorToCode(err)
o.DurationFormatter(time.Since(startTime))
fields := []hlog.Field{
hlog.Uint32("code", uint32(code)),
hlog.String("full_method", info.FullMethod),
}
if err != nil {
fields = append(fields, hlog.Err(err))
}
if o.LogRequest {
fields = append(fields, hlog.Any("request", req))
}
if o.LogResponse {
fields = append(fields, hlog.Any("resp", resp))
}
fields = append(fields, hlog.MapToFields(o.DurationFormatter(time.Since(startTime)))...)
logger := hexa.CtxLogger(ctx)
if logger == nil {
logger = l.logger
}
logger.With(fields...).Info("finished unary call with code " + code.String())
return resp, err
}
}
// NewRequestLogger returns new instance of the RequestLogger
func NewRequestLogger(l hlog.Logger) *RequestLogger {
return &RequestLogger{logger: l}
}