raindrops 0.12.0 - compatibility fixes
[raindrops.git] / lib / raindrops / last_data_recv.rb
blobf96a776aeeed6fba2bbf5f7223290970f44a587c
1 # -*- encoding: binary -*-
2 require "raindrops"
4 # This is highly experimental!
6 # A self-contained Rack application for aggregating in the
7 # +tcpi_last_data_recv+ field in +struct+ +tcp_info+ defined in
8 # +/usr/include/linux/tcp.h+.  This is only useful for \Linux 2.6 and later.
9 # This primarily supports Unicorn and derived servers, but may also be
10 # used with any Ruby web server using the core TCPServer class in Ruby.
12 # Hitting the Rack endpoint configured for this application will return
13 # a an ASCII histogram response body with the following headers:
15 # - X-Count   - number of requests received
17 # The following headers are only present if X-Count is greater than one.
19 # - X-Min     - lowest last_data_recv time recorded (in milliseconds)
20 # - X-Max     - highest last_data_recv time recorded (in milliseconds)
21 # - X-Mean    - mean last_data_recv time recorded (rounded, in milliseconds)
22 # - X-Std-Dev - standard deviation of last_data_recv times
23 # - X-Outliers-Low - number of low outliers (hopefully many!)
24 # - X-Outliers-High - number of high outliers (hopefully zero!)
26 # == To use with Unicorn and derived servers (preload_app=false):
28 # Put the following in our Unicorn config file (not config.ru):
30 #   require "raindrops/last_data_recv"
32 # Then follow the instructions below for config.ru:
34 # == To use with any Rack server using TCPServer
36 # Setup a route for Raindrops::LastDataRecv in your Rackup config file
37 # (typically config.ru):
39 #   require "raindrops"
40 #   map "/raindrops/last_data_recv" do
41 #     run Raindrops::LastDataRecv.new
42 #   end
43 #   map "/" do
44 #     use SomeMiddleware
45 #     use MoreMiddleware
46 #     # ...
47 #     run YourAppHere.new
48 #   end
50 # == To use with any other Ruby web server that uses TCPServer
52 # Put the following in any piece of Ruby code loaded after the server has
53 # bound its TCP listeners:
55 #   ObjectSpace.each_object(TCPServer) do |s|
56 #     s.extend Raindrops::Aggregate::LastDataRecv
57 #   end
59 #   Thread.new do
60 #     Raindrops::Aggregate::LastDataRecv.default_aggregate.master_loop
61 #   end
63 # Then follow the above instructions for config.ru
65 class Raindrops::LastDataRecv
66   # :stopdoc:
68   # trigger autoloads
69   if defined?(Unicorn)
70     agg = Raindrops::Aggregate::LastDataRecv.default_aggregate
71     AGGREGATE_THREAD = Thread.new { agg.master_loop }
72   end
73   # :startdoc
75   def initialize(opts = {})
76     Raindrops::Aggregate::LastDataRecv.cornify! if defined?(Unicorn)
77     @aggregate =
78       opts[:aggregate] || Raindrops::Aggregate::LastDataRecv.default_aggregate
79   end
81   def call(_)
82     a = @aggregate
83     count = a.count
84     headers = {
85       "Content-Type" => "text/plain",
86       "X-Count" => count.to_s,
87     }
88     if count > 1
89       headers["X-Min"] = a.min.to_s
90       headers["X-Max"] = a.max.to_s
91       headers["X-Mean"] = a.mean.round.to_s
92       headers["X-Std-Dev"] = a.std_dev.round.to_s
93       headers["X-Outliers-Low"] = a.outliers_low.to_s
94       headers["X-Outliers-High"] = a.outliers_high.to_s
95     end
96     body = a.to_s
97     headers["Content-Length"] = body.size.to_s
98     [ 200, headers, [ body ] ]
99   end