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
17 | 17 | "github.com/go-kit/kit/ratelimit" |
18 | 18 | "github.com/go-kit/kit/tracing/opentracing" |
19 | 19 | "github.com/go-kit/kit/tracing/zipkin" |
20 | "github.com/go-kit/kit/transport" | |
20 | 21 | grpctransport "github.com/go-kit/kit/transport/grpc" |
21 | 22 | |
22 | 23 | "github.com/go-kit/kit/examples/addsvc/pb" |
43 | 44 | zipkinServer := zipkin.GRPCServerTrace(zipkinTracer) |
44 | 45 | |
45 | 46 | options := []grpctransport.ServerOption{ |
46 | grpctransport.ServerErrorLogger(logger), | |
47 | grpctransport.ServerErrorHandler(transport.NewLogErrorHandler(logger)), | |
47 | 48 | zipkinServer, |
48 | 49 | } |
49 | 50 |
22 | 22 | "github.com/go-kit/kit/ratelimit" |
23 | 23 | "github.com/go-kit/kit/tracing/opentracing" |
24 | 24 | "github.com/go-kit/kit/tracing/zipkin" |
25 | "github.com/go-kit/kit/transport" | |
25 | 26 | httptransport "github.com/go-kit/kit/transport/http" |
26 | 27 | |
27 | 28 | "github.com/go-kit/kit/examples/addsvc/pkg/addendpoint" |
40 | 41 | |
41 | 42 | options := []httptransport.ServerOption{ |
42 | 43 | httptransport.ServerErrorEncoder(errorEncoder), |
43 | httptransport.ServerErrorLogger(logger), | |
44 | httptransport.ServerErrorHandler(transport.NewLogErrorHandler(logger)), | |
44 | 45 | zipkinServer, |
45 | 46 | } |
46 | 47 |
13 | 13 | "github.com/gorilla/mux" |
14 | 14 | |
15 | 15 | "github.com/go-kit/kit/log" |
16 | "github.com/go-kit/kit/transport" | |
16 | 17 | httptransport "github.com/go-kit/kit/transport/http" |
17 | 18 | ) |
18 | 19 | |
28 | 29 | r := mux.NewRouter() |
29 | 30 | e := MakeServerEndpoints(s) |
30 | 31 | options := []httptransport.ServerOption{ |
31 | httptransport.ServerErrorLogger(logger), | |
32 | httptransport.ServerErrorHandler(transport.NewLogErrorHandler(logger)), | |
32 | 33 | httptransport.ServerErrorEncoder(encodeError), |
33 | 34 | } |
34 | 35 |
9 | 9 | "github.com/gorilla/mux" |
10 | 10 | |
11 | 11 | kitlog "github.com/go-kit/kit/log" |
12 | "github.com/go-kit/kit/transport" | |
12 | 13 | kithttp "github.com/go-kit/kit/transport/http" |
13 | 14 | |
14 | 15 | "github.com/go-kit/kit/examples/shipping/cargo" |
18 | 19 | // MakeHandler returns a handler for the booking service. |
19 | 20 | func MakeHandler(bs Service, logger kitlog.Logger) http.Handler { |
20 | 21 | opts := []kithttp.ServerOption{ |
21 | kithttp.ServerErrorLogger(logger), | |
22 | kithttp.ServerErrorHandler(transport.NewLogErrorHandler(logger)), | |
22 | 23 | kithttp.ServerErrorEncoder(encodeError), |
23 | 24 | } |
24 | 25 |
8 | 8 | "github.com/gorilla/mux" |
9 | 9 | |
10 | 10 | kitlog "github.com/go-kit/kit/log" |
11 | "github.com/go-kit/kit/transport" | |
11 | 12 | kithttp "github.com/go-kit/kit/transport/http" |
12 | 13 | |
13 | 14 | "github.com/go-kit/kit/examples/shipping/cargo" |
20 | 21 | r := mux.NewRouter() |
21 | 22 | |
22 | 23 | opts := []kithttp.ServerOption{ |
23 | kithttp.ServerErrorLogger(logger), | |
24 | kithttp.ServerErrorHandler(transport.NewLogErrorHandler(logger)), | |
24 | 25 | kithttp.ServerErrorEncoder(encodeError), |
25 | 26 | } |
26 | 27 |
8 | 8 | "github.com/gorilla/mux" |
9 | 9 | |
10 | 10 | kitlog "github.com/go-kit/kit/log" |
11 | kittransport "github.com/go-kit/kit/transport" | |
11 | 12 | kithttp "github.com/go-kit/kit/transport/http" |
12 | 13 | |
13 | 14 | "github.com/go-kit/kit/examples/shipping/cargo" |
18 | 19 | r := mux.NewRouter() |
19 | 20 | |
20 | 21 | opts := []kithttp.ServerOption{ |
21 | kithttp.ServerErrorLogger(logger), | |
22 | kithttp.ServerErrorHandler(kittransport.NewLogErrorHandler(logger)), | |
22 | 23 | kithttp.ServerErrorEncoder(encodeError), |
23 | 24 | } |
24 | 25 |
6 | 6 | |
7 | 7 | "github.com/go-kit/kit/endpoint" |
8 | 8 | "github.com/go-kit/kit/log" |
9 | "github.com/go-kit/kit/transport" | |
9 | 10 | "github.com/streadway/amqp" |
10 | 11 | ) |
11 | 12 | |
18 | 19 | after []SubscriberResponseFunc |
19 | 20 | responsePublisher ResponsePublisher |
20 | 21 | errorEncoder ErrorEncoder |
21 | logger log.Logger | |
22 | errorHandler transport.ErrorHandler | |
22 | 23 | } |
23 | 24 | |
24 | 25 | // NewSubscriber constructs a new subscriber, which provides a handler |
35 | 36 | enc: enc, |
36 | 37 | responsePublisher: DefaultResponsePublisher, |
37 | 38 | errorEncoder: DefaultErrorEncoder, |
38 | logger: log.NewNopLogger(), | |
39 | errorHandler: transport.NewLogErrorHandler(log.NewNopLogger()), | |
39 | 40 | } |
40 | 41 | for _, option := range options { |
41 | 42 | option(s) |
77 | 78 | // are logged. This is intended as a diagnostic measure. Finer-grained control |
78 | 79 | // of error handling, including logging in more detail, should be performed in a |
79 | 80 | // custom SubscriberErrorEncoder which has access to the context. |
81 | // Deprecated: Use SubscriberErrorHandler instead. | |
80 | 82 | 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 } | |
82 | 92 | } |
83 | 93 | |
84 | 94 | // ServeDelivery handles AMQP Delivery messages |
97 | 107 | |
98 | 108 | request, err := s.dec(ctx, deliv) |
99 | 109 | if err != nil { |
100 | s.logger.Log("err", err) | |
110 | s.errorHandler.Handle(ctx, err) | |
101 | 111 | s.errorEncoder(ctx, err, deliv, ch, &pub) |
102 | 112 | return |
103 | 113 | } |
104 | 114 | |
105 | 115 | response, err := s.e(ctx, request) |
106 | 116 | if err != nil { |
107 | s.logger.Log("err", err) | |
117 | s.errorHandler.Handle(ctx, err) | |
108 | 118 | s.errorEncoder(ctx, err, deliv, ch, &pub) |
109 | 119 | return |
110 | 120 | } |
114 | 124 | } |
115 | 125 | |
116 | 126 | if err := s.enc(ctx, &pub, response); err != nil { |
117 | s.logger.Log("err", err) | |
127 | s.errorHandler.Handle(ctx, err) | |
118 | 128 | s.errorEncoder(ctx, err, deliv, ch, &pub) |
119 | 129 | return |
120 | 130 | } |
121 | 131 | |
122 | 132 | if err := s.responsePublisher(ctx, deliv, ch, &pub); err != nil { |
123 | s.logger.Log("err", err) | |
133 | s.errorHandler.Handle(ctx, err) | |
124 | 134 | s.errorEncoder(ctx, err, deliv, ch, &pub) |
125 | 135 | return |
126 | 136 | } |
4 | 4 | |
5 | 5 | "github.com/go-kit/kit/endpoint" |
6 | 6 | "github.com/go-kit/kit/log" |
7 | "github.com/go-kit/kit/transport" | |
7 | 8 | ) |
8 | 9 | |
9 | 10 | // Handler wraps an endpoint. |
15 | 16 | after []HandlerResponseFunc |
16 | 17 | errorEncoder ErrorEncoder |
17 | 18 | finalizer []HandlerFinalizerFunc |
18 | logger log.Logger | |
19 | errorHandler transport.ErrorHandler | |
19 | 20 | } |
20 | 21 | |
21 | 22 | // NewHandler constructs a new handler, which implements |
30 | 31 | e: e, |
31 | 32 | dec: dec, |
32 | 33 | enc: enc, |
33 | logger: log.NewNopLogger(), | |
34 | 34 | errorEncoder: DefaultErrorEncoder, |
35 | errorHandler: transport.NewLogErrorHandler(log.NewNopLogger()), | |
35 | 36 | } |
36 | 37 | for _, option := range options { |
37 | 38 | option(h) |
56 | 57 | |
57 | 58 | // HandlerErrorLogger is used to log non-terminal errors. |
58 | 59 | // By default, no errors are logged. |
60 | // Deprecated: Use HandlerErrorHandler instead. | |
59 | 61 | 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 } | |
61 | 69 | } |
62 | 70 | |
63 | 71 | // HandlerErrorEncoder is used to encode errors. |
96 | 104 | |
97 | 105 | request, err := h.dec(ctx, payload) |
98 | 106 | if err != nil { |
99 | h.logger.Log("err", err) | |
107 | h.errorHandler.Handle(ctx, err) | |
100 | 108 | return h.errorEncoder(ctx, err) |
101 | 109 | } |
102 | 110 | |
103 | 111 | response, err := h.e(ctx, request) |
104 | 112 | if err != nil { |
105 | h.logger.Log("err", err) | |
113 | h.errorHandler.Handle(ctx, err) | |
106 | 114 | return h.errorEncoder(ctx, err) |
107 | 115 | } |
108 | 116 | |
111 | 119 | } |
112 | 120 | |
113 | 121 | if resp, err = h.enc(ctx, response); err != nil { |
114 | h.logger.Log("err", err) | |
122 | h.errorHandler.Handle(ctx, err) | |
115 | 123 | return h.errorEncoder(ctx, err) |
116 | 124 | } |
117 | 125 |
8 | 8 | "github.com/aws/aws-lambda-go/events" |
9 | 9 | "github.com/go-kit/kit/endpoint" |
10 | 10 | "github.com/go-kit/kit/log" |
11 | "github.com/go-kit/kit/transport" | |
11 | 12 | ) |
12 | 13 | |
13 | 14 | type key int |
38 | 39 | makeTest01HelloEndpoint(svc), |
39 | 40 | decodeHelloRequestWithTwoBefores, |
40 | 41 | encodeResponse, |
41 | HandlerErrorLogger(log.NewNopLogger()), | |
42 | HandlerErrorHandler(transport.NewLogErrorHandler(log.NewNopLogger())), | |
42 | 43 | HandlerBefore(func( |
43 | 44 | ctx context.Context, |
44 | 45 | payload []byte, |
0 | // Package transport contains bindings to concrete transports. | |
0 | // Package transport contains helpers applicable to all supported transports. | |
1 | 1 | 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 | } |
7 | 7 | |
8 | 8 | "github.com/go-kit/kit/endpoint" |
9 | 9 | "github.com/go-kit/kit/log" |
10 | "github.com/go-kit/kit/transport" | |
10 | 11 | ) |
11 | 12 | |
12 | 13 | // Handler which should be called from the gRPC binding of the service |
18 | 19 | |
19 | 20 | // Server wraps an endpoint and implements grpc.Handler. |
20 | 21 | 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 | |
28 | 29 | } |
29 | 30 | |
30 | 31 | // NewServer constructs a new server, which implements wraps the provided |
39 | 40 | options ...ServerOption, |
40 | 41 | ) *Server { |
41 | 42 | 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()), | |
46 | 47 | } |
47 | 48 | for _, option := range options { |
48 | 49 | option(s) |
67 | 68 | |
68 | 69 | // ServerErrorLogger is used to log non-terminal errors. By default, no errors |
69 | 70 | // are logged. |
71 | // Deprecated: Use ServerErrorHandler instead. | |
70 | 72 | 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 } | |
72 | 80 | } |
73 | 81 | |
74 | 82 | // ServerFinalizer is executed at the end of every gRPC request. |
105 | 113 | |
106 | 114 | request, err = s.dec(ctx, req) |
107 | 115 | if err != nil { |
108 | s.logger.Log("err", err) | |
116 | s.errorHandler.Handle(ctx, err) | |
109 | 117 | return ctx, nil, err |
110 | 118 | } |
111 | 119 | |
112 | 120 | response, err = s.e(ctx, request) |
113 | 121 | if err != nil { |
114 | s.logger.Log("err", err) | |
122 | s.errorHandler.Handle(ctx, err) | |
115 | 123 | return ctx, nil, err |
116 | 124 | } |
117 | 125 | |
122 | 130 | |
123 | 131 | grpcResp, err = s.enc(ctx, response) |
124 | 132 | if err != nil { |
125 | s.logger.Log("err", err) | |
133 | s.errorHandler.Handle(ctx, err) | |
126 | 134 | return ctx, nil, err |
127 | 135 | } |
128 | 136 | |
129 | 137 | if len(mdHeader) > 0 { |
130 | 138 | if err = grpc.SendHeader(ctx, mdHeader); err != nil { |
131 | s.logger.Log("err", err) | |
139 | s.errorHandler.Handle(ctx, err) | |
132 | 140 | return ctx, nil, err |
133 | 141 | } |
134 | 142 | } |
135 | 143 | |
136 | 144 | if len(mdTrailer) > 0 { |
137 | 145 | if err = grpc.SetTrailer(ctx, mdTrailer); err != nil { |
138 | s.logger.Log("err", err) | |
146 | s.errorHandler.Handle(ctx, err) | |
139 | 147 | return ctx, nil, err |
140 | 148 | } |
141 | 149 | } |
6 | 6 | |
7 | 7 | "github.com/go-kit/kit/endpoint" |
8 | 8 | "github.com/go-kit/kit/log" |
9 | "github.com/go-kit/kit/transport" | |
9 | 10 | ) |
10 | 11 | |
11 | 12 | // Server wraps an endpoint and implements http.Handler. |
17 | 18 | after []ServerResponseFunc |
18 | 19 | errorEncoder ErrorEncoder |
19 | 20 | finalizer []ServerFinalizerFunc |
20 | logger log.Logger | |
21 | errorHandler transport.ErrorHandler | |
21 | 22 | } |
22 | 23 | |
23 | 24 | // NewServer constructs a new server, which implements http.Handler and wraps |
33 | 34 | dec: dec, |
34 | 35 | enc: enc, |
35 | 36 | errorEncoder: DefaultErrorEncoder, |
36 | logger: log.NewNopLogger(), | |
37 | errorHandler: transport.NewLogErrorHandler(log.NewNopLogger()), | |
37 | 38 | } |
38 | 39 | for _, option := range options { |
39 | 40 | option(s) |
69 | 70 | // of error handling, including logging in more detail, should be performed in a |
70 | 71 | // custom ServerErrorEncoder or ServerFinalizer, both of which have access to |
71 | 72 | // the context. |
73 | // Deprecated: Use ServerErrorHandler instead. | |
72 | 74 | 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 } | |
74 | 85 | } |
75 | 86 | |
76 | 87 | // ServerFinalizer is executed at the end of every HTTP request. |
101 | 112 | |
102 | 113 | request, err := s.dec(ctx, r) |
103 | 114 | if err != nil { |
104 | s.logger.Log("err", err) | |
115 | s.errorHandler.Handle(ctx, err) | |
105 | 116 | s.errorEncoder(ctx, err, w) |
106 | 117 | return |
107 | 118 | } |
108 | 119 | |
109 | 120 | response, err := s.e(ctx, request) |
110 | 121 | if err != nil { |
111 | s.logger.Log("err", err) | |
122 | s.errorHandler.Handle(ctx, err) | |
112 | 123 | s.errorEncoder(ctx, err, w) |
113 | 124 | return |
114 | 125 | } |
118 | 129 | } |
119 | 130 | |
120 | 131 | if err := s.enc(ctx, w, response); err != nil { |
121 | s.logger.Log("err", err) | |
132 | s.errorHandler.Handle(ctx, err) | |
122 | 133 | s.errorEncoder(ctx, err, w) |
123 | 134 | return |
124 | 135 | } |
5 | 5 | |
6 | 6 | "github.com/go-kit/kit/endpoint" |
7 | 7 | "github.com/go-kit/kit/log" |
8 | "github.com/go-kit/kit/transport" | |
8 | 9 | |
9 | 10 | "github.com/nats-io/go-nats" |
10 | 11 | ) |
18 | 19 | after []SubscriberResponseFunc |
19 | 20 | errorEncoder ErrorEncoder |
20 | 21 | finalizer []SubscriberFinalizerFunc |
21 | logger log.Logger | |
22 | errorHandler transport.ErrorHandler | |
22 | 23 | } |
23 | 24 | |
24 | 25 | // NewSubscriber constructs a new subscriber, which provides nats.MsgHandler and wraps |
34 | 35 | dec: dec, |
35 | 36 | enc: enc, |
36 | 37 | errorEncoder: DefaultErrorEncoder, |
37 | logger: log.NewNopLogger(), | |
38 | errorHandler: transport.NewLogErrorHandler(log.NewNopLogger()), | |
38 | 39 | } |
39 | 40 | for _, option := range options { |
40 | 41 | option(s) |
69 | 70 | // are logged. This is intended as a diagnostic measure. Finer-grained control |
70 | 71 | // of error handling, including logging in more detail, should be performed in a |
71 | 72 | // custom SubscriberErrorEncoder which has access to the context. |
73 | // Deprecated: Use SubscriberErrorHandler instead. | |
72 | 74 | 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 } | |
74 | 84 | } |
75 | 85 | |
76 | 86 | // SubscriberFinalizer is executed at the end of every request from a publisher through NATS. |
99 | 109 | |
100 | 110 | request, err := s.dec(ctx, msg) |
101 | 111 | if err != nil { |
102 | s.logger.Log("err", err) | |
112 | s.errorHandler.Handle(ctx, err) | |
103 | 113 | if msg.Reply == "" { |
104 | 114 | return |
105 | 115 | } |
109 | 119 | |
110 | 120 | response, err := s.e(ctx, request) |
111 | 121 | if err != nil { |
112 | s.logger.Log("err", err) | |
122 | s.errorHandler.Handle(ctx, err) | |
113 | 123 | if msg.Reply == "" { |
114 | 124 | return |
115 | 125 | } |
126 | 136 | } |
127 | 137 | |
128 | 138 | if err := s.enc(ctx, msg.Reply, nc, response); err != nil { |
129 | s.logger.Log("err", err) | |
139 | s.errorHandler.Handle(ctx, err) | |
130 | 140 | s.errorEncoder(ctx, err, msg.Reply, nc) |
131 | 141 | return |
132 | 142 | } |