-
Notifications
You must be signed in to change notification settings - Fork 148
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
generate_path
yields incorrect values for Sinatra+Rack::Build apps
#249
Comments
Hey @shurikp, Thank you very much for such a detailed bug report! Sorry for the slow reply on my part. I got ill right after releasing 3.0.0, and then got back in to a very busy period in my day job. I'm going to set up an app like the example you gave and see what we can do. My immediate thoughts (in order of preference) are:
My schedule is pretty busy right now, but I will try and get something together when I have a moment. |
Okay, I did a little digging, and it's not quite what I expected. It looks like I printed those two values in two places: once in the Prometheus collector middleware, and once in the app itself. In the collector middleware, they look like this:
whereas from inside the Sinatra app (i.e. after
The reason your monkeypatch works is that when the middleware sees the request environment, everything is in My first suggestion isn't useful, as our middleware is working before My second one would work, but it does feel somewhat brittle, so I'd like to take some time to see if I can think of a less janky solution to the problem. EDIT: I just checked, any my worry about canonicalisation was well-placed:
EDIT2: EDIT3: Canonicalising it might be reasonably simple, if all we're focused on is removing double
but in testing that, I discovered a new problem. I decided to test out what happened with trailing slashes (single and multiple), only to find that you need to add a
which seems kinda naff. I'm starting to think this whole framework-specific path detection thing was a mistake. Even if we can sort out all of the canonicalisation issues (which I'm increasingly dubious of, the more I find new edge cases), more complex cases of I'm inclined to back that part of #245 out of the gem, and just keep the improvements we made to handling IDs in consecutive path segments. @dmagliola I'd love your thoughts. |
So @dmagliola and I ended up spending a couple of hours talking through this and digging further into the source code of There were two factors that convinced us of that course of action, and I wanted to share them here so it's clear to the community how we reached the decision, and so that we have a clear explanation of why this route didn't work out if it comes up in the future. First factorThe first factor came from digging further into why we were seeing different values when printing In order to dispatch to the different apps, The unfortunate part, when it comes to our middleware, is that it undoes this before returning to the previous middleware. Let's look at this in the context of the collector middleware. Our middleware runs before Unfortunately, From Sinatra's point of view, the route it handled didn't include the app prefix, so it's missing from Second factorI mentioned in a previous comment that route definitions could end up looking quite weird in
We ended up experimenting with more of Sinatra's route syntax, and it turns out that there's much worse in there. For example, if you use Sinatra's regex route matching:
then you'll end up with path labels that look like:
which neither @dmagliola nor I felt was what users would want. What we're doing nextBetween those two factors, we decided that that the best course of action was to back out the changes from #245 that introduced the framework-specific route detection, and just keep the fix to We also realised that we missed a potential change that would make it easier for users to subclass Unfortunately, following the principles we set out for ourselves in the 3.0 release when it came to changing the labels we generate, this is a breaking change, so we'll be releasing a rather empty version 4.0 to communicate the potential breakage to users. Thank you for bearing with us while we got this all figured out. Hopefully we've found the right path to take this time round. |
Sadly, with the benefit of hindsight, this wasn't a good idea. There are two reasons we're dropping this: - It doesn't play nicely with libraries like `Rack::Builder`, which dispatches requests to different Rack apps based on a path prefix in a way that isn't visible to middleware. For example, when using `Rack::Builder`, `sinatra.route` only contains the parts of the path after the prefix that `Rack::Builder` used to dispatch to the specific app, and doesn't leave any information in the request environment to indicate which prefix it dispatched to. - It turns out framework-specific route info isn't always formatted in a way that looks good in a Prometheus label. For example, when using regex-based route-matching in Sinatra, you can end up with labels that look like `\\/vapes\\/([0-9]+)\\/?`. For a really detailed dive into those two issues, see this GitHub comment: #249 (comment)
Sadly, with the benefit of hindsight, this wasn't a good idea. There are two reasons we're dropping this: - It doesn't play nicely with libraries like `Rack::Builder`, which dispatches requests to different Rack apps based on a path prefix in a way that isn't visible to middleware. For example, when using `Rack::Builder`, `sinatra.route` only contains the parts of the path after the prefix that `Rack::Builder` used to dispatch to the specific app, and doesn't leave any information in the request environment to indicate which prefix it dispatched to. - It turns out framework-specific route info isn't always formatted in a way that looks good in a Prometheus label. For example, when using regex-based route-matching in Sinatra, you can end up with labels that look like `\\/vapes\\/([0-9]+)\\/?`. For a really detailed dive into those two issues, see this GitHub comment: #249 (comment) Signed-off-by: Chris Sinjakli <[email protected]>
Sadly, with the benefit of hindsight, this wasn't a good idea. There are two reasons we're dropping this: - It doesn't play nicely with libraries like `Rack::Builder`, which dispatches requests to different Rack apps based on a path prefix in a way that isn't visible to middleware. For example, when using `Rack::Builder`, `sinatra.route` only contains the parts of the path after the prefix that `Rack::Builder` used to dispatch to the specific app, and doesn't leave any information in the request environment to indicate which prefix it dispatched to. - It turns out framework-specific route info isn't always formatted in a way that looks good in a Prometheus label. For example, when using regex-based route-matching in Sinatra, you can end up with labels that look like `\\/vapes\\/([0-9]+)\\/?`. For a really detailed dive into those two issues, see this GitHub comment: #249 (comment) Signed-off-by: Chris Sinjakli <[email protected]>
Wow @Sinjo, thanks for such an incredibly detailed investigation and explanation! Unfortunately, I missed all your comments.. This means we'll stick with our monkeypatch until 4.0.0 and then remove it. |
@shurikp No worries at all - we wanted to understand this properly so we could make a good decision. Good news though: we released 4.0.0 yesterday! Hopefully that does the trick for you. Let us know if you run into any issues. |
@Sinjo works great, thank you! |
Prometheus::Middleware::Collector#generate_path
yields incorrect values when used on top-level of application build withRack::Build
, that also has several mounted Sinatra apps insidemap '/subpath'
blocks.We have the following setup:
config.ru:
app1.rb:
app2.rb:
After upgrading
prometheus-client
to 3.0.0, metrics start to go into wrong buckets: for both/app1
and/app2
requests we now have:http_server_request_duration_seconds_bucket{method="get",path="/",le="0.025"} 0.0
path labels being "/" for both, whereas before it was:
The problem here is with the new way of inferring paths for sinatra applications: https://github.com/prometheus/client_ruby/pull/245/files#diff-1026444c3a547bf72b02d69fa3ca9be012988d69f45af85bbee6df35560c9dbfR108-R109
The problem is that
env['sinatra.route']
is present butenv['SCRIPT_NAME']
at the moment this top-level middleware runs (before we hit Sinatra app).If we move
use Prometheus::Middleware::Collector
inside each of the applications they'll start to conflict withhttp_server_requests_total has already been registered
error.Current workaround is to just monkeypatch
generate_path
to the old behaviour:but I wonder if there's any better solution
The text was updated successfully, but these errors were encountered: