Adding metadata/labels to a route?
rlipscombe opened this issue · comments
One question that occasionally arises at work is "how do we attach telemetry labels to a cowboy route?". We'd like to be able to attach arbitrary metadata to a route, and have it available in the cowboy_metrics_h
callback.
Ideally, it would be an extra element in the route tuple, something like this:
Dispatch = cowboy_router:compile([
{'_', [
{"/", cowboy_static, {priv_file, ?APPLICATION, "index.html"}},
{"/users/:id", [{id, int}], the_user_h, [], #{labels => #{route => "/users"}}}
]}
]),
...and would be picked up by the cowboy_router
middleware and put in the env along with handler
and handler_opts
.
(to avoid ambiguity, if you wanted this, you'd have to explicitly specify constraints, possibly empty -- or maybe {Handler, Opts}
would need to be a tuple in this case).
Does this seem like a good idea? Is there another way to do it right now?
I've been wracking my brains for ways to wrap cowboy_router:compile
or the cowboy_router
middleware, or to wrap the individual handlers, but I can't come up with anything that doesn't feel like a hack.
After some thought, I've come up with the following, which doesn't require any cowboy changes:
- Replace the current
Handler
with a tuple,{Handler, HandlerOpts}
- Replace the current
HandlerOpts
withHandlerMetadata
.
Add a middleware that goes in between cowboy_router
and cowboy_handler
that does this:
execute(Req, Env = #{handler := {Handler, HandlerOpts}, handler_opts := Metadata}) ->
Env2 = Env#{handler => Handler, handler_opts => HandlerOpts, handler_metadata => Metadata},
{ok, Req, Env2}.
Getting handler_metadata
into user_data
where the metrics callback can see it is left as an exercise for the reader.