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 < Struct.new(:app, :stats, :path, :tcp, :unix)
9 Stats = Raindrops::Struct.new(:calling, :writing)
10 PATH_INFO = "PATH_INFO"
13 def initialize(app, opts = {})
14 super(app, opts[:stats] || Stats.new, opts[:path] || "/_raindrops")
15 tmp = opts[:listeners]
16 if tmp.nil? && defined?(Unicorn) && Unicorn.respond_to?(:listener_names)
17 tmp = Unicorn.listener_names
21 self.tcp = tmp.grep(/\A[^:]+:\d+\z/)
22 self.unix = tmp.grep(%r{\A/})
23 self.tcp = nil if tcp.empty?
24 self.unix = nil if unix.empty?
28 # standard Rack endpoint
30 env[PATH_INFO] == path ? stats_response : dup._call(env)
35 status, headers, self.app = app.call(env)
37 # the Rack server will start writing headers soon after this method
39 [ status, headers, self ]
44 # yield to the Rack server here for writing
46 app.each { |x| yield x }
49 # the Rack server should call this after #each (usually ensure-d)
52 app.close if app.respond_to?(:close)
56 body = "calling: #{stats.calling}\n" \
57 "writing: #{stats.writing}\n"
59 if defined?(Raindrops::Linux)
60 Raindrops::Linux.tcp_listener_stats(tcp).each do |addr,stats|
61 body << "#{addr} active: #{stats.active}\n" \
62 "#{addr} queued: #{stats.queued}\n"
64 Raindrops::Linux.unix_listener_stats(unix).each do |addr,stats|
65 body << "#{addr} active: #{stats.active}\n" \
66 "#{addr} queued: #{stats.queued}\n"
71 "Content-Type" => "text/plain",
72 "Content-Length" => body.size.to_s,
74 [ 200, headers, [ body ] ]