preliminary Rack app to track last_data_recv
[raindrops.git] / lib / raindrops / middleware.rb
blobd45fa1a00d368c1db6259c3fad845666423908cb
1 # -*- encoding: binary -*-
2 require 'raindrops'
4 # Raindrops middleware should be loaded at the top of Rack
5 # middleware stack before other middlewares for maximum accuracy.
6 class Raindrops::Middleware
7   attr_accessor :app, :stats, :path, :tcp, :unix
9   # :stopdoc:
10   Stats = Raindrops::Struct.new(:calling, :writing)
11   PATH_INFO = "PATH_INFO"
12   require "raindrops/middleware/proxy"
13   autoload :TCP, "raindrops/middleware/tcp"
14   # :startdoc:
16   def initialize(app, opts = {})
17     @app = app
18     @stats = opts[:stats] || Stats.new
19     @path = opts[:path] || "/_raindrops"
20     tmp = opts[:listeners]
21     if tmp.nil? && defined?(Unicorn) && Unicorn.respond_to?(:listener_names)
22       tmp = Unicorn.listener_names
23     end
24     @tcp = @unix = nil
26     if tmp
27       @tcp = tmp.grep(/\A.+:\d+\z/)
28       @unix = tmp.grep(%r{\A/})
29       @tcp = nil if @tcp.empty?
30       @unix = nil if @unix.empty?
31     end
32   end
34   # standard Rack endpoint
35   def call(env)
36     env[PATH_INFO] == @path and return stats_response
37     begin
38       @stats.incr_calling
40       status, headers, body = @app.call(env)
41       rv = [ status, headers, Proxy.new(body, @stats) ]
43       # the Rack server will start writing headers soon after this method
44       @stats.incr_writing
45       rv
46     ensure
47       @stats.decr_calling
48     end
49   end
51   def stats_response
52     body = "calling: #{@stats.calling}\n" \
53            "writing: #{@stats.writing}\n"
55     if defined?(Raindrops::Linux)
56       Raindrops::Linux.tcp_listener_stats(@tcp).each do |addr,stats|
57         body << "#{addr} active: #{stats.active}\n" \
58                 "#{addr} queued: #{stats.queued}\n"
59       end if @tcp
60       Raindrops::Linux.unix_listener_stats(@unix).each do |addr,stats|
61         body << "#{addr} active: #{stats.active}\n" \
62                 "#{addr} queued: #{stats.queued}\n"
63       end if @unix
64     end
66     headers = {
67       "Content-Type" => "text/plain",
68       "Content-Length" => body.size.to_s,
69     }
70     [ 200, headers, [ body ] ]
71   end
72 end