1 # -*- encoding: binary -*-
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
10 Stats = Raindrops::Struct.new(:calling, :writing)
11 PATH_INFO = "PATH_INFO"
12 require "raindrops/middleware/proxy"
13 autoload :TCP, "raindrops/middleware/tcp"
16 def initialize(app, opts = {})
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
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?
34 # standard Rack endpoint
36 env[PATH_INFO] == @path and return stats_response
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
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"
60 Raindrops::Linux.unix_listener_stats(@unix).each do |addr,stats|
61 body << "#{addr} active: #{stats.active}\n" \
62 "#{addr} queued: #{stats.queued}\n"
67 "Content-Type" => "text/plain",
68 "Content-Length" => body.size.to_s,
70 [ 200, headers, [ body ] ]