Skip to content

Instantly share code, notes, and snippets.

@pseudomuto
Last active March 29, 2019 18:52
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save pseudomuto/aff211b9d08d7f2d00a5 to your computer and use it in GitHub Desktop.
Save pseudomuto/aff211b9d08d7f2d00a5 to your computer and use it in GitHub Desktop.
Blog Code: Monitoring Rails Requests
# app/middleware/statsd_monitor.rb
class Middleware::StatsDMonitor
def initialize(app)
@app = app
end
def call(env)
@app.call(env)
end
end
# config/application.rb
module DemoApp
class Application < Rails::Application
...
...
config.middleware.insert(0, "Middleware::StatsDMonitor")
end
end
# app/middleware/statsd_monitor.rb
class Middleware::StatsDMonitor
def initialize(app)
@app = app
end
def call(env)
@app.call(env)
end
end
# config/initializers/inflections.rb
ActiveSupport::Inflector.inflections(:en) do |inflect|
# allows Middleware::StatsDMonitor to be loaded from middleware/statsd_monitor.rb
inflect.acronym "StatsD"
end
# config/initializers/statsd.rb
STATSD_REQUEST_METRICS = {
"request.success" => 200,
"request.redirect" => 302,
"request.bad_request" => 400,
"request.not_found" => 404,
"request.too_many_requests" => 429,
"request.internal_server_error" => 500,
"request.bad_gateway" => 502
}.freeze
STATSD_TAGS = ["env:#{Rails.env}"].freeze
StatsD.prefix = "DemoApp"
StatsD.default_sample_rate = 1
Middleware::StatsDMonitor.extend(StatsD::Instrument)
Middleware::StatsDMonitor.statsd_measure(:call, "request.duration", tags: STATSD_TAGS)
STATSD_REQUEST_METRICS.each do |name, code|
Middleware::StatsDMonitor.statsd_count_if(:call, name, tags: STATSD_TAGS) do |status, _env, _body|
status.to_i == code
end
end
# test/integration/statsd_request_monitoring_test.rb
require "test_helper"
class StatsDRequestMonitoringTest < ActionDispatch::IntegrationTest
include StatsD::Instrument::Assertions
test "request duration is measured" do
assert_statsd_measure("#{StatsD.prefix}.request.duration", tags: STATSD_TAGS) do
get "/"
end
end
test "successful requests are counted" do
assert_increment("request.success", 200)
end
test "redirects are counted" do
assert_increment("request.redirect", 302)
end
test "bad requests are counted" do
assert_increment("request.bad_request", 400)
end
test "not found requests are counted" do
assert_increment("request.not_found", 404)
end
test "dropped requests are counted" do
assert_increment("request.too_many_requests", 429)
end
test "internal server errors are counted" do
assert_increment("request.internal_server_error", 500)
end
test "bad gateway requests are counted" do
assert_increment("request.bad_gateway", 502)
end
private
def assert_increment(name, status)
assert_statsd_increment("#{StatsD.prefix}.#{name}", tags: STATSD_TAGS) do
Rack::Runtime.any_instance.stubs(call: [status, {}, ""])
get "/"
end
end
end
source "https://rubygems.org/"
...
...
gem "statsd-instrument"
# config/initializers/inflections.rb
ActiveSupport::Inflector.inflections(:en) do |inflect|
# allows Middleware::StatsDMonitor to be loaded from middleware/statsd_monitor.rb
inflect.acronym "StatsD"
end
# config/initializers/statsd.rb
StatsD.prefix = "DemoApp"
StatsD.default_sample_rate = 1
# config/initializers/statsd.rb
...
...
# send the environment as a tag
STATSD_TAGS = ["env:#{Rails.env}"].freeze
Middleware::StatsDMonitor.extend(StatsD::Instrument)
Middleware::StatsDMonitor.statsd_measure(:call, "request.duration", tags: STATSD_TAGS)
# config/initializers/statsd.rb
STATSD_REQUEST_METRICS = {
"request.success" => 200,
"request.redirect" => 302,
"request.bad_request" => 400,
"request.not_found" => 404,
"request.too_many_requests" => 429,
"request.internal_server_error" => 500,
"request.bad_gateway" => 502
}.freeze
STATSD_REQUEST_METRICS.each do |name, code|
Middleware::StatsDMonitor.statsd_count_if(:call, name, tags: STATSD_TAGS) do |status, _env, _body|
status.to_i == code
end
end
# test/integration/statsd_request_monitoring_test.rb
class StatsDRequestMonitoringTest < ActionDispatch::IntegrationTest
...
...
test "successful requests are counted" do
assert_increment("request.success", 200)
end
test "redirects are counted" do
assert_increment("request.redirect", 302)
end
test "bad requests are counted" do
assert_increment("request.bad_request", 400)
end
test "not found requests are counted" do
assert_increment("request.not_found", 404)
end
test "dropped requests are counted" do
assert_increment("request.too_many_requests", 429)
end
test "internal server errors are counted" do
assert_increment("request.internal_server_error", 500)
end
test "bad gateway requests are counted" do
assert_increment("request.bad_gateway", 502)
end
private
def assert_increment(name, status)
assert_statsd_increment("#{StatsD.prefix}.#{name}", tags: STATSD_TAGS) do
# skip the processing and just return the supplied status
Rack::Runtime.any_instance.stubs(call: [status, {}, ""])
get "/"
end
end
end
# test/integration/statsd_request_monitoring_test.rb
require "test_helper"
class StatsDRequestMonitoringTest < ActionDispatch::IntegrationTest
include StatsD::Instrument::Assertions
test "request duration is measured" do
assert_statsd_measure("#{StatsD.prefix}.request.duration", tags: STATSD_TAGS) do
get "/"
end
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment