Codebase list golang-github-go-kit-kit / 3c77e8c
Implement transport level error handlers (#863) * Add error handler implementation to the log package * Add error handler to http transport * Add error handler to amqp transport * Add error handler to awslambda transport * Add error handler to grpc transport * Add error handler to nats transport * Move error handler interfaces to transport package * Move log error handler to transport package * Remove error logger precedence * Improve documentation wording * Adjust transport package documentation * Remove ignore error * Update examples * Add context to the error handler signature Márk Sági-Kazár authored 4 years ago Peter Bourgon committed 4 years ago
15 changed file(s) with 161 addition(s) and 50 deletion(s). Raw diff Collapse all Expand all
1717 "github.com/go-kit/kit/ratelimit"
1818 "github.com/go-kit/kit/tracing/opentracing"
1919 "github.com/go-kit/kit/tracing/zipkin"
20 "github.com/go-kit/kit/transport"
2021 grpctransport "github.com/go-kit/kit/transport/grpc"
2122
2223 "github.com/go-kit/kit/examples/addsvc/pb"
4344 zipkinServer := zipkin.GRPCServerTrace(zipkinTracer)
4445
4546 options := []grpctransport.ServerOption{
46 grpctransport.ServerErrorLogger(logger),
47 grpctransport.ServerErrorHandler(transport.NewLogErrorHandler(logger)),
4748 zipkinServer,
4849 }
4950
2222 "github.com/go-kit/kit/ratelimit"
2323 "github.com/go-kit/kit/tracing/opentracing"
2424 "github.com/go-kit/kit/tracing/zipkin"
25 "github.com/go-kit/kit/transport"
2526 httptransport "github.com/go-kit/kit/transport/http"
2627
2728 "github.com/go-kit/kit/examples/addsvc/pkg/addendpoint"
4041
4142 options := []httptransport.ServerOption{
4243 httptransport.ServerErrorEncoder(errorEncoder),
43 httptransport.ServerErrorLogger(logger),
44 httptransport.ServerErrorHandler(transport.NewLogErrorHandler(logger)),
4445 zipkinServer,
4546 }
4647
1313 "github.com/gorilla/mux"
1414
1515 "github.com/go-kit/kit/log"
16 "github.com/go-kit/kit/transport"
1617 httptransport "github.com/go-kit/kit/transport/http"
1718 )
1819
2829 r := mux.NewRouter()
2930 e := MakeServerEndpoints(s)
3031 options := []httptransport.ServerOption{
31 httptransport.ServerErrorLogger(logger),
32 httptransport.ServerErrorHandler(transport.NewLogErrorHandler(logger)),
3233 httptransport.ServerErrorEncoder(encodeError),
3334 }
3435
99 "github.com/gorilla/mux"
1010
1111 kitlog "github.com/go-kit/kit/log"
12 "github.com/go-kit/kit/transport"
1213 kithttp "github.com/go-kit/kit/transport/http"
1314
1415 "github.com/go-kit/kit/examples/shipping/cargo"
1819 // MakeHandler returns a handler for the booking service.
1920 func MakeHandler(bs Service, logger kitlog.Logger) http.Handler {
2021 opts := []kithttp.ServerOption{
21 kithttp.ServerErrorLogger(logger),
22 kithttp.ServerErrorHandler(transport.NewLogErrorHandler(logger)),
2223 kithttp.ServerErrorEncoder(encodeError),
2324 }
2425
88 "github.com/gorilla/mux"
99
1010 kitlog "github.com/go-kit/kit/log"
11 "github.com/go-kit/kit/transport"
1112 kithttp "github.com/go-kit/kit/transport/http"
1213
1314 "github.com/go-kit/kit/examples/shipping/cargo"
2021 r := mux.NewRouter()
2122
2223 opts := []kithttp.ServerOption{
23 kithttp.ServerErrorLogger(logger),
24 kithttp.ServerErrorHandler(transport.NewLogErrorHandler(logger)),
2425 kithttp.ServerErrorEncoder(encodeError),
2526 }
2627
88 "github.com/gorilla/mux"
99
1010 kitlog "github.com/go-kit/kit/log"
11 kittransport "github.com/go-kit/kit/transport"
1112 kithttp "github.com/go-kit/kit/transport/http"
1213
1314 "github.com/go-kit/kit/examples/shipping/cargo"
1819 r := mux.NewRouter()
1920
2021 opts := []kithttp.ServerOption{
21 kithttp.ServerErrorLogger(logger),
22 kithttp.ServerErrorHandler(kittransport.NewLogErrorHandler(logger)),
2223 kithttp.ServerErrorEncoder(encodeError),
2324 }
2425
66
77 "github.com/go-kit/kit/endpoint"
88 "github.com/go-kit/kit/log"
9 "github.com/go-kit/kit/transport"
910 "github.com/streadway/amqp"
1011 )
1112
1819 after []SubscriberResponseFunc
1920 responsePublisher ResponsePublisher
2021 errorEncoder ErrorEncoder
21 logger log.Logger
22 errorHandler transport.ErrorHandler
2223 }
2324
2425 // NewSubscriber constructs a new subscriber, which provides a handler
3536 enc: enc,
3637 responsePublisher: DefaultResponsePublisher,
3738 errorEncoder: DefaultErrorEncoder,
38 logger: log.NewNopLogger(),
39 errorHandler: transport.NewLogErrorHandler(log.NewNopLogger()),
3940 }
4041 for _, option := range options {
4142 option(s)
7778 // are logged. This is intended as a diagnostic measure. Finer-grained control
7879 // of error handling, including logging in more detail, should be performed in a
7980 // custom SubscriberErrorEncoder which has access to the context.
81 // Deprecated: Use SubscriberErrorHandler instead.
8082 func SubscriberErrorLogger(logger log.Logger) SubscriberOption {
81 return func(s *Subscriber) { s.logger = logger }
83 return func(s *Subscriber) { s.errorHandler = transport.NewLogErrorHandler(logger) }
84 }
85
86 // SubscriberErrorHandler is used to handle non-terminal errors. By default, non-terminal errors
87 // are ignored. This is intended as a diagnostic measure. Finer-grained control
88 // of error handling, including logging in more detail, should be performed in a
89 // custom SubscriberErrorEncoder which has access to the context.
90 func SubscriberErrorHandler(errorHandler transport.ErrorHandler) SubscriberOption {
91 return func(s *Subscriber) { s.errorHandler = errorHandler }
8292 }
8393
8494 // ServeDelivery handles AMQP Delivery messages
97107
98108 request, err := s.dec(ctx, deliv)
99109 if err != nil {
100 s.logger.Log("err", err)
110 s.errorHandler.Handle(ctx, err)
101111 s.errorEncoder(ctx, err, deliv, ch, &pub)
102112 return
103113 }
104114
105115 response, err := s.e(ctx, request)
106116 if err != nil {
107 s.logger.Log("err", err)
117 s.errorHandler.Handle(ctx, err)
108118 s.errorEncoder(ctx, err, deliv, ch, &pub)
109119 return
110120 }
114124 }
115125
116126 if err := s.enc(ctx, &pub, response); err != nil {
117 s.logger.Log("err", err)
127 s.errorHandler.Handle(ctx, err)
118128 s.errorEncoder(ctx, err, deliv, ch, &pub)
119129 return
120130 }
121131
122132 if err := s.responsePublisher(ctx, deliv, ch, &pub); err != nil {
123 s.logger.Log("err", err)
133 s.errorHandler.Handle(ctx, err)
124134 s.errorEncoder(ctx, err, deliv, ch, &pub)
125135 return
126136 }
44
55 "github.com/go-kit/kit/endpoint"
66 "github.com/go-kit/kit/log"
7 "github.com/go-kit/kit/transport"
78 )
89
910 // Handler wraps an endpoint.
1516 after []HandlerResponseFunc
1617 errorEncoder ErrorEncoder
1718 finalizer []HandlerFinalizerFunc
18 logger log.Logger
19 errorHandler transport.ErrorHandler
1920 }
2021
2122 // NewHandler constructs a new handler, which implements
3031 e: e,
3132 dec: dec,
3233 enc: enc,
33 logger: log.NewNopLogger(),
3434 errorEncoder: DefaultErrorEncoder,
35 errorHandler: transport.NewLogErrorHandler(log.NewNopLogger()),
3536 }
3637 for _, option := range options {
3738 option(h)
5657
5758 // HandlerErrorLogger is used to log non-terminal errors.
5859 // By default, no errors are logged.
60 // Deprecated: Use HandlerErrorHandler instead.
5961 func HandlerErrorLogger(logger log.Logger) HandlerOption {
60 return func(h *Handler) { h.logger = logger }
62 return func(h *Handler) { h.errorHandler = transport.NewLogErrorHandler(logger) }
63 }
64
65 // HandlerErrorHandler is used to handle non-terminal errors.
66 // By default, non-terminal errors are ignored.
67 func HandlerErrorHandler(errorHandler transport.ErrorHandler) HandlerOption {
68 return func(h *Handler) { h.errorHandler = errorHandler }
6169 }
6270
6371 // HandlerErrorEncoder is used to encode errors.
96104
97105 request, err := h.dec(ctx, payload)
98106 if err != nil {
99 h.logger.Log("err", err)
107 h.errorHandler.Handle(ctx, err)
100108 return h.errorEncoder(ctx, err)
101109 }
102110
103111 response, err := h.e(ctx, request)
104112 if err != nil {
105 h.logger.Log("err", err)
113 h.errorHandler.Handle(ctx, err)
106114 return h.errorEncoder(ctx, err)
107115 }
108116
111119 }
112120
113121 if resp, err = h.enc(ctx, response); err != nil {
114 h.logger.Log("err", err)
122 h.errorHandler.Handle(ctx, err)
115123 return h.errorEncoder(ctx, err)
116124 }
117125
88 "github.com/aws/aws-lambda-go/events"
99 "github.com/go-kit/kit/endpoint"
1010 "github.com/go-kit/kit/log"
11 "github.com/go-kit/kit/transport"
1112 )
1213
1314 type key int
3839 makeTest01HelloEndpoint(svc),
3940 decodeHelloRequestWithTwoBefores,
4041 encodeResponse,
41 HandlerErrorLogger(log.NewNopLogger()),
42 HandlerErrorHandler(transport.NewLogErrorHandler(log.NewNopLogger())),
4243 HandlerBefore(func(
4344 ctx context.Context,
4445 payload []byte,
0 // Package transport contains bindings to concrete transports.
0 // Package transport contains helpers applicable to all supported transports.
11 package transport
0 package transport
1
2 import (
3 "context"
4
5 "github.com/go-kit/kit/log"
6 )
7
8 // ErrorHandler receives a transport error to be processed for diagnostic purposes.
9 // Usually this means logging the error.
10 type ErrorHandler interface {
11 Handle(ctx context.Context, err error)
12 }
13
14 // LogErrorHandler is a transport error handler implementation which logs an error.
15 type LogErrorHandler struct {
16 logger log.Logger
17 }
18
19 func NewLogErrorHandler(logger log.Logger) *LogErrorHandler {
20 return &LogErrorHandler{
21 logger: logger,
22 }
23 }
24
25 func (h *LogErrorHandler) Handle(ctx context.Context, err error) {
26 h.logger.Log("err", err)
27 }
0 package transport_test
1
2 import (
3 "context"
4 "errors"
5 "testing"
6
7 "github.com/go-kit/kit/log"
8 "github.com/go-kit/kit/transport"
9 )
10
11 func TestLogErrorHandler(t *testing.T) {
12 var output []interface{}
13
14 logger := log.Logger(log.LoggerFunc(func(keyvals ...interface{}) error {
15 output = append(output, keyvals...)
16 return nil
17 }))
18
19 errorHandler := transport.NewLogErrorHandler(logger)
20
21 err := errors.New("error")
22
23 errorHandler.Handle(context.Background(), err)
24
25 if output[1] != err {
26 t.Errorf("expected an error log event: have %v, want %v", output[1], err)
27 }
28 }
77
88 "github.com/go-kit/kit/endpoint"
99 "github.com/go-kit/kit/log"
10 "github.com/go-kit/kit/transport"
1011 )
1112
1213 // Handler which should be called from the gRPC binding of the service
1819
1920 // Server wraps an endpoint and implements grpc.Handler.
2021 type Server struct {
21 e endpoint.Endpoint
22 dec DecodeRequestFunc
23 enc EncodeResponseFunc
24 before []ServerRequestFunc
25 after []ServerResponseFunc
26 finalizer []ServerFinalizerFunc
27 logger log.Logger
22 e endpoint.Endpoint
23 dec DecodeRequestFunc
24 enc EncodeResponseFunc
25 before []ServerRequestFunc
26 after []ServerResponseFunc
27 finalizer []ServerFinalizerFunc
28 errorHandler transport.ErrorHandler
2829 }
2930
3031 // NewServer constructs a new server, which implements wraps the provided
3940 options ...ServerOption,
4041 ) *Server {
4142 s := &Server{
42 e: e,
43 dec: dec,
44 enc: enc,
45 logger: log.NewNopLogger(),
43 e: e,
44 dec: dec,
45 enc: enc,
46 errorHandler: transport.NewLogErrorHandler(log.NewNopLogger()),
4647 }
4748 for _, option := range options {
4849 option(s)
6768
6869 // ServerErrorLogger is used to log non-terminal errors. By default, no errors
6970 // are logged.
71 // Deprecated: Use ServerErrorHandler instead.
7072 func ServerErrorLogger(logger log.Logger) ServerOption {
71 return func(s *Server) { s.logger = logger }
73 return func(s *Server) { s.errorHandler = transport.NewLogErrorHandler(logger) }
74 }
75
76 // ServerErrorHandler is used to handle non-terminal errors. By default, non-terminal errors
77 // are ignored.
78 func ServerErrorHandler(errorHandler transport.ErrorHandler) ServerOption {
79 return func(s *Server) { s.errorHandler = errorHandler }
7280 }
7381
7482 // ServerFinalizer is executed at the end of every gRPC request.
105113
106114 request, err = s.dec(ctx, req)
107115 if err != nil {
108 s.logger.Log("err", err)
116 s.errorHandler.Handle(ctx, err)
109117 return ctx, nil, err
110118 }
111119
112120 response, err = s.e(ctx, request)
113121 if err != nil {
114 s.logger.Log("err", err)
122 s.errorHandler.Handle(ctx, err)
115123 return ctx, nil, err
116124 }
117125
122130
123131 grpcResp, err = s.enc(ctx, response)
124132 if err != nil {
125 s.logger.Log("err", err)
133 s.errorHandler.Handle(ctx, err)
126134 return ctx, nil, err
127135 }
128136
129137 if len(mdHeader) > 0 {
130138 if err = grpc.SendHeader(ctx, mdHeader); err != nil {
131 s.logger.Log("err", err)
139 s.errorHandler.Handle(ctx, err)
132140 return ctx, nil, err
133141 }
134142 }
135143
136144 if len(mdTrailer) > 0 {
137145 if err = grpc.SetTrailer(ctx, mdTrailer); err != nil {
138 s.logger.Log("err", err)
146 s.errorHandler.Handle(ctx, err)
139147 return ctx, nil, err
140148 }
141149 }
66
77 "github.com/go-kit/kit/endpoint"
88 "github.com/go-kit/kit/log"
9 "github.com/go-kit/kit/transport"
910 )
1011
1112 // Server wraps an endpoint and implements http.Handler.
1718 after []ServerResponseFunc
1819 errorEncoder ErrorEncoder
1920 finalizer []ServerFinalizerFunc
20 logger log.Logger
21 errorHandler transport.ErrorHandler
2122 }
2223
2324 // NewServer constructs a new server, which implements http.Handler and wraps
3334 dec: dec,
3435 enc: enc,
3536 errorEncoder: DefaultErrorEncoder,
36 logger: log.NewNopLogger(),
37 errorHandler: transport.NewLogErrorHandler(log.NewNopLogger()),
3738 }
3839 for _, option := range options {
3940 option(s)
6970 // of error handling, including logging in more detail, should be performed in a
7071 // custom ServerErrorEncoder or ServerFinalizer, both of which have access to
7172 // the context.
73 // Deprecated: Use ServerErrorHandler instead.
7274 func ServerErrorLogger(logger log.Logger) ServerOption {
73 return func(s *Server) { s.logger = logger }
75 return func(s *Server) { s.errorHandler = transport.NewLogErrorHandler(logger) }
76 }
77
78 // ServerErrorHandler is used to handle non-terminal errors. By default, non-terminal errors
79 // are ignored. This is intended as a diagnostic measure. Finer-grained control
80 // of error handling, including logging in more detail, should be performed in a
81 // custom ServerErrorEncoder or ServerFinalizer, both of which have access to
82 // the context.
83 func ServerErrorHandler(errorHandler transport.ErrorHandler) ServerOption {
84 return func(s *Server) { s.errorHandler = errorHandler }
7485 }
7586
7687 // ServerFinalizer is executed at the end of every HTTP request.
101112
102113 request, err := s.dec(ctx, r)
103114 if err != nil {
104 s.logger.Log("err", err)
115 s.errorHandler.Handle(ctx, err)
105116 s.errorEncoder(ctx, err, w)
106117 return
107118 }
108119
109120 response, err := s.e(ctx, request)
110121 if err != nil {
111 s.logger.Log("err", err)
122 s.errorHandler.Handle(ctx, err)
112123 s.errorEncoder(ctx, err, w)
113124 return
114125 }
118129 }
119130
120131 if err := s.enc(ctx, w, response); err != nil {
121 s.logger.Log("err", err)
132 s.errorHandler.Handle(ctx, err)
122133 s.errorEncoder(ctx, err, w)
123134 return
124135 }
55
66 "github.com/go-kit/kit/endpoint"
77 "github.com/go-kit/kit/log"
8 "github.com/go-kit/kit/transport"
89
910 "github.com/nats-io/go-nats"
1011 )
1819 after []SubscriberResponseFunc
1920 errorEncoder ErrorEncoder
2021 finalizer []SubscriberFinalizerFunc
21 logger log.Logger
22 errorHandler transport.ErrorHandler
2223 }
2324
2425 // NewSubscriber constructs a new subscriber, which provides nats.MsgHandler and wraps
3435 dec: dec,
3536 enc: enc,
3637 errorEncoder: DefaultErrorEncoder,
37 logger: log.NewNopLogger(),
38 errorHandler: transport.NewLogErrorHandler(log.NewNopLogger()),
3839 }
3940 for _, option := range options {
4041 option(s)
6970 // are logged. This is intended as a diagnostic measure. Finer-grained control
7071 // of error handling, including logging in more detail, should be performed in a
7172 // custom SubscriberErrorEncoder which has access to the context.
73 // Deprecated: Use SubscriberErrorHandler instead.
7274 func SubscriberErrorLogger(logger log.Logger) SubscriberOption {
73 return func(s *Subscriber) { s.logger = logger }
75 return func(s *Subscriber) { s.errorHandler = transport.NewLogErrorHandler(logger) }
76 }
77
78 // SubscriberErrorHandler is used to handle non-terminal errors. By default, non-terminal errors
79 // are ignored. This is intended as a diagnostic measure. Finer-grained control
80 // of error handling, including logging in more detail, should be performed in a
81 // custom SubscriberErrorEncoder which has access to the context.
82 func SubscriberErrorHandler(errorHandler transport.ErrorHandler) SubscriberOption {
83 return func(s *Subscriber) { s.errorHandler = errorHandler }
7484 }
7585
7686 // SubscriberFinalizer is executed at the end of every request from a publisher through NATS.
99109
100110 request, err := s.dec(ctx, msg)
101111 if err != nil {
102 s.logger.Log("err", err)
112 s.errorHandler.Handle(ctx, err)
103113 if msg.Reply == "" {
104114 return
105115 }
109119
110120 response, err := s.e(ctx, request)
111121 if err != nil {
112 s.logger.Log("err", err)
122 s.errorHandler.Handle(ctx, err)
113123 if msg.Reply == "" {
114124 return
115125 }
126136 }
127137
128138 if err := s.enc(ctx, msg.Reply, nc, response); err != nil {
129 s.logger.Log("err", err)
139 s.errorHandler.Handle(ctx, err)
130140 s.errorEncoder(ctx, err, msg.Reply, nc)
131141 return
132142 }