-
Notifications
You must be signed in to change notification settings - Fork 0
/
grpc.go
162 lines (141 loc) · 3.71 KB
/
grpc.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
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
package accesslog
import (
"context"
"encoding/json"
"io"
"os"
"time"
"github.com/golang/protobuf/jsonpb"
"github.com/golang/protobuf/proto"
"github.com/rs/zerolog"
"google.golang.org/grpc"
"google.golang.org/grpc/metadata"
"google.golang.org/grpc/peer"
"google.golang.org/grpc/status"
)
// DefaultGRPCLogger is default gRPC Logger.
var DefaultGRPCLogger = NewGRPCLogger(os.Stdout, NewDefaultGRPCLogFormatter())
// GRPCLogger is logger for gRPC access logging.
type GRPCLogger struct {
l *zerolog.Logger
f GRPCLogFormatter
}
// NewGRPCLogger returns a new GRPCLogger.
func NewGRPCLogger(w io.Writer, f GRPCLogFormatter) *GRPCLogger {
l := zerolog.New(w)
return &GRPCLogger{
l: &l,
f: f,
}
}
// NewLogEntry returns a New LogEntry.
func (l *GRPCLogger) NewLogEntry(ctx context.Context, req interface{}, res *interface{}, info *grpc.UnaryServerInfo, err *error) LogEntry {
return l.f.NewLogEntry(l.l, ctx, req, res, info, err)
}
// GRPCLogFormatter is the interface for NewLogEntry method.
type GRPCLogFormatter interface {
NewLogEntry(l *zerolog.Logger, ctx context.Context, req interface{}, res *interface{}, info *grpc.UnaryServerInfo, err *error) LogEntry
}
type grpcConfig struct {
ignoredMethods map[string]struct{}
metadata map[string]string
withRequest bool
withResponse bool
withPeer bool
}
// DefaultGRPCLogFormatter is default GRPCLogFormatter.
type DefaultGRPCLogFormatter struct {
cfg *grpcConfig
}
// NewDefaultGRPCLogFormatter returns a new DefaultGRPCLogFormatter.
func NewDefaultGRPCLogFormatter(opts ...grpcOption) *DefaultGRPCLogFormatter {
cfg := new(grpcConfig)
for _, fn := range opts {
fn(cfg)
}
return &DefaultGRPCLogFormatter{cfg: cfg}
}
// NewLogEntry returns a New LogEntry formatted in DefaultGRPCLogFormatter.
func (f *DefaultGRPCLogFormatter) NewLogEntry(l *zerolog.Logger, ctx context.Context, req interface{}, res *interface{}, info *grpc.UnaryServerInfo, err *error) LogEntry {
return &DefaultGRPCLogEntry{
l: l,
cfg: f.cfg,
ctx: ctx,
req: req,
res: res,
info: info,
add: []func(e *zerolog.Event){},
err: err,
}
}
// DefaultGRPCLogEntry is the LogEntry formatted in DefaultGRPCLogFormatter.
type DefaultGRPCLogEntry struct {
l *zerolog.Logger
cfg *grpcConfig
ctx context.Context
req interface{}
res *interface{}
info *grpc.UnaryServerInfo
err *error
add []func(e *zerolog.Event)
}
// Add adds function for adding fields to log event.
func (le *DefaultGRPCLogEntry) Add(f func(e *zerolog.Event)) {
if le == nil {
return
}
le.add = append(le.add, f)
}
// Write writes a log.
func (le *DefaultGRPCLogEntry) Write(t time.Time) {
if _, ok := le.cfg.ignoredMethods[le.info.FullMethod]; ok {
return
}
e := le.l.Log().
Str("protocol", "grpc").
Str("method", le.info.FullMethod).
Str("status", status.Code(*le.err).String()).
Str("time", t.UTC().Format(time.RFC3339Nano)).
Dur("elapsed(ms)", time.Since(t))
if wm := le.cfg.metadata; len(wm) != 0 {
if md, ok := metadata.FromIncomingContext(le.ctx); ok {
for m, a := range wm {
if ms := md.Get(m); len(ms) != 0 {
b, err := json.Marshal(ms)
if err == nil {
n := m
if a != "" {
n = a
}
e.Str(n, string(b))
}
}
}
}
}
if le.cfg.withPeer {
if p, ok := peer.FromContext(le.ctx); ok {
e.Str("peer", p.Addr.String())
}
}
if le.cfg.withRequest {
var m jsonpb.Marshaler
if p, ok := le.req.(proto.Message); ok {
if s, err := m.MarshalToString(p); err == nil {
e.Str("req", s)
}
}
}
if le.cfg.withResponse {
var m jsonpb.Marshaler
if p, ok := (*le.res).(proto.Message); ok {
if s, err := m.MarshalToString(p); err == nil {
e.Str("res", s)
}
}
}
for _, f := range le.add {
f(e)
}
e.Send()
}