Ruby Agent Now Automatically Instruments Rack Middlewares

Since its early roots in Rails, our internal Ruby infrastructure at New Relic has branched out significantly. In addition to multiple Rails apps, we now have internal applications based on Sinatra, and a myriad of bare Rack applications. Instrumentation at just the Rails controller action or Sinatra route is no longer enough to get a complete picture of the performance of our internal apps, and we suspect the same is true for many of our customers.

With that in mind, we’re happy to announce that in version 3.9.0, the Ruby agent will automatically instrument Rack middlewares. The first change that you’ll notice with this new instrumentation is a new band on your overview graph, showing you the average time that was spent in the Rack middleware layer per request.

In the example application below, I’ve manually added a middleware that takes 50 ms on each request. On the left is data generated by version 3.8.1 of the Ruby agent, and on the right, data from 3.9.0 (the latest release). You can see that some of what was previously accounted for under request queue time was actually being spent in this middleware:

Rack Middleware 1

You’ll also be able to see which specific middlewares are taking up the most time for a specific transaction:

Rack Middleware 2

… and of course, you’ll be able to see middlewares in transaction traces:

Rack Middleware 3

Read on to see why this is a big step forward for visibility into your app performance.

Broader visibility for each request

The biggest impact of this change is that the new Rack middleware instrumentation gives you a broader, more accurate view of each request.

The Ruby agent has traditionally started the clock for a given request when it hits our instrumentation points in Rails or Sinatra (or your manual instrumentation points if you’ve added transaction tracers to your app explicitly). This means that previously, the agent didn’t even know a request existed until it got through all of your Rack middlewares.

This situation is helped somewhat by our front-end queue time tracking feature, which uses an HTTP request header attached to each incoming request by your frontend web server to determine how much time a request spent waiting before it hit your application proper. This queue time, however, is a bit of a catch-all: we can track the time between the frontend web server receiving a request and that request being seen by Rails or Sinatra, but until now we haven’t been able to tell you anything about what was happening during that time.

By starting our instrumentation at the outer-most Rack middleware layer, we’re now able to further break down the time between those two events (the receipt of a request by your front-end web server, and the same request hitting your Rails controller action or Sinatra route). We can also measure time spent on the way out of your middleware stack, which was previously invisible to the Ruby agent.

Revealing “invisible” requests

Requests that never made it all the way to your Rails or Sinatra application, and were instead serviced by Rack middlewares directly would before have been invisible to the Ruby agent by default.

Now, any request that hits the Rack layer will be instrumented, including requests that are serviced from middlewares directly—this might include responses that are served by caching middlewares, or entire mini-applications implemented as Rack middlewares.

More error tracing coverage

Errors occurring in Rack middlewares, which used to be invisible to the Ruby agent, will now be tracked just like other errors.

In particular, this means that Rails routing errors can be captured by the Ruby agent. (You can of course still use the existing mechanisms to ignore certain classes of errors if you’d prefer not to see these exceptions.)

Automatic instrumentation for all Rack apps

Applications that used Rack directly (or used rack-based frameworks besides Rails or Sinatra) previously required manual instrumentation.

These applications will now be automatically instrumented, as long as the Ruby agent is required early in the application startup sequence. By default, all requests will be recorded under the same transaction name, but you can easily change this by using the set_transaction_name API call to segment your requests into more meaningful buckets for your application.

Conclusion

We’re excited to be delivering a more complete picture of your Ruby application’s performance with version 3.9.0 of the Ruby agent, and we hope that you find the new Rack middleware instrumentation useful. See our docs for more details about the instrumentation, and if you have questions or concerns, or suggestions as to how it could be more useful for you, we’d love to hear from you in our community forum!

ben@newrelic.com'

Ben Weintraub is a Rubyist at New Relic, working primarily on the newrelic_rpm gem. View posts by .

Interested in writing for New Relic Blog? Send us a pitch!