mongrel_proctitle 1.3

Sign up to get free protection for your applications and to get access to all the features.
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
+