Project

io_monitor

0.05
There's a lot of open issues
A gem that helps to detect potential memory bloats
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
 Dependencies

Development

>= 4.0

Runtime

>= 6.0
 Project Readme

IoMonitor

Gem Version Tests status

A gem that helps to detect potential memory bloats.

When your controller loads a lot of data to the memory but returns a small response to the client it might mean that you're using the IO in the non–optimal way. In this case, you'll see the following message in your logs:

Completed 200 OK in 349ms (Views: 2.1ms | ActiveRecord: 38.7ms | ActiveRecord Payload: 866.00 B | Response Payload: 25.00 B | Allocations: 72304)

Usage

Add this line to your application's Gemfile:

gem 'io_monitor'

Currently gem can collect the data from ActiveRecord, Net::HTTP and Redis.

Change configuration in an initializer if you need:

IoMonitor.configure do |config|
  config.publish = [:logs, :notifications, :prometheus] # defaults to :logs
  config.warn_threshold = 0.8 # defaults to 0
  config.adapters = [:active_record, :net_http, :redis] # defaults to [:active_record]
end

Then include the concern into your controller:

class MyController < ApplicationController
  include IoMonitor::Controller
end

Depending on configuration when IO payload size to response payload size ratio reaches the threshold either a warn_threshold_reached.io_monitor notification will be sent or a following warning will be logged:

ActiveRecord I/O to response payload ratio is 0.1, while threshold is 0.8

Prometheus metrics example:

...
# TYPE io_monitor_ratio histogram
# HELP io_monitor_ratio IO payload size to response payload size ratio
io_monitor_ratio_bucket{adapter="active_record",le="0.01"} 0.0
io_monitor_ratio_bucket{adapter="active_record",le="5"} 2.0
io_monitor_ratio_bucket{adapter="active_record",le="10"} 2.0
io_monitor_ratio_bucket{adapter="active_record",le="+Inf"} 2.0
io_monitor_ratio_sum{adapter="active_record"} 0.15779381908414167
io_monitor_ratio_count{adapter="active_record"} 2.0
...

If you want to customize Prometheus publisher you can pass it as object:

IoMonitor.configure do |config|
  config.publish = [
    IoMonitor::PrometheusPublisher.new(
      registry: custom_registry, # defaults to Prometheus::Client.registry
      aggregation: :max, # defaults to nil
      buckets: [0.1, 5, 10] # defaults to Prometheus::Client::Histogram::DEFAULT_BUCKETS
    )
  ]
end

In addition, if publish is set to logs, additional data will be logged on each request:

Completed 200 OK in 349ms (Views: 2.1ms | ActiveRecord: 38.7ms | ActiveRecord Payload: 866.00 B | Response Payload: 25.00 B | Allocations: 72304)

If you want to inspect payload sizes, check out payload data for the process_action.action_controller event:

ActiveSupport::Notifications.subscribe("process_action.action_controller") do |name, start, finish, id, payload|
  payload[:io_monitor] # { active_record: 866, response: 25 }
end

Per–action monitoring

Since this approach can lead to false–positives or other things you don't want or cannot fix, there is a way to configure monitoring only for specific actions:

class MyController < ApplicationController
  include IoMonitor::Controller

  monitor_io_for :index, :show
end

Custom publishers

Implement your custom publisher by inheriting from BasePublisher:

class MyPublisher < IoMonitor::BasePublisher
  def publish(source, ratio)
    puts "Warn threshold reched for #{source} at #{ratio}!"
  end
end

Then specify it in the configuration:

IoMonitor.configure do |config|
  config.publish = MyPublisher.new
end

Custom adapters

Implement your custom adapter by inheriting from BaseAdapter:

class MyAdapter < IoMonitor::BaseAdapter
  def self.kind
    :my_source
  end

  def initialize!
    # Take a look at `AbstractAdapterPatch` for an example.
  end
end

Then specify it in the configuration:

IoMonitor.configure do |config|
  config.adapters = [:active_record, MyAdapter.new]
end

Development

After checking out the repo, run bin/setup to install dependencies. Then, run rake spec to run the tests.

Credits

Initially sponsored by Evil Martians.

Contributing

Bug reports and pull requests are welcome on GitHub at https://github.com/DmitryTsepelev/io_monitor.

License

The gem is available as open source under the terms of the MIT License.

Credits

Thanks to @prog-supdex and @maxshend for building the initial implementations (see PR#2 and PR#3).