mongrel_proctitle 1.3

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,93 @@
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
+ Monitoring Mongrels
33
+ -------------------
34
+
35
+ Once the program is installed, you should be able to see the formatted process
36
+ title by running:
37
+
38
+ $ ps -axwwo pid,command | grep mongrel_rails
39
+
40
+ See ps(1) for more options. You may want to include %cpu, rsz, %mem, or other
41
+ fields in output.
42
+
43
+ There's also a `mongrel_top` executable included in the gem that works like
44
+ top(1) but displays only mongrel processes:
45
+
46
+ $ mongrel_top
47
+
48
+ By default, `mongrel_top` updates the display every 0.25 seconds and shows the
49
+ pid and process title. You can select a different interval and fields with the
50
+ -s and -o arguments, respectively:
51
+
52
+ $ mongrel_top -s 0.1 -o pid,%cpu,rsz,command
53
+
54
+ The "command" field must be included.
55
+
56
+ Installation
57
+ ------------
58
+
59
+ This version of the plugin is packaged specifically as a Mongrel GemPlugin. Install
60
+ using:
61
+
62
+ gem install mongrel_proctitle --source=http://tomayko.com
63
+
64
+ Once installed, all new mongrels will automatically load the plugin during startup. If
65
+ you would prefer to control which mongrels load the plugin, do not install this gem.
66
+ Use the directions below instead.
67
+
68
+ Installing into a specific Rails app only
69
+ -----------------------------------------
70
+
71
+ See Alexander Staubo's original project:
72
+
73
+ http://purefiction.net/mongrel_proctitle/
74
+
75
+ Showing your application-specific revision/release in the title
76
+ -------------------------------------------------------------------
77
+
78
+ In your application's start-up process, re-open Mongrel::Proctitler
79
+ and define a get_app_revision method. In a Rails app, a good place
80
+ to do this is in RAILS_ROOT/config/environments/production.rb. An
81
+ example get_app_revision method might look like:
82
+
83
+ def get_app_revision
84
+ `cat ./REVISION`.chomp
85
+ end
86
+
87
+ License
88
+ -------
89
+
90
+ I've included the LICENSE file from the original mongrel_proctitle distribution. It is
91
+ the "New and Simplified BSD License". More information on this license can be found at:
92
+
93
+ http://www.opensource.org/licenses/bsd-license.php
data/Rakefile ADDED
@@ -0,0 +1,42 @@
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
+ # Load gemspec like github to surface SAFE issues early
16
+ require 'rubygems/specification'
17
+ data = File.read('mongrel_proctitle.gemspec')
18
+ spec = nil
19
+ Thread.new { spec = eval("$SAFE = 3\n#{data}") }.join
20
+
21
+ Rake::GemPackageTask.new(spec) do |p|
22
+ p.gem_spec = spec
23
+ p.need_zip = true
24
+ p.need_tar_gz = true
25
+ end
26
+
27
+ task :install => [:package] do
28
+ sh %{gem install pkg/#{name}-#{version}.gem}
29
+ end
30
+
31
+ task :uninstall => [:clean] do
32
+ sh %{gem uninstall #{name}}
33
+ end
34
+
35
+ desc 'Publish gem and tarball to rubyforge'
36
+ task :release => [:package] do
37
+ pkg = "pkg/#{spec.name}-#{spec.version}"
38
+ sh <<-end
39
+ rubyforge add_release wink #{spec.name} #{spec.version} #{pkg}.gem &&
40
+ rubyforge add_file wink #{spec.name} #{spec.version} #{pkg}.tar.gz
41
+ end
42
+ 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,148 @@
1
+ require 'mongrel'
2
+
3
+ module Mongrel
4
+
5
+ # Mongrel process title modification.
6
+ class Proctitler
7
+
8
+ # Initializes titler.
9
+ def initialize(port, prefix)
10
+ @prefix = prefix
11
+ @port = port
12
+ @mutex = Mutex.new
13
+ @titles = []
14
+ @request_threads = []
15
+ @queue_length = 0
16
+ @request_count = 0
17
+ end
18
+
19
+ # Returns port used in title.
20
+ def port
21
+ @port
22
+ end
23
+
24
+ # Return port used in title.
25
+ def port=(new_port)
26
+ @port = new_port
27
+ end
28
+
29
+ # Returns revision used in title.
30
+ def revision
31
+ @revision ||= get_app_revision if self.respond_to?(:get_app_revision)
32
+ end
33
+
34
+ def request(&block)
35
+ titles, mutex = @titles, @mutex
36
+ mutex.synchronize do
37
+ @queue_length += 1
38
+ titles.push(self.title)
39
+ end
40
+ begin
41
+ yield
42
+ ensure
43
+ mutex.synchronize do
44
+ @queue_length -= 1
45
+ @request_count += 1
46
+ @request_threads.delete(Thread.current)
47
+ set_request_list_title
48
+ end
49
+ end
50
+ end
51
+
52
+ def set_request_list_title(excluding = nil)
53
+ if @request_threads.empty?
54
+ set_idle
55
+ else
56
+ if defined?(Rails)
57
+ # find the first awake/critical thread and put it in the front
58
+ running_thread = @request_threads.detect {|thread| thread.status == "run" && excluding != thread }
59
+ @request_threads.unshift(@request_threads.delete(running_thread)) if running_thread
60
+ # this isn't exact, but it works for most situations
61
+ end
62
+ self.title = "handling #{@request_threads.collect {|t| t[:request_str]}.join(', ')}"
63
+ end
64
+ end
65
+
66
+ # Reports process as being idle.
67
+ def set_idle
68
+ self.title = "idle"
69
+ end
70
+
71
+ # Reports process as handling a socket.
72
+ def set_processing(socket)
73
+ self.title = "handling #{socket.peeraddr.last}"
74
+ end
75
+
76
+ # Reports process as handling a socket.
77
+ def set_handling(request)
78
+ params = request.params
79
+ address = params['REMOTE_ADDR']
80
+ method = params['REQUEST_METHOD']
81
+ path = params['REQUEST_PATH']
82
+ path = "#{path[0, 60]}..." if path.length > 60
83
+ Thread.current[:request_str] = "#{address}: #{method} #{path}"
84
+ @request_threads.push(Thread.current)
85
+ set_request_list_title(Thread.current)
86
+ end
87
+
88
+ # Returns current title
89
+ def title
90
+ @title
91
+ end
92
+
93
+ # Sets process title.
94
+ def title=(title)
95
+ @title = title
96
+ update_process_title
97
+ end
98
+
99
+ # Updates the process title.
100
+ def update_process_title
101
+ title = "#{@prefix} ["
102
+ title << (@port ? "#{@port}" : "?")
103
+ title << (revision ? "/r#{revision}" : "")
104
+ title << "/#{@queue_length}"
105
+ title << "/#{@request_count}"
106
+ title << "]: #{@title}"
107
+ $0 = title
108
+ end
109
+
110
+ end
111
+
112
+ # Handler which sets process title before request.
113
+ class ProctitleHandler < HttpHandler
114
+ def initialize(titler)
115
+ @titler = titler
116
+ end
117
+
118
+ def process(request, response)
119
+ @titler.set_handling(request)
120
+ end
121
+ end
122
+
123
+ class HttpServer
124
+
125
+ def run_with_proctitle(*args)
126
+ @titler = Proctitler.new(self.port, File.basename($0))
127
+ @titler.set_idle
128
+ run_without_proctitle
129
+ end
130
+ alias_method :run_without_proctitle, :run
131
+ alias_method :run, :run_with_proctitle
132
+
133
+ def process_client_with_proctitle(client)
134
+ unless @handler
135
+ @handler = ProctitleHandler.new(@titler)
136
+ register("/", @handler, true)
137
+ end
138
+ @titler.request do
139
+ @titler.set_processing(client)
140
+ return process_client_without_proctitle(client)
141
+ end
142
+ end
143
+ alias_method :process_client_without_proctitle, :process_client
144
+ alias_method :process_client, :process_client_with_proctitle
145
+
146
+ end
147
+
148
+ end
@@ -0,0 +1,40 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ Gem::Specification.new do |s|
4
+ s.specification_version = 2 if s.respond_to? :specification_version=
5
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
6
+
7
+ s.name = 'mongrel_proctitle'
8
+ s.version = '1.3'
9
+ s.date = '2009-02-23'
10
+
11
+ s.platform = Gem::Platform::RUBY
12
+ s.summary = "The mongrel_proctitle GemPlugin"
13
+ s.description = s.summary
14
+
15
+ s.authors = ["Alexander Staubo", "Ryan Tomayko", "Arya Asemanfar"]
16
+ s.email = "r@tomayko.com"
17
+ s.homepage = "http://github.com/rtomayko/mongrel_proctitle"
18
+
19
+ s.add_dependency 'mongrel', '>= 1.1'
20
+ s.add_dependency 'gem_plugin', '>= 0.2.3'
21
+
22
+ s.has_rdoc = true
23
+ s.extra_rdoc_files = ["README"]
24
+
25
+ s.files = %w[
26
+ LICENSE
27
+ README
28
+ Rakefile
29
+ mongrel_proctitle.gemspec
30
+ lib/mongrel_proctitle.rb
31
+ bin/mongrel_top
32
+ ]
33
+
34
+ s.bindir = 'bin'
35
+ s.executables = %w[mongrel_top]
36
+ s.require_path = 'lib'
37
+
38
+ s.rubyforge_project = "wink"
39
+ s.rubygems_version = '1.1.1'
40
+ end
metadata ADDED
@@ -0,0 +1,79 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: mongrel_proctitle
3
+ version: !ruby/object:Gem::Version
4
+ version: "1.3"
5
+ platform: ruby
6
+ authors:
7
+ - Alexander Staubo
8
+ - Ryan Tomayko
9
+ - Arya Asemanfar
10
+ autorequire:
11
+ bindir: bin
12
+ cert_chain: []
13
+
14
+ date: 2009-02-23 00:00:00 -08:00
15
+ default_executable:
16
+ dependencies:
17
+ - !ruby/object:Gem::Dependency
18
+ name: mongrel
19
+ type: :runtime
20
+ version_requirement:
21
+ version_requirements: !ruby/object:Gem::Requirement
22
+ requirements:
23
+ - - ">="
24
+ - !ruby/object:Gem::Version
25
+ version: "1.1"
26
+ version:
27
+ - !ruby/object:Gem::Dependency
28
+ name: gem_plugin
29
+ type: :runtime
30
+ version_requirement:
31
+ version_requirements: !ruby/object:Gem::Requirement
32
+ requirements:
33
+ - - ">="
34
+ - !ruby/object:Gem::Version
35
+ version: 0.2.3
36
+ version:
37
+ description: The mongrel_proctitle GemPlugin
38
+ email: r@tomayko.com
39
+ executables:
40
+ - mongrel_top
41
+ extensions: []
42
+
43
+ extra_rdoc_files:
44
+ - README
45
+ files:
46
+ - LICENSE
47
+ - README
48
+ - Rakefile
49
+ - mongrel_proctitle.gemspec
50
+ - lib/mongrel_proctitle.rb
51
+ - bin/mongrel_top
52
+ has_rdoc: true
53
+ homepage: http://github.com/rtomayko/mongrel_proctitle
54
+ post_install_message:
55
+ rdoc_options: []
56
+
57
+ require_paths:
58
+ - lib
59
+ required_ruby_version: !ruby/object:Gem::Requirement
60
+ requirements:
61
+ - - ">="
62
+ - !ruby/object:Gem::Version
63
+ version: "0"
64
+ version:
65
+ required_rubygems_version: !ruby/object:Gem::Requirement
66
+ requirements:
67
+ - - ">="
68
+ - !ruby/object:Gem::Version
69
+ version: "0"
70
+ version:
71
+ requirements: []
72
+
73
+ rubyforge_project: wink
74
+ rubygems_version: 1.3.1
75
+ signing_key:
76
+ specification_version: 2
77
+ summary: The mongrel_proctitle GemPlugin
78
+ test_files: []
79
+