-
Notifications
You must be signed in to change notification settings - Fork 5
/
middleware.go
131 lines (113 loc) · 3.24 KB
/
middleware.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
package loggingmiddleware
import (
"context"
"fmt"
"time"
"github.com/arquivei/foundationkit/errors"
"github.com/arquivei/foundationkit/gokitmiddlewares"
logutil "github.com/arquivei/foundationkit/log"
"github.com/go-kit/kit/endpoint"
"github.com/rs/zerolog"
"github.com/rs/zerolog/log"
)
// MustNew calls New and panics in case of error.
func MustNew(c Config) endpoint.Middleware {
return gokitmiddlewares.Must(New(c))
}
// New returns a new go-kit logging middleware with the given name and configuration.
//
// Fields Config.Name and Config.Logger are mandatory.
// Considering that this middleware puts a logger inside the context, this should always
// be the outter middleware when using endpoint.Chain.
func New(c Config) (endpoint.Middleware, error) {
if c.Name == "" {
return nil, errors.New("endpoint name is empty")
}
if c.Logger == nil {
return nil, errors.New("logger is nil")
}
return func(next endpoint.Endpoint) endpoint.Endpoint {
log.Debug().Str("config", logutil.Flatten(c)).Msg("New logging endpoint middleware")
return func(ctx context.Context, req interface{}) (resp interface{}, err error) {
begin := time.Now()
ctx = initLoggerContext(ctx, *c.Logger)
l := log.Ctx(ctx)
enrichLoggerContext(ctx, l, c, req)
ctx = doCustomEnrichRequest(ctx, c, l, req)
defer func() {
var r interface{}
// Panics are handled as errors and re-raised
if r = recover(); r != nil {
err = errors.NewFromRecover(r)
log.Ctx(ctx).Warn().Err(err).
Msg("Logging endpoint middleware is handling an uncaught a panic. Please fix it!")
}
enrichLoggerAfterResponse(l, c, begin, resp)
doCustomEnrichResponse(ctx, c, l, resp, err)
doLogging(l, c, err)
if r != nil {
panic(r)
}
}()
return next(ctx, req)
}
}, nil
}
func doLogging(l *zerolog.Logger, c Config, err error) {
if err != nil {
l.WithLevel(getErrorLevel(c, err)).
Err(err).
EmbedObject(errors.GetCode(err)).
EmbedObject(errors.GetSeverity(err)).
Msg("Request failed")
return
}
l.WithLevel(c.SuccessLevel).Msg("Request successful")
}
func toString(i interface{}, n int) string {
s := fmt.Sprintf("%#v", i)
if n <= 0 || len(s) <= n {
return s
}
return s[:n]
}
func doCustomEnrichRequest(
ctx context.Context,
config Config,
logger *zerolog.Logger,
request interface{},
) context.Context {
if typedReq, ok := request.(LoggableEndpointRequest); ok {
logger.UpdateContext(func(zctx zerolog.Context) zerolog.Context {
ctx, zctx = typedReq.EnrichLog(ctx, zctx)
return zctx
})
}
if config.EnrichLogWithRequest != nil {
logger.UpdateContext(func(zctx zerolog.Context) zerolog.Context {
ctx, zctx = config.EnrichLogWithRequest(ctx, zctx, request)
return zctx
})
}
return ctx
}
func doCustomEnrichResponse(
ctx context.Context,
config Config,
logger *zerolog.Logger,
response interface{},
err error,
) {
if typedReq, ok := response.(LoggableEndpointResponse); ok {
logger.UpdateContext(func(zctx zerolog.Context) zerolog.Context {
zctx = typedReq.EnrichLog(ctx, zctx)
return zctx
})
}
if config.EnrichLogWithResponse != nil {
logger.UpdateContext(func(zctx zerolog.Context) zerolog.Context {
zctx = config.EnrichLogWithResponse(ctx, zctx, response, err)
return zctx
})
}
}