freels-mongrel_proctitle 1.3.5.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/LICENSE ADDED
@@ -0,0 +1,27 @@
1
+ Copyright (c) 2008, Ryan Tomayko
2
+ Copyright (c) 2007, Alexander Staubo
3
+
4
+ All rights reserved.
5
+
6
+ Redistribution and use in source and binary forms, with or without modification, are
7
+ permitted provided that the following conditions are met:
8
+
9
+ * Redistributions of source code must retain the above copyright notice, this list of
10
+ conditions and the following disclaimer.
11
+
12
+ * Redistributions in binary form must reproduce the above copyright notice, this list
13
+ of conditions and the following disclaimer in the documentation and/or other materials
14
+ provided with the distribution.
15
+
16
+ * The names of its contributors may be used to endorse or promote products derived from
17
+ this software without specific prior written permission.
18
+
19
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND WITHOUT ANY
20
+ EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
21
+ MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
22
+ COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
23
+ EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
24
+ GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
25
+ ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
26
+ OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27
+ POSSIBILITY OF SUCH DAMAGE.
data/README ADDED
@@ -0,0 +1,96 @@
1
+ Mongrel process title GemPlugin
2
+ ===============================
3
+
4
+ This is a simple plugin for Mongrel which changes the process title to reflect
5
+ what it's currently doing. You can then determine a given Mongrel server's
6
+ status using "ps".
7
+
8
+ For example:
9
+
10
+ mongrel_rails [10010/2/358]: handling 127.0.0.1: HEAD /feed/cal/global/91/6de4, GET /feed/index
11
+ | | | | | |
12
+ | | | | | The current req (method / path)
13
+ | | | | |
14
+ | | | | The client IP
15
+ | | | |
16
+ | | | What it's doing
17
+ | | |
18
+ | | Requests processed during server lifetime
19
+ | |
20
+ | Requests currently queued/being processed concurrently
21
+ |
22
+ The port that Mongrel is serving
23
+
24
+ This is almost entirely based on Alexander Staubo's Rails plugin with the same
25
+ name:
26
+
27
+ http://purefiction.net/mongrel_proctitle/
28
+
29
+ The main difference is that the GemPlugin will automatically be loaded by all
30
+ mongrels without additional code changes or configuration.
31
+
32
+ This is a fork of rtomayko's fork of mongrel_proctitle that displays the current request
33
+ instead of the most recent received request, as well a list of the request queue.
34
+
35
+ Monitoring Mongrels
36
+ -------------------
37
+
38
+ Once the program is installed, you should be able to see the formatted process
39
+ title by running:
40
+
41
+ $ ps -axwwo pid,command | grep mongrel_rails
42
+
43
+ See ps(1) for more options. You may want to include %cpu, rsz, %mem, or other
44
+ fields in output.
45
+
46
+ There's also a `mongrel_top` executable included in the gem that works like
47
+ top(1) but displays only mongrel processes:
48
+
49
+ $ mongrel_top
50
+
51
+ By default, `mongrel_top` updates the display every 0.25 seconds and shows the
52
+ pid and process title. You can select a different interval and fields with the
53
+ -s and -o arguments, respectively:
54
+
55
+ $ mongrel_top -s 0.1 -o pid,%cpu,rsz,command
56
+
57
+ The "command" field must be included.
58
+
59
+ Installation
60
+ ------------
61
+
62
+ This version of the plugin is packaged specifically as a Mongrel GemPlugin. Install
63
+ using:
64
+
65
+ gem install mongrel_proctitle --source=http://tomayko.com
66
+
67
+ Once installed, all new mongrels will automatically load the plugin during startup. If
68
+ you would prefer to control which mongrels load the plugin, do not install this gem.
69
+ Use the directions below instead.
70
+
71
+ Installing into a specific Rails app only
72
+ -----------------------------------------
73
+
74
+ See Alexander Staubo's original project:
75
+
76
+ http://purefiction.net/mongrel_proctitle/
77
+
78
+ Showing your application-specific revision/release in the title
79
+ -------------------------------------------------------------------
80
+
81
+ In your application's start-up process, re-open Mongrel::Proctitler
82
+ and define a get_app_revision method. In a Rails app, a good place
83
+ to do this is in RAILS_ROOT/config/environments/production.rb. An
84
+ example get_app_revision method might look like:
85
+
86
+ def get_app_revision
87
+ `cat ./REVISION`.chomp
88
+ end
89
+
90
+ License
91
+ -------
92
+
93
+ I've included the LICENSE file from the original mongrel_proctitle distribution. It is
94
+ the "New and Simplified BSD License". More information on this license can be found at:
95
+
96
+ http://www.opensource.org/licenses/bsd-license.php
data/Rakefile ADDED
@@ -0,0 +1,60 @@
1
+ require 'rake'
2
+ require 'rake/testtask'
3
+ require 'rake/clean'
4
+ require 'rake/gempackagetask'
5
+ require 'rake/rdoctask'
6
+ require 'rake/contrib/rubyforgepublisher'
7
+ require 'fileutils'
8
+ include FileUtils
9
+
10
+ CLEAN.include [ "pkg", "lib/*.bundle", "*.gem", ".config", "**/*.log" ]
11
+
12
+ desc "Build package"
13
+ task :default => [:package]
14
+
15
+ version = "1.2.5"
16
+ name = "mongrel_proctitle"
17
+
18
+ spec =
19
+ Gem::Specification.new do |s|
20
+ s.name = name
21
+ s.version = version
22
+ s.platform = Gem::Platform::RUBY
23
+ s.summary = "The mongrel_proctitle GemPlugin"
24
+ s.description = s.summary
25
+ s.author = "Ryan Tomayko"
26
+ s.email = "rtomayko@gmail.com"
27
+ s.homepage = "http://github.com/rtomayko/mongrel_proctitle"
28
+ s.add_dependency('mongrel', '>= 1.1')
29
+ s.add_dependency('gem_plugin', '>= 0.2.3')
30
+ s.has_rdoc = true
31
+ s.extra_rdoc_files = [ "README" ]
32
+ s.bindir = "bin"
33
+ s.executables = [ "mongrel_top" ]
34
+ s.files = %w(LICENSE README Rakefile) +
35
+ Dir.glob("{bin,doc/rdoc,test,lib}/**/*")
36
+ s.require_path = "lib"
37
+ s.rubyforge_project = "orphans"
38
+ end
39
+
40
+ Rake::GemPackageTask.new(spec) do |p|
41
+ p.gem_spec = spec
42
+ p.need_zip = true
43
+ p.need_tar_gz = true
44
+ end
45
+
46
+ task :install => [:package] do
47
+ sh %{gem install pkg/#{name}-#{version}.gem}
48
+ end
49
+
50
+ task :uninstall => [:clean] do
51
+ sh %{gem uninstall #{name}}
52
+ end
53
+
54
+ desc 'Publish gems and other distributables to tomayko.com'
55
+ task :release => [:package] do
56
+ sh <<-end
57
+ ssh tomayko.com 'mkdir -p /dist/#{name}' && \
58
+ rsync -azP pkg/#{name}-#{version}.* tomayko.com:/dist/#{name}/
59
+ end
60
+ end
data/bin/mongrel_top ADDED
@@ -0,0 +1,92 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ $last_update = nil
4
+ $clear_char = `tput clear`
5
+
6
+ def usage
7
+ puts "usage: #{File.basename($0)} [-s delay] [-o fields]"
8
+ end
9
+
10
+ def die(*message)
11
+ STDERR.puts "fatal: #{format(*message)}" if message.any?
12
+ exit 1
13
+ end
14
+
15
+ # clear the terminal
16
+ def clear_screen
17
+ STDOUT.write($clear_char)
18
+ end
19
+
20
+ # clear the terminal and then write output.
21
+ def update_screen(output)
22
+ if output != $last_update
23
+ clear_screen
24
+ puts(output)
25
+ end
26
+ end
27
+
28
+ def terminal_columns
29
+ @terminal_columns ||=
30
+ if (cols = `tput cols`) == ""
31
+ 80
32
+ else
33
+ cols.to_i
34
+ end
35
+ end
36
+
37
+ trap("INT") {
38
+ STDERR.puts "\nbailing ..."
39
+ exit 0
40
+ }
41
+
42
+ # time to wait between updates
43
+ interval = 0.25
44
+
45
+ # the fields to show in our display (see ps -o)
46
+ fields = "pid,command"
47
+
48
+ # parse arguments.
49
+ # TODO: use getoptlong
50
+ argv = ARGV.map { |a| a.split('=', 2) }.flatten
51
+ while argv.any?
52
+ arg = argv.shift
53
+ case arg
54
+ when /^-(s|-delay)$/
55
+ interval = argv.shift.to_f
56
+ when /^-(o|-fields)$/
57
+ fields = argv.shift
58
+ when /^-(h|-help)$/
59
+ usage and exit(0)
60
+ else
61
+ usage and die
62
+ end
63
+ end
64
+
65
+ # Builds the process output display.
66
+ def process_display(fields, interval)
67
+ now = Time.now.strftime('%a %b %d %H:%M:%S %Y')
68
+ cols = terminal_columns
69
+ processes =
70
+ `ps axww -o #{fields}`.grep(/mongrel_rails/).map do |line|
71
+ line.strip!
72
+ line.sub! /\s+SHELL=.*$/, '' # weird MacOS X issue
73
+ line.sub! /(?:ruby\d*: )?mongrel_rails /, '' # remove $0 prefix
74
+ line.sub! /\(ruby\d*\)/, '' # remove (ruby) suffix
75
+ line[0,cols].chomp
76
+ end
77
+ output = [
78
+ (' ' * (cols - now.length)) + now + "\r" +
79
+ "Mongrel Top (delay: #{interval})",
80
+ "",
81
+ processes,
82
+ "",
83
+ "#{processes.length} process(es)"
84
+ ]
85
+ output.flatten.join("\n")
86
+ end
87
+
88
+ while true
89
+ output = process_display(fields, interval)
90
+ update_screen(output)
91
+ sleep(interval)
92
+ end
@@ -0,0 +1,3 @@
1
+ require 'mongrel'
2
+ require 'gem_plugin'
3
+ require 'mongrel_proctitle'
@@ -0,0 +1,181 @@
1
+ module Mongrel
2
+
3
+ # Mongrel process title modification.
4
+ class Proctitler
5
+
6
+ # Initializes titler.
7
+ def initialize(port, prefix)
8
+ @prefix = prefix
9
+ @port = port
10
+ @mutex = Mutex.new
11
+ @titles = []
12
+ @request_threads = []
13
+ @queue_length = 0
14
+ @request_count = 0
15
+
16
+ @updater_thread = Thread.new do
17
+ while true
18
+ @mutex.synchronize do
19
+ set_request_list_title
20
+ end
21
+ sleep 0.5
22
+ end
23
+ end
24
+ end
25
+
26
+ # Returns port used in title.
27
+ def port
28
+ @port
29
+ end
30
+
31
+ # Return port used in title.
32
+ def port=(new_port)
33
+ @port = new_port
34
+ end
35
+
36
+ # Returns revision used in title.
37
+ def revision
38
+ @revision ||= get_app_revision if self.respond_to?(:get_app_revision)
39
+ end
40
+
41
+ def request(&block)
42
+ titles, mutex = @titles, @mutex
43
+ mutex.synchronize do
44
+ @queue_length += 1
45
+ titles.push(self.title)
46
+ end
47
+ begin
48
+ yield
49
+ ensure
50
+ mutex.synchronize do
51
+ @queue_length -= 1
52
+ @request_count += 1
53
+
54
+ @last_time = Time.now.to_f - Thread.current[:arrived_at].to_f
55
+ @last_request_str = Thread.current[:request_str].to_s
56
+
57
+ @request_threads.delete(Thread.current)
58
+ set_request_list_title
59
+ end
60
+ end
61
+ end
62
+
63
+ def set_request_list_title(excluding = nil)
64
+ if @request_threads.empty?
65
+ set_idle
66
+ else
67
+ if defined?(Rails)
68
+ # find the first awake/critical thread and put it in the front
69
+ running_thread = @request_threads.detect {|thread| thread.status == "run" && excluding != thread }
70
+ @request_threads.unshift(@request_threads.delete(running_thread)) if running_thread
71
+ # this isn't exact, but it works for most situations
72
+ end
73
+ now = Time.now.to_f
74
+ list = @request_threads.inject([]) do |str, thread|
75
+ str << "#{time_delta_abbriv(now - thread[:arrived_at])} #{thread[:request_str]}"
76
+ end.join(" | ")
77
+ self.title = "handling #{list}"
78
+ end
79
+ end
80
+
81
+ def time_delta_abbriv(delta)
82
+ if delta < 60
83
+ "%.1fs" % delta
84
+ elsif delta < 3600
85
+ "#{delta.to_i / 60}m#{delta.to_i % 60}s"
86
+ elsif delta < 86400
87
+ "#{delta.to_i / 3600}h#{(delta.to_i % 3600) / 60}m"
88
+ else
89
+ "#{delta.to_i / 86400}d#{(delta.to_i % 86400) / 3600}h"
90
+ end
91
+ end
92
+
93
+ # Reports process as being idle.
94
+ def set_idle
95
+ str = "idle#{' '*20}"
96
+ str << "[last #{time_delta_abbriv(@last_time)} #{@last_request_str}]" if @last_time && @last_request_str
97
+ self.title = str
98
+ end
99
+
100
+ # Reports process as handling a socket.
101
+ def set_processing(socket)
102
+ self.title = "handling #{socket.peeraddr.last}"
103
+ end
104
+
105
+ # Reports process as handling a socket.
106
+ def set_handling(request)
107
+ params = request.params
108
+ address = params['REMOTE_ADDR']
109
+ method = params['REQUEST_METHOD']
110
+ path = params['REQUEST_PATH']
111
+ # path = "#{path[0, 60]}..." if path.length > 60
112
+ # Thread.current[:request_str] = "#{address}: #{method} #{path}"
113
+ Thread.current[:request_str] = "#{method} #{path}"
114
+ Thread.current[:arrived_at] = Time.now.to_f
115
+ @mutex.synchronize do
116
+ @request_threads.push(Thread.current)
117
+ set_request_list_title(Thread.current)
118
+ end
119
+ end
120
+
121
+ # Returns current title
122
+ def title
123
+ @title
124
+ end
125
+
126
+ # Sets process title.
127
+ def title=(title)
128
+ @title = title
129
+ update_process_title
130
+ end
131
+
132
+ # Updates the process title.
133
+ def update_process_title
134
+ title = "#{@prefix} ["
135
+ title << (@port ? "#{@port}" : "?")
136
+ title << (revision ? "/r#{revision}" : "")
137
+ title << "/#{@queue_length}"
138
+ title << "/#{@request_count}"
139
+ title << "]: #{@title}"
140
+ $0 = title
141
+ end
142
+
143
+ end
144
+
145
+ # Handler which sets process title before request.
146
+ class ProctitleHandler < HttpHandler
147
+ def initialize(titler)
148
+ @titler = titler
149
+ end
150
+
151
+ def process(request, response)
152
+ @titler.set_handling(request)
153
+ end
154
+ end
155
+
156
+ class HttpServer
157
+
158
+ def run_with_proctitle(*args)
159
+ @titler = Proctitler.new(self.port, File.basename($0))
160
+ @titler.set_idle
161
+ run_without_proctitle
162
+ end
163
+ alias_method :run_without_proctitle, :run
164
+ alias_method :run, :run_with_proctitle
165
+
166
+ def process_client_with_proctitle(client)
167
+ unless @handler
168
+ @handler = ProctitleHandler.new(@titler)
169
+ register("/", @handler, true)
170
+ end
171
+ @titler.request do
172
+ @titler.set_processing(client)
173
+ return process_client_without_proctitle(client)
174
+ end
175
+ end
176
+ alias_method :process_client_without_proctitle, :process_client
177
+ alias_method :process_client, :process_client_with_proctitle
178
+
179
+ end
180
+
181
+ end
metadata ADDED
@@ -0,0 +1,77 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: freels-mongrel_proctitle
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.3.5.1
5
+ platform: ruby
6
+ authors:
7
+ - Arya Asemanfar
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2009-04-08 00:00:00 -07:00
13
+ default_executable:
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: mongrel
17
+ type: :runtime
18
+ version_requirement:
19
+ version_requirements: !ruby/object:Gem::Requirement
20
+ requirements:
21
+ - - ">="
22
+ - !ruby/object:Gem::Version
23
+ version: "1.1"
24
+ version:
25
+ - !ruby/object:Gem::Dependency
26
+ name: gem_plugin
27
+ type: :runtime
28
+ version_requirement:
29
+ version_requirements: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: 0.2.3
34
+ version:
35
+ description: The mongrel_proctitle Gem
36
+ email: arya@seriousbusiness.com
37
+ executables:
38
+ - mongrel_top
39
+ extensions: []
40
+
41
+ extra_rdoc_files:
42
+ - README
43
+ files:
44
+ - LICENSE
45
+ - README
46
+ - Rakefile
47
+ - bin/mongrel_top
48
+ - lib/mongrel_proctitle.rb
49
+ - lib/arya-mongrel_proctitle/init.rb
50
+ has_rdoc: true
51
+ homepage: http://github.com/arya/mongrel_proctitle
52
+ post_install_message:
53
+ rdoc_options: []
54
+
55
+ require_paths:
56
+ - lib
57
+ required_ruby_version: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: "0"
62
+ version:
63
+ required_rubygems_version: !ruby/object:Gem::Requirement
64
+ requirements:
65
+ - - ">="
66
+ - !ruby/object:Gem::Version
67
+ version: "0"
68
+ version:
69
+ requirements: []
70
+
71
+ rubyforge_project:
72
+ rubygems_version: 1.2.0
73
+ signing_key:
74
+ specification_version: 2
75
+ summary: The mongrel_proctitle Gem
76
+ test_files: []
77
+