-
Notifications
You must be signed in to change notification settings - Fork 453
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Refactor Middleware to a single set of functions for all routes #3534
Conversation
d071610
to
821328a
Compare
The multiple sets of Middleware functions was getting confusing and difficult to reason about. Now there is a single set of Middleware functions that run for every route before the handler is dispatched. A route can provide an OptionsOverride function to change the middleware.Options passed to the Middleware for a route. This allows a route to tweak how the Middleware runs for a route (e.g response logging). The set of Middleware is completely configurable on the HandlerOptions. If not set, a set of Default middleware is used. A CustomHandler can also provide an OptionOverride function, in addition to the OptionOverride already set on the previous handler. This allows further configuring the options for the CustomHandler.
821328a
to
62ffe2a
Compare
Codecov Report
@@ Coverage Diff @@
## master #3534 +/- ##
======================================
Coverage 55.9% 55.9%
======================================
Files 549 549
Lines 61437 61437
======================================
Hits 34373 34373
Misses 23964 23964
Partials 3100 3100
Flags with carried forward coverage won't be shown. Click here to find out more. Continue to review full report at Codecov.
|
InstrumentOpts instrument.Options | ||
Clock clockwork.Clock | ||
// WithQueryParams adds the query request parameters to the middleware options. | ||
var WithQueryParams middleware.OverrideOptions = func(opts middleware.Options) middleware.Options { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
the query response logging and non-query response logging were merged into a single middleware func that does all response logging. this has the added benefit of improving the non-query response logging with things we only added to the query logging, like status code.
now the query endpoints need to register this option to add the query params as log fields. while I could have hacked and just looked for query
, this seemed cleaner. the middleware
pkg should know nothing about the native
pkg.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
additionally this override style is used for the metrics middleware as well for similar reasons. in order to extract the query params from the request.
if override != nil { | ||
opts = override(opts) | ||
} | ||
if customMiddle[route] != nil { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
now we support a custom handler overriding the middleware options of a prev handler.
} | ||
fields = appendM3Headers(r.Header, fields) | ||
fields = appendM3Headers(w.Header(), fields) | ||
if opts.Logging.Fields != nil { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this will make it much easier to add custom headers to the log fields in the future
|
||
// Default is the default list of middleware functions applied if no middleware functions are set in the | ||
// HandlerOptions. | ||
func Default(opts Options) []mux.MiddlewareFunc { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
now there is a single set of middleware for all routes.
return []mux.MiddlewareFunc{ | ||
Cors(), | ||
Tracing(opentracing.GlobalTracer(), opts.InstrumentOpts), | ||
Source(opts), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this means Source
runs for every route. the impl of Source
changes to short circuit with a M3-Source
header present
// Source adds the headers.SourceHeader value to the request context. | ||
// Installing this middleware function allows application code to access the typed source value using FromContext. | ||
// Additionally a source log field is added to the request scope logger. | ||
func Source(opts Options) mux.MiddlewareFunc { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this had to move to the middleware
pkg so the SourceOptions
could be part of the MiddlewareOptions
.
This is a tradeoff for allowing routes to overrides options for middleware. All middleware will need to be the middleware
pkg, instead of individual pkgs. I think this is fine, since middleware
fns will just delegate to exposed functions from other pkgs, like source.NewContext
} | ||
|
||
// Register registers an endpoint. | ||
func (r *EndpointRegistry) Register(opts RegisterOptions) error { | ||
route := r.router.NewRoute() | ||
r.middlewareOpts[route] = opts.MiddlewareOverride |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nice
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice! LG
Clock clockwork.Clock | ||
// WithQueryParams adds the query request parameters to the middleware options. | ||
var WithQueryParams middleware.OverrideOptions = func(opts middleware.Options) middleware.Options { | ||
opts.Logging.Fields = func(r *http.Request, start time.Time) []zap.Field { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is it always ok to blow away whatever logging options may already exist? Maybe we need to do something like capture the existing opts.Logging.Fields()
, running that method, and then appending the new fields to those?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
that's a good point.
The multiple sets of Middleware functions was getting confusing and
difficult to reason about. Now there is a single set of Middleware
functions that run for every route before the handler is dispatched.
A route can provide an OptionsOverride function to change the
middleware.Options passed to the Middleware for a route. This
allows a route to tweak how the Middleware runs for a route (e.g
response logging).
The set of Middleware is completely configurable on the
HandlerOptions. If not set, a set of Default middleware is used.
A CustomHandler can also provide an OptionOverride function, in addition
to the OptionOverride already set on the previous handler. This allows
further configuring the options for the CustomHandler.