rack_proctitle 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (4) hide show
  1. data/LICENSE +22 -0
  2. data/README.md +34 -0
  3. data/lib/rack_proctitle.rb +94 -0
  4. metadata +58 -0
data/LICENSE ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2010 Arya Asemanfar
2
+
3
+ Permission is hereby granted, free of charge, to any person
4
+ obtaining a copy of this software and associated documentation
5
+ files (the "Software"), to deal in the Software without
6
+ restriction, including without limitation the rights to use,
7
+ copy, modify, merge, publish, distribute, sublicense, and/or sell
8
+ copies of the Software, and to permit persons to whom the
9
+ Software is furnished to do so, subject to the following
10
+ conditions:
11
+
12
+ The above copyright notice and this permission notice shall be
13
+ included in all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
17
+ OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
19
+ HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
20
+ WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21
+ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
22
+ OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,34 @@
1
+ # About
2
+ RackProctitle allows you to see what request a given server process is handling. By running "watch -n 0.1 ‘ps aux | grep “USER\|rack” ’ you can see all your rack processes, what request they’re currently handling and for how long (or if they’re idle), what their last request was and how long it took, how many requests have been handled in the life of this process, and the requests in queue.
3
+
4
+ It ends up being really useful to diagnose problems.
5
+
6
+ Example output:
7
+
8
+ rack/14a0b0 [1/682]: handling 0.0s /users/6014086
9
+
10
+ You can set a prefix, which will replace “rack” in the line above, and you can set an _APPLICATION\_VERSION_ constant which will be after the prefix. You can use this to distinguish between different rack processes if you run multiple applications on the same machine.
11
+
12
+ Concept and output formatting is based on Alexander Staubo’s [mongrel\_proctitle][mongrel_proctitle] but has more features, is thread safe, and is Rack compatible. For more information on why mongrel\_proctitle is not thread safe, [read this post][blog_post].
13
+
14
+
15
+ # Usage
16
+ sudo gem install rack_proctitle
17
+
18
+ In some file somewhere (optional):
19
+
20
+ APPLICATION_VERSION = File.read(File.join(RAILS\_ROOT, “REVISION”))[0,6] # if you use Capistrano, which creates a REVISION file for you.
21
+
22
+ In your rackup file (prefix is optional):
23
+
24
+ use RackProctitle, :prefix => “application_name”
25
+
26
+ We use _watch_ to get a continuously updating status of our rack processes:
27
+
28
+ watch -n 0.1 ‘ps aux | grep “USER\|application_name” | grep -v grep ; uptime; hostname’
29
+
30
+ The _watch_ linux utility is one of those things that is hard to Google, so here's the link if it's not installed or not in your package manager: [http://procps.sourceforge.net/](http://procps.sourceforge.net/)
31
+
32
+
33
+ [mongrel_proctitle]: http://github.com/alexstaubo/mongrel_proctitle
34
+ [blog_post]: http://asemanfar.com/Request-Queue-via-Mongrel-Proctitle
@@ -0,0 +1,94 @@
1
+ class RackProctitle
2
+ def initialize(app, options = nil)
3
+ @app = app
4
+
5
+ @title = "#{(options && options.delete(:prefix)) || 'rack'}"
6
+ @title << "/#{APPLICATION_VERSION}" if defined?(APPLICATION_VERSION)
7
+ @title << " [%d/%d]: %s"
8
+
9
+ @mutex = Mutex.new
10
+ @request_threads = []
11
+ @total_request_count = 0
12
+
13
+ start_updater_thread
14
+ end
15
+
16
+ def call(env)
17
+ ensure_updater_thread_running
18
+ Thread.current[:request_str] = ((env["REQUEST_URI"].nil? || env["REQUEST_URI"].empty?) ? "/" : env["REQUEST_URI"]).split("?", 2)[0]
19
+ Thread.current[:arrived_at] = Time.now.to_f
20
+ @mutex.synchronize do
21
+ @request_threads.push(Thread.current)
22
+ set_request_list_title
23
+ end
24
+
25
+ begin
26
+ @app.call(env)
27
+ ensure
28
+ @mutex.synchronize do
29
+ @total_request_count += 1
30
+
31
+ @last_time = Time.now.to_f - Thread.current[:arrived_at].to_f
32
+ @last_request_str = Thread.current[:request_str].to_s
33
+
34
+ @request_threads.delete(Thread.current)
35
+ set_request_list_title
36
+ end
37
+ end
38
+ end
39
+
40
+ protected
41
+ # This exists for cases like unicorn where the instance initialized and then the process is forked.
42
+ # Threads don't live through forks, so we have to start a new one inside each new process.
43
+ def ensure_updater_thread_running
44
+ if @pid != ::Process.pid
45
+ start_updater_thread
46
+ end
47
+ end
48
+
49
+ def start_updater_thread
50
+ @updater_thread.kill if @updater_thread
51
+ @pid = ::Process.pid
52
+ @updater_thread = Thread.new do
53
+ while true
54
+ @mutex.synchronize do
55
+ set_request_list_title
56
+ end
57
+ sleep 0.5
58
+ end
59
+ end
60
+ end
61
+
62
+ def set_request_list_title
63
+ current_status = if @request_threads.empty?
64
+ idle_message
65
+ else
66
+ now = Time.now.to_f
67
+ list = @request_threads.inject([]) do |str, thread|
68
+ str << "#{time_delta_abbriv(now - thread[:arrived_at])} #{thread[:request_str]}"
69
+ end.join(" | ")
70
+ "handling #{list}"
71
+ end
72
+
73
+ $0 = @title % [@request_threads.size, @total_request_count, current_status]
74
+ end
75
+
76
+ def idle_message
77
+ str = "idle#{' '*20}" # the spacing is for visual distinction in a list of processes.
78
+ str << "[last #{time_delta_abbriv(@last_time)} #{@last_request_str}]" if @last_time && @last_request_str
79
+ str
80
+ end
81
+
82
+ TIME_DELTA_STRS = %w{%.1fs %dm%ds %dh%dm %dd%dh}
83
+ def time_delta_abbriv(delta)
84
+ if delta < 60
85
+ TIME_DELTA_STRS[0] % delta
86
+ elsif delta < 3600
87
+ TIME_DELTA_STRS[1] % [delta.to_i / 60, delta.to_i % 60]
88
+ elsif delta < 86400
89
+ TIME_DELTA_STRS[2] % [delta.to_i / 3600, (delta.to_i % 3600) / 60]
90
+ else
91
+ TIME_DELTA_STRS[3] % [delta.to_i / 86400, (delta.to_i % 86400) / 3600]
92
+ end
93
+ end
94
+ end
metadata ADDED
@@ -0,0 +1,58 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: rack_proctitle
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ platform: ruby
6
+ authors:
7
+ - Arya Asemanfar
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2010-01-16 00:00:00 -08:00
13
+ default_executable:
14
+ dependencies: []
15
+
16
+ description:
17
+ email: aryaasemanfar@gmail.com
18
+ executables: []
19
+
20
+ extensions: []
21
+
22
+ extra_rdoc_files:
23
+ - LICENSE
24
+ - README.md
25
+ files:
26
+ - lib/rack_proctitle.rb
27
+ - LICENSE
28
+ - README.md
29
+ has_rdoc: true
30
+ homepage: http://github.com/arya/rack_proctitle
31
+ licenses: []
32
+
33
+ post_install_message:
34
+ rdoc_options:
35
+ - --charset=UTF-8
36
+ require_paths:
37
+ - lib
38
+ required_ruby_version: !ruby/object:Gem::Requirement
39
+ requirements:
40
+ - - ">="
41
+ - !ruby/object:Gem::Version
42
+ version: "0"
43
+ version:
44
+ required_rubygems_version: !ruby/object:Gem::Requirement
45
+ requirements:
46
+ - - ">="
47
+ - !ruby/object:Gem::Version
48
+ version: "0"
49
+ version:
50
+ requirements: []
51
+
52
+ rubyforge_project:
53
+ rubygems_version: 1.3.5
54
+ signing_key:
55
+ specification_version: 3
56
+ summary: A utility to update the proctite of Rack process with helpful information.
57
+ test_files: []
58
+