For metrics purposes (having Exometer in mind) it would be nice to know which route was matched in addition to the actual URI that was hit.
In other words, both GET api/entities/1 and GET api/entities/2 might match the route GET api/entities/:id, but that fact is not recorded in the conn. There are of course several less than ideal ways of establishing which route was matched, but recording it as it is matched seems the simplest (if that is possible).
I'd be happy to give it a shot, if you feel such an addition could be useful.
To be clear, you want to know the pattern that was match on? Why that would be useful to record?
Yes, that is the idea.
To record endpoint hits with Exometer one could do this:
:exometer.update([:myapp, :api, conn.method, conn.request_path], 1)
but if the route contains variables like interpolated id's, it would look like a separate endpoint was hit for every id. In some cases that may be desirable, but I think in the most common case, you would want to consider requests to GET api/entity/1 and GET api/entity/2 as having hit the same endpoint.
I realize that using the controller name and action gives similar information, so one could do this:
:exometer.update([:myapp, :api, conn.private.phoenix_controller, conn.private.phoenix_action], 1)
(inspect or string conversion omitted for clarity)
but multiple routes could point to the same controller and action and different plugs may have been applied.
I realize that using the controller name and action gives similar information
That's exactly what I would suggest. controller+action+verb should be enough to gather the uniqueness information you need for your exometer reports.
My concern in that case, in addition to the ones provided in the previous post, is that it pollutes my metrics with implementation details.
I can imagine having different routes pointing to the same action.
If one is being deprecated, I would like to know when I can safely kill the old route.
/api/horrible/:id/endpoint vs /api/v2/better/:id
Also, could be a simple way of doing A/B testing analysis
@palm86 I would argue "/api/v2/better/:id" is also an implementation detail. The path and verb, however, are not as they are part of the request.
@franc If the goal is to do A/B testing, I would prefer to use an explicit API than implicitly rely on the route pattern. For example:
get "/api/v2/better/:id", Controller, :action, assigns: %{ab: {:experiment, :a}}
get "/api/horrible/better/:id", Controller, :action, assigns: %{ab: {:experiment, :b}}
I am pretty sure we can come up with something cleaner than the above. For example, you could also use pipelines to store this information and group routes accordingly.
Is there a good way to write a plug that can extract this information? It's not clear to me how one would go about extracting the functionality to log which route was recognized into a separate plug.
If someone can provide a pointer of how this could in principle be done it will be a good exercise for me to see if I can build that rather than requiring this functionality to be in Phoenix itself.
@Ivor the only way I can think of implementing this is by replacing the Phoenix macros by your own macros. Something like this:
require Phoenix.Router
defmacro get(path, controller, action, options \\ []) do
quote bind_quoted: [path: path, controller: controller, action: action, options: options] do
assigns = Map.put(options[:assigns] || %{}, :router_path, path)
Phoenix.Router.get path, controller, action, Keyword.put(options, :assigns, assigns)
end
end
Then you can replace Phoenix macros by the above.
Thank you! I'll have a look :)
I think Jos茅's suggestion of storing the metadata about the routes in an assign is the way to go. Pipelines would allow them to be nicely composed as well:
scope "/" do
pipe_through [:browser, :ab_test_1]
end
I don't believe we need to expose the uninterpolated path segments at this time. Thanks!
Most helpful comment
@Ivor the only way I can think of implementing this is by replacing the Phoenix macros by your own macros. Something like this:
Then you can replace Phoenix macros by the above.