RailsRemoteControl 1.0.0

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.
@@ -0,0 +1,7 @@
1
+ = 1.0.0 / 2007-01-02
2
+
3
+ * Birthday!
4
+ * Monitor processes
5
+ * Control process log level without restarts
6
+ * Logs actions handled and count per process
7
+
@@ -0,0 +1,27 @@
1
+ Copyright 2006 Eric Hodel, The Robot Co-op. All rights reserved.
2
+
3
+ Redistribution and use in source and binary forms, with or without
4
+ modification, are permitted provided that the following conditions
5
+ are met:
6
+
7
+ 1. Redistributions of source code must retain the above copyright
8
+ notice, this list of conditions and the following disclaimer.
9
+ 2. Redistributions in binary form must reproduce the above copyright
10
+ notice, this list of conditions and the following disclaimer in the
11
+ documentation and/or other materials provided with the distribution.
12
+ 3. Neither the names of the authors nor the names of their contributors
13
+ may be used to endorse or promote products derived from this software
14
+ without specific prior written permission.
15
+
16
+ THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS
17
+ OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18
+ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19
+ ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE
20
+ LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
21
+ OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
22
+ OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
23
+ BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
24
+ WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
25
+ OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
26
+ EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
+
@@ -0,0 +1,21 @@
1
+ History.txt
2
+ LICENSE.txt
3
+ Manifest.txt
4
+ README.txt
5
+ Rakefile
6
+ bin/rails_remote_control
7
+ lib/rails_remote_control.rb
8
+ lib/rails_remote_control/http_server.rb
9
+ lib/rails_remote_control/process.rb
10
+ lib/rails_remote_control/remote.rb
11
+ lib/rails_remote_control/remote/server.rb
12
+ lib/rails_remote_control/server.rb
13
+ lib/rails_remote_control/servlet.rb
14
+ test/test_rails_remote_control.rb
15
+ test/test_rails_remote_control_http_server.rb
16
+ test/test_rails_remote_control_process.rb
17
+ test/test_rails_remote_control_remote.rb
18
+ test/test_rails_remote_control_remote_server.rb
19
+ test/test_rails_remote_control_server.rb
20
+ test/test_rails_remote_control_servlet.rb
21
+ test/util.rb
@@ -0,0 +1,38 @@
1
+ RailsRemoteControl by Eric Hodel <drbrain@segment7.net>
2
+
3
+ http://seattlerb.rubyforge.org/RailsRemoteControl
4
+
5
+ == DESCRIPTION:
6
+
7
+ Rails Remote Control allows you to attach to running Rails processes
8
+ using DRb and change the log level without restarts. Also, view
9
+ actions handled per process.
10
+
11
+ == FEATURES/PROBLEMS:
12
+
13
+ * Monitor processes
14
+ * Control process log level without restarts
15
+ * Logs actions handled and count per process
16
+
17
+ == SYNOPSYS:
18
+
19
+ See RailsRemoteControl:
20
+
21
+ ri RailsRemoteControl
22
+
23
+ == REQUIREMENTS:
24
+
25
+ * A Rails project
26
+ * DRb connectivity
27
+ * RingyDingy (gem)
28
+
29
+ == INSTALL:
30
+
31
+ First install the gem:
32
+
33
+ $ sudo gem install RailsRemoteControl
34
+
35
+ Then read and follow the RailsRemoteControl installation instructions:
36
+
37
+ $ ri RailsRemoteControl
38
+
@@ -0,0 +1,23 @@
1
+ # -*- ruby -*-
2
+
3
+ require 'rubygems'
4
+ require 'hoe'
5
+
6
+ $:.unshift 'lib'
7
+ require 'rails_remote_control'
8
+
9
+ hoe = Hoe.new('RailsRemoteControl', RailsRemoteControl::VERSION) do |p|
10
+ p.summary = 'Alter Rails log levels and monitor processes without restarts'
11
+ p.description = File.read('README.txt').scan(/== DESCRIPTION:(.*?)==/m).first.first.strip
12
+ p.author = 'Eric Hodel'
13
+ p.email = 'drbrain@segment7.net'
14
+ p.rubyforge_name = 'seattlerb'
15
+ p.url = 'http://seattlerb.rubyforge.org/RailsRemoteControl'
16
+ p.changes = File.read('History.txt').scan(/\A(=.*?)(=|\Z)/m).first.first
17
+
18
+ p.extra_deps << ['RingyDingy', '>= 1.2.0']
19
+ p.extra_deps << ['ZenTest', '>= 3.4.2']
20
+ p.extra_deps << ['actionpack', '>= 1.12.5']
21
+ end
22
+
23
+ # vim: syntax=Ruby
@@ -0,0 +1,6 @@
1
+ #!/usr/local/bin/ruby -w
2
+
3
+ require 'rails_remote_control/http_server'
4
+
5
+ RailsRemoteControl::HTTPServer.run
6
+
@@ -0,0 +1,64 @@
1
+ require 'rubygems'
2
+
3
+ ##
4
+ # RailsRemoteControl allows you to monitor individual Rails processes and
5
+ # adjust the log level of a process for debugging purposes. (For example, to
6
+ # turn on partial rendering times for a single process.)
7
+ #
8
+ # = Installation
9
+ #
10
+ # First, start a RailsRemoteControl::Server when your Rails process starts up
11
+ # by adding these two lines to config/environment.rb:
12
+ #
13
+ # require 'rails_remote_control/server'
14
+ # RailsRemoteControl::Server.run 'my_rails_app'
15
+ #
16
+ # Next, add <tt>include RailsRemoteControl::Process</tt> in Application
17
+ # controller:
18
+ #
19
+ # require 'rails_remote_control/process'
20
+ #
21
+ # class ApplicationController < ActionController::Base
22
+ #
23
+ # include RailsRemoteControl::Process
24
+ #
25
+ # # ...
26
+ #
27
+ # end
28
+ #
29
+ # = Usage
30
+ #
31
+ # Then start up a RingServer where you want to monitor and control your remote
32
+ # processes:
33
+ #
34
+ # $ ring_server -d
35
+ #
36
+ # You can start the RingServer up before or after the Rails app. The rails
37
+ # processes will automatically connect soon after it starts.
38
+ #
39
+ # Then start up the RailsRemoteControl::HTTPServer so you can control your
40
+ # processes:
41
+ #
42
+ # $ rails_remote_control -d
43
+ #
44
+ # Then connect with your web browser to port 8000 on that machine.
45
+ #
46
+ # = It Doesn't Work
47
+ #
48
+ # * Do you have forward and reverse DNS set up for all your machines?
49
+ # $ host `hostname`
50
+ # ziz.jijo.segment7.net has address 10.101.28.1
51
+ # $ host 10.101.28.1
52
+ # 1.28.101.10.in-addr.arpa domain name pointer ziz.jijo.segment7.net.
53
+ # Both forward and reverse addresses need to match here.
54
+ # * Have you disabled IPv6 or set up RDNS for your IPv6 hosts?
55
+
56
+ module RailsRemoteControl
57
+
58
+ ##
59
+ # The version of RailsRemoteControl you have installed.
60
+
61
+ VERSION = '1.0.0'
62
+
63
+ end
64
+
@@ -0,0 +1,68 @@
1
+ require 'rails_remote_control'
2
+ require 'rails_remote_control/servlet'
3
+ require 'webrick/httpserver'
4
+
5
+ ##
6
+ # RailsRemoteControl HTTP server.
7
+ #
8
+ # This provides the console for monitoring and modifying your Rails processes.
9
+ # By default it runs on port 8000.
10
+
11
+ class RailsRemoteControl::HTTPServer < WEBrick::HTTPServer
12
+
13
+ @server = nil
14
+
15
+ ##
16
+ # Processes ARGV style +args+ into an options Hash.
17
+
18
+ def self.process_args(args)
19
+ options = {}
20
+ options[:Daemon] = false
21
+ options[:Port] = 8000
22
+
23
+ opts = OptionParser.new do |opts|
24
+ opts.banner = "Usage: #{name} [options]"
25
+ opts.on("-p", "--port=PORT",
26
+ "RailsRemoteControl HTTP Server Port", Integer) do |port|
27
+ options[:Port] = port
28
+ end
29
+
30
+ opts.on("-d", "--daemon",
31
+ "Run as a daemon process") do |daemon|
32
+ options[:Daemon] = true
33
+ end
34
+ end
35
+
36
+ opts.parse! args
37
+
38
+ return options
39
+ end
40
+
41
+ ##
42
+ # Start and run a RailsRemoteControl HTTP server, depending upon +args+.
43
+
44
+ def self.run(args = ARGV)
45
+ options = process_args args
46
+
47
+ if options[:Daemon] then
48
+ WEBrick::Daemon.start
49
+ end
50
+
51
+ @server = new :Port => options[:Port]
52
+ @server.mount '/', RailsRemoteControl::Servlet
53
+
54
+ trap 'INT' do stop end
55
+ trap 'KILL' do stop end
56
+
57
+ @server.start
58
+ end
59
+
60
+ ##
61
+ # Stop the RailsRemoteControl HTTP server.
62
+
63
+ def self.stop
64
+ @server.stop
65
+ end
66
+
67
+ end
68
+
@@ -0,0 +1,59 @@
1
+ require 'rails_remote_control'
2
+
3
+ ##
4
+ # RailsRemoteControl::Process records statistics of a running Rails process.
5
+ #
6
+ # Include it in your ApplicationController to record these statistics:
7
+ #
8
+ # require 'rails_remote_control/process'
9
+ #
10
+ # class ApplicationController < ActionController::Base
11
+ #
12
+ # include RailsRemoteControl::Process
13
+ #
14
+ # end
15
+
16
+ module RailsRemoteControl::Process
17
+
18
+ @requests_attempted = 0
19
+ @requests_handled = 0
20
+
21
+ @requests = Hash.new { |h,full_action_name| h[full_action_name] = 0 }
22
+
23
+ class << self
24
+
25
+ ##
26
+ # Hash mapping action names to times handled.
27
+
28
+ attr_reader :requests
29
+
30
+ ##
31
+ # Requests attempted
32
+
33
+ attr_accessor :requests_attempted
34
+
35
+ ##
36
+ # Requests successfully handled
37
+
38
+ attr_accessor :requests_handled
39
+
40
+ end
41
+
42
+ ##
43
+ # ActionController::Base#process wrapper that records statistics for actions
44
+ # handled by this Rails process.
45
+
46
+ def process(req, res)
47
+ RailsRemoteControl::Process.requests_attempted += 1
48
+
49
+ result = super
50
+
51
+ RailsRemoteControl::Process.requests_handled += 1
52
+ full_action_name = "#{self.class.name}##{action_name}"
53
+ RailsRemoteControl::Process.requests[full_action_name] += 1
54
+
55
+ return result
56
+ end
57
+
58
+ end
59
+
@@ -0,0 +1,38 @@
1
+ require 'rails_remote_control'
2
+ require 'ringy_dingy/ring_server'
3
+ require 'rails_remote_control/server'
4
+
5
+ ##
6
+ # RailsRemoteControl process locater.
7
+
8
+ class RailsRemoteControl::Remote
9
+
10
+ ##
11
+ # Remote server struct
12
+
13
+ Server = Struct.new :host, :pid, :remote_server
14
+
15
+ ##
16
+ # Looks for services on the RingServer and returns an Array of discovered
17
+ # Rails processes.
18
+
19
+ def services
20
+ services = RingyDingy::RingServer.list_services
21
+ return [] if services.empty?
22
+
23
+ services = RingyDingy::RingServer.list_services.values.first.uniq
24
+
25
+ rrc_servers = services.select do |_, klass,|
26
+ klass == RailsRemoteControl::Server::RINGY_DINGY_SERVICE
27
+ end
28
+
29
+ rrc_servers.map do |_, _, server, name|
30
+ host, pid, = name.split '_', 3
31
+ Server.new host, pid.to_i, server
32
+ end
33
+ end
34
+
35
+ end
36
+
37
+ require 'rails_remote_control/remote/server'
38
+
@@ -0,0 +1,16 @@
1
+ require 'rails_remote_control/remote'
2
+
3
+ ##
4
+ # RailsRemoteControl remote server convenience wrapper.
5
+
6
+ class RailsRemoteControl::Remote::Server
7
+
8
+ ##
9
+ # Dispatch other messages to the remote server.
10
+
11
+ def method_missing(*args, &block)
12
+ remote_server.send(*args, &block)
13
+ end
14
+
15
+ end
16
+
@@ -0,0 +1,117 @@
1
+ require 'English'
2
+ require 'logger'
3
+ require 'rubygems'
4
+ require 'ringy_dingy'
5
+ require 'rails_remote_control'
6
+ require 'rails_remote_control/process'
7
+
8
+ ##
9
+ # RailsRemoteControl server process. Run this from config/environment.rb to
10
+ # allow RailsRemoteControl::Remote to find the Rails processes you are
11
+ # running.
12
+ #
13
+ # = Example
14
+ #
15
+ # Add the following lines to config/environment.rb for your application:
16
+ #
17
+ # require 'rails_remote_control/server'
18
+ # RailsRemoteControl::Server.run 'my_rails_app'
19
+
20
+ class RailsRemoteControl::Server
21
+
22
+ ##
23
+ # Service name for RingyDingy
24
+
25
+ RINGY_DINGY_SERVICE = name.delete(':').intern
26
+
27
+ ##
28
+ # Run as +name+.
29
+
30
+ def self.run(name = nil)
31
+ new(name).run
32
+ end
33
+
34
+ ##
35
+ # Creates a new RailsRemoteControl server as +name+.
36
+ #
37
+ # Use +name+ to disambiguate multiple Rails applications.
38
+
39
+ def initialize(name)
40
+ @name = name
41
+ @ringy_dingy = RingyDingy.new self, RINGY_DINGY_SERVICE, name
42
+ @pid = $PID
43
+ @host = Socket.gethostname
44
+ end
45
+
46
+ ##
47
+ # Start running
48
+
49
+ def run
50
+ @ringy_dingy.run
51
+ end
52
+
53
+ ##
54
+ # Returns the current log level of the default logger for this Rails
55
+ # process.
56
+
57
+ def log_level
58
+ RAILS_DEFAULT_LOGGER.level
59
+ end
60
+
61
+ ##
62
+ # Sets the current log level of the default logger for this Rails process to
63
+ # +level+.
64
+
65
+ def log_level=(level)
66
+ RAILS_DEFAULT_LOGGER.level = level
67
+ end
68
+
69
+ ##
70
+ # A Hash mapping action names to number of requests handled.
71
+ #
72
+ # See RailsRemoteControl::Process#requests.
73
+
74
+ def requests
75
+ RailsRemoteControl::Process.requests
76
+ end
77
+
78
+ ##
79
+ # Number of requests attempted by this Rails process.
80
+
81
+ def requests_attempted
82
+ RailsRemoteControl::Process.requests_attempted
83
+ end
84
+
85
+ ##
86
+ # Number of requests handled by this Rails process. (If this number is
87
+ # different from #requests_attempted something bad happened, check your
88
+ # logs.)
89
+
90
+ def requests_handled
91
+ RailsRemoteControl::Process.requests_handled
92
+ end
93
+
94
+ def ==(other) # :nodoc:
95
+ self.class === other and other.name == self.name and
96
+ other.host == self.host and other.pid == self.pid
97
+ end
98
+
99
+ protected
100
+
101
+ ##
102
+ # Name of this Rails process.
103
+
104
+ attr_reader :name
105
+
106
+ ##
107
+ # Host this Rails process is running on.
108
+
109
+ attr_reader :host
110
+
111
+ ##
112
+ # Process id for this Rails process.
113
+
114
+ attr_reader :pid
115
+
116
+ end
117
+
@@ -0,0 +1,207 @@
1
+ $TESTING = false unless defined? $TESTING
2
+
3
+ require 'webrick/httpservlet/abstract'
4
+ require 'webrick/httpstatus'
5
+ require 'rails_remote_control'
6
+ require 'rails_remote_control/remote'
7
+ require 'logger'
8
+
9
+ ##
10
+ # RailsRemoteControl WEBrick servlet for process monitoring and control.
11
+
12
+ class RailsRemoteControl::Servlet < WEBrick::HTTPServlet::AbstractServlet
13
+
14
+ logger_levels = Logger::Severity.constants.map do |c|
15
+ [Logger::Severity.const_get(c), c]
16
+ end
17
+
18
+ ##
19
+ # Map Logger's log levels to friendly names
20
+
21
+ LOGGER_LEVELS = logger_levels.sort_by { |l,n| l }
22
+
23
+ @services = nil
24
+ @services_thread = nil
25
+
26
+ ##
27
+ # Accessor for services cache
28
+
29
+ def self.services
30
+ @services
31
+ end
32
+
33
+ ##
34
+ # Fetching a list of services will block for five seconds, so do that in a
35
+ # separate thread and cache the results. This method is called at require
36
+ # time.
37
+
38
+ def self.start_services_thread
39
+ @services_thread = Thread.start do
40
+ remote = RailsRemoteControl::Remote.new
41
+
42
+ loop do
43
+ @services = remote.services
44
+ sleep 10
45
+ end
46
+ end
47
+
48
+ sleep 0.1 while @services.nil?
49
+ end
50
+
51
+ start_services_thread unless $TESTING
52
+
53
+ def do_GET(req, res) # :nodoc:
54
+ case req.request_uri.request_uri
55
+ when '/' then
56
+ res.body = list
57
+ when %r%\A/server/([^/]+)/(\d+)\Z%
58
+ res.body = server $1, $2.to_i
59
+ else
60
+ super
61
+ end
62
+ end
63
+
64
+ def do_POST(req, res) # :nodoc:
65
+ case req.request_uri.request_uri
66
+ when %r%\A/server/([^/]+)/(\d+)/log_level\Z%
67
+ host, pid = $1, $2.to_i
68
+ req.body =~ /log_level=(\d+)/
69
+ level = Integer($1) rescue nil
70
+ res.body = set_log_level host, pid, level
71
+ else
72
+ super
73
+ end
74
+ end
75
+
76
+ ##
77
+ # Displays a list of rails processes available for remote control.
78
+
79
+ def list
80
+ out = "<title>No Processes</title>\n"
81
+ out << "<h1>No Processes</h1>\n"
82
+ out << "<p>Did you start ring_server?"
83
+ out << "<p>Did you start rails_remote_control?\n"
84
+ out << "<p>Did you set up your Rails application for monitoring?\n"
85
+ return out if services.nil?
86
+
87
+ out = []
88
+ out << "<title>Active Processes</title>"
89
+ out << "<h1>Active Processes</h1>"
90
+ out << nil
91
+ out << '<table>'
92
+ out << '<tr><th colspan=2>&nbsp;<th colspan=2>Requests<th>&nbsp;'
93
+ out << '<tr><th>Host<th>Process<th>Attempted<th>Handled<th>Log Level'
94
+
95
+ services.each do |server|
96
+ row = server_row server
97
+ out << row if row
98
+ end
99
+
100
+ out << '</table>' << nil
101
+
102
+ out.join "\n"
103
+ end
104
+
105
+ ##
106
+ # Displays information about process +pid+ on +host+.
107
+
108
+ def server(host, pid)
109
+ server = get_server host, pid
110
+
111
+ out = []
112
+ out << "<title>#{host} pid #{pid}</title>"
113
+ out << "<h1>#{host} pid #{pid}</h1>"
114
+ out << nil
115
+
116
+ out << '<a href="/">Active Processes</a>'
117
+ out << nil
118
+
119
+ out << '<table>'
120
+ out << "<tr><th>Log Level<td>#{server.log_level}"
121
+ out << "<tr><th>Requests Attempted<td>#{server.requests_attempted}"
122
+ out << "<tr><th>Requests Handled<td>#{server.requests_handled}"
123
+ out << '</table>' << nil
124
+
125
+ out << "<form method=\"post\" action=\"/server/#{host}/#{pid}/log_level\">"
126
+ out << '<div>'
127
+ out << '<label for="log_level">Change Log Level</label>'
128
+ out << '<select id="log_level" name="log_level">'
129
+
130
+ LOGGER_LEVELS.each do |level, name|
131
+ selected = server.log_level == level ? ' selected' : nil
132
+ out << "<option#{selected} value=\"#{level}\">#{name}</option>"
133
+ end
134
+
135
+ out << '</select>'
136
+ out << '<input type="submit" value="Change">'
137
+ out << '</div>' << '</form>' << nil
138
+
139
+ unless server.requests.empty? then
140
+ out << '<table>'
141
+ out << "<tr><th>Action<th>Requests Handled"
142
+ server.requests.sort_by { |a,c| -c }.each do |action, count|
143
+ out << "<tr><td>#{action}<td>#{count}"
144
+ end
145
+ out << '</table>' << nil
146
+ end
147
+
148
+ out.join "\n"
149
+ rescue DRb::DRbConnError
150
+ raise WEBrick::HTTPStatus::NotFound, "#{host}:#{pid} is no longer reachable"
151
+ rescue NoMethodError
152
+ raise WEBrick::HTTPStatus::NotFound, "#{host}:#{pid} has gone away"
153
+ end
154
+
155
+ def service(req, res) # :nodoc:
156
+ @req = req
157
+ @res = res
158
+ @res.content_type = 'text/html'
159
+ super
160
+ end
161
+
162
+ ##
163
+ # Services accessor
164
+
165
+ def services
166
+ self.class.services
167
+ end
168
+
169
+ ##
170
+ # Construct a table row with information on +server+.
171
+
172
+ def server_row(server)
173
+ tr = []
174
+ tr << "<td>#{server.host}"
175
+ tr << "<td><a href=\"/server/#{server.host}/#{server.pid}\">#{server.pid}</a>"
176
+ tr << "<td>#{server.requests_attempted}"
177
+ tr << "<td>#{server.requests_handled}"
178
+ tr << "<td>#{server.log_level}"
179
+
180
+ "<tr>#{tr.join}"
181
+
182
+ rescue DRb::DRbConnError
183
+ nil
184
+ end
185
+
186
+ ##
187
+ # Sets the log level for process +pid+ on +host+ to +level+.
188
+
189
+ def set_log_level(host, pid, level)
190
+ server = get_server host, pid
191
+ server.log_level = level
192
+ @res.set_redirect WEBrick::HTTPStatus::SeeOther, "/server/#{host}/#{pid}"
193
+ rescue DRb::DRbConnError
194
+ raise WEBrick::HTTPStatus::NotFound, "#{host}:#{pid} is no longer reachable"
195
+ rescue NoMethodError
196
+ raise WEBrick::HTTPStatus::NotFound, "#{host}:#{pid} has gone away"
197
+ end
198
+
199
+ ##
200
+ # Retrieves the server for process +pid+ on +host+.
201
+
202
+ def get_server(host, pid)
203
+ services.find { |s| s.host == host and s.pid == pid }
204
+ end
205
+
206
+ end
207
+
File without changes
@@ -0,0 +1,16 @@
1
+ $TESTING = true
2
+
3
+ require 'test/unit'
4
+ require 'rails_remote_control/http_server'
5
+
6
+ class TestRailsRemoteControlHTTPServer < Test::Unit::TestCase
7
+
8
+ def test_self_process_args
9
+ options = RailsRemoteControl::HTTPServer.process_args %w[-d -p 80]
10
+
11
+ expected = { :Daemon => true, :Port => 80 }
12
+ assert_equal expected, options
13
+ end
14
+
15
+ end
16
+
@@ -0,0 +1,93 @@
1
+ require 'test/unit'
2
+
3
+ module ActionController; end
4
+ class ActionController::Base
5
+
6
+ attr_reader :action_name
7
+
8
+ def self.process(req, res)
9
+ new.process req, res
10
+ end
11
+
12
+ def process(req, res)
13
+ params = req.parameters
14
+ @action_name = params['action']
15
+ end
16
+
17
+ def controller_class_name
18
+ self.class.name.split('::').last
19
+ end
20
+
21
+ end
22
+
23
+ require 'rails_remote_control/process'
24
+
25
+ class ApplicationController < ActionController::Base
26
+ include RailsRemoteControl::Process
27
+ end
28
+
29
+ class MyController < ApplicationController
30
+
31
+ def index
32
+ end
33
+
34
+ def show
35
+ end
36
+
37
+ end
38
+
39
+ module Nested; end
40
+ class Nested::MyController < ApplicationController
41
+
42
+ def index
43
+ end
44
+
45
+ def show
46
+ end
47
+
48
+ end
49
+
50
+ module RailsRemoteControl
51
+ def Process.reset
52
+ @requests_handled = 0
53
+ @requests_attempted = 0
54
+ @requests.clear
55
+ end
56
+ end
57
+
58
+ class TestRailsRemoteControlProcess < Test::Unit::TestCase
59
+
60
+ RRCP = RailsRemoteControl::Process
61
+
62
+ FakeRequest = Struct.new :parameters
63
+
64
+ def setup
65
+ @request = FakeRequest.new
66
+ @request.parameters = { 'action' => 'index' }
67
+ end
68
+
69
+ def teardown
70
+ RRCP.reset
71
+ end
72
+
73
+ def test_process
74
+ MyController.new.process @request, nil
75
+
76
+ assert_equal 1, RRCP.requests_handled
77
+ assert_equal 1, RRCP.requests_attempted
78
+
79
+ expected = { 'MyController#index' => 1 }
80
+ assert_equal expected, RRCP.requests
81
+ end
82
+
83
+ def test_process_nested
84
+ Nested::MyController.new.process @request, nil
85
+
86
+ assert_equal 1, RRCP.requests_handled
87
+
88
+ expected = { 'Nested::MyController#index' => 1 }
89
+ assert_equal expected, RRCP.requests
90
+ end
91
+
92
+ end
93
+
@@ -0,0 +1,42 @@
1
+ $TESTING = true
2
+
3
+ require 'test/unit'
4
+ require 'rails_remote_control/remote'
5
+ require 'test/util'
6
+
7
+ class TestRailsRemoteControlRemote < Test::Unit::TestCase
8
+
9
+ RRCR = RailsRemoteControl::Remote
10
+
11
+ def setup
12
+ @remote = RRCR.new
13
+ RingyDingy::RingServer.default = RingyDingy::RingServer::DEFAULT
14
+ end
15
+
16
+ def teardown
17
+ RingyDingy::RingServer.default = RingyDingy::RingServer::DEFAULT
18
+ end
19
+
20
+ def test_services
21
+ RingyDingy::RingServer.default = RingyDingy::RingServer::DEFAULT
22
+
23
+ expected = [
24
+ RRCR::Server.new('cutie', 1000,
25
+ RailsRemoteControl::Server.new('43places')),
26
+ RRCR::Server.new('cutie', 1001,
27
+ RailsRemoteControl::Server.new('43places')),
28
+ RRCR::Server.new('hal', 61000,
29
+ RailsRemoteControl::Server.new('43things')),
30
+ ]
31
+
32
+ assert_equal expected, @remote.services
33
+ end
34
+
35
+ def test_services_no_services
36
+ RingyDingy::RingServer.default = {}
37
+
38
+ assert_equal [], @remote.services
39
+ end
40
+
41
+ end
42
+
@@ -0,0 +1,17 @@
1
+ require 'test/unit'
2
+ require 'rails_remote_control/server'
3
+ require 'rails_remote_control/remote/server'
4
+
5
+ class TestRailsRemoteControlRemoteServer < Test::Unit::TestCase
6
+
7
+ def setup
8
+ @server = RailsRemoteControl::Server.new 'name'
9
+ @remote_server = RailsRemoteControl::Remote::Server.new 'localhost', $$, @server
10
+ end
11
+
12
+ def test_method_missing
13
+ assert_equal 0, @remote_server.requests_handled
14
+ end
15
+
16
+ end
17
+
@@ -0,0 +1,80 @@
1
+ require 'test/unit'
2
+ require 'rubygems'
3
+ require 'test/zentest_assertions'
4
+ require 'test/util'
5
+
6
+ require 'rails_remote_control/server'
7
+
8
+ class RailsRemoteControl::Server
9
+ attr_reader :ringy_dingy
10
+ public :host, :name, :pid
11
+ end
12
+
13
+ class TestRailsRemoteControlServer < Test::Unit::TestCase
14
+
15
+ RRCS = RailsRemoteControl::Server
16
+
17
+ def setup
18
+ @name = 'RailsRemoteControl::Server test'
19
+ @server = RRCS.new @name
20
+ end
21
+
22
+ def test_equal
23
+ server = RRCS.new @name
24
+
25
+ assert_equal server, @server
26
+ end
27
+
28
+ def test_host
29
+ assert_equal Socket.gethostname, @server.host
30
+ end
31
+
32
+ def test_initialize
33
+ deny_nil @server.ringy_dingy
34
+ assert_equal "#{Socket.gethostname.downcase}_#{$PID}_#{@name}",
35
+ @server.ringy_dingy.identifier
36
+ end
37
+
38
+ def test_log_level
39
+ assert_equal Logger::DEBUG, @server.log_level
40
+ end
41
+
42
+ def test_log_level_equals
43
+ level = @server.log_level
44
+ @server.log_level = Logger::FATAL
45
+ assert_equal Logger::FATAL, @server.log_level
46
+ assert_equal Logger::FATAL, RAILS_DEFAULT_LOGGER.level
47
+ ensure
48
+ @server.log_level = level
49
+ end
50
+
51
+ def test_name
52
+ assert_equal @name, @server.name
53
+ end
54
+
55
+ def test_pid
56
+ assert_equal $$, @server.pid
57
+ end
58
+
59
+ def test_requests
60
+ assert_equal Hash.new, @server.requests
61
+ end
62
+
63
+ def test_requests_attempted
64
+ assert_equal 0, @server.requests_attempted
65
+ end
66
+
67
+ def test_requests_handled
68
+ assert_equal 0, @server.requests_handled
69
+ end
70
+
71
+ def test_run
72
+ assert_nil @server.ringy_dingy.thread
73
+ @server.run
74
+ deny_nil @server.ringy_dingy.thread
75
+ end
76
+
77
+ alias deny_nil assert_not_nil # HACK ZenTest 3.4.2
78
+
79
+ end
80
+
@@ -0,0 +1,230 @@
1
+ $TESTING = true
2
+
3
+ require 'test/unit'
4
+ require 'stringio'
5
+ require 'test/util'
6
+
7
+ require 'rails_remote_control/servlet'
8
+
9
+ require 'webrick/httprequest'
10
+ require 'webrick/httpresponse'
11
+
12
+ class FakeWEBrickServer
13
+ def [](arg); end
14
+ end
15
+
16
+ class RailsRemoteControl::Servlet
17
+ def self.services=(services)
18
+ @services = services
19
+ end
20
+ end
21
+
22
+ class TestRailsRemoteControlServlet < Test::Unit::TestCase
23
+
24
+ RRCRS = RailsRemoteControl::Remote::Server
25
+ RRCS = RailsRemoteControl::Servlet
26
+
27
+ def setup
28
+ @server = RailsRemoteControl::Server.new 'name'
29
+ @dead_server = RailsRemoteControl::Server.new 'name'
30
+ def @dead_server.requests_attempted() raise DRb::DRbConnError; end
31
+ RRCS.services = [
32
+ RRCRS.new('cutie', 1000, @server),
33
+ RRCRS.new('cutie', 1001, @server),
34
+ RRCRS.new('hal', 61000, @server),
35
+ RRCRS.new('hal', 61001, @dead_server),
36
+ ]
37
+
38
+ @http_server = FakeWEBrickServer.new
39
+ @servlet = RRCS.new @http_server
40
+ @config = { :Logger => nil, :HTTPVersion => '1.0' }
41
+ end
42
+
43
+ def teardown
44
+ RailsRemoteControl::Server.new(nil).requests.clear
45
+ end
46
+
47
+ def test_do_GET_list
48
+ req = WEBrick::HTTPRequest.new @config
49
+ req.parse StringIO.new("GET / HTTP/1.0\r\n\r\n")
50
+ res = WEBrick::HTTPResponse.new @config
51
+
52
+ def @servlet.list
53
+ return 'list'
54
+ end
55
+
56
+ @servlet.service req, res
57
+
58
+ assert_equal 'list', res.body
59
+ end
60
+
61
+ def test_do_GET_server
62
+ req = WEBrick::HTTPRequest.new @config
63
+ req.parse StringIO.new("GET /server/cutie/1000 HTTP/1.0\r\n\r\n")
64
+ res = WEBrick::HTTPResponse.new @config
65
+
66
+ def @servlet.server(host, pid)
67
+ return "server #{host} #{pid}"
68
+ end
69
+
70
+ @servlet.service req, res
71
+
72
+ assert_equal 'server cutie 1000', res.body
73
+ end
74
+
75
+ def test_do_GET_server_with_dot
76
+ req = WEBrick::HTTPRequest.new @config
77
+ req.parse StringIO.new("GET /server/kaa.local/1000 HTTP/1.0\r\n\r\n")
78
+ res = WEBrick::HTTPResponse.new @config
79
+
80
+ def @servlet.server(host, pid)
81
+ return "server %p %p" % [host, pid]
82
+ end
83
+
84
+ @servlet.service req, res
85
+
86
+ assert_equal 'server "kaa.local" 1000', res.body
87
+ end
88
+
89
+ def test_do_POST_server_log_level
90
+ req = WEBrick::HTTPRequest.new @config
91
+ req.parse StringIO.new("POST /server/cutie/1000/log_level HTTP/1.0\r\nContent-Length: 11\r\n\r\nlog_level=5")
92
+ res = WEBrick::HTTPResponse.new @config
93
+
94
+ def @servlet.set_log_level(host, pid, level)
95
+ return "server #{host} #{pid} #{level}"
96
+ end
97
+
98
+ @servlet.service req, res
99
+
100
+ assert_equal 'server cutie 1000 5', res.body
101
+ end
102
+
103
+ def test_list
104
+ expected = <<-EOF
105
+ <title>Active Processes</title>
106
+ <h1>Active Processes</h1>
107
+
108
+ <table>
109
+ <tr><th colspan=2>&nbsp;<th colspan=2>Requests<th>&nbsp;
110
+ <tr><th>Host<th>Process<th>Attempted<th>Handled<th>Log Level
111
+ <tr><td>cutie<td><a href="/server/cutie/1000">1000</a><td>0<td>0<td>0
112
+ <tr><td>cutie<td><a href="/server/cutie/1001">1001</a><td>0<td>0<td>0
113
+ <tr><td>hal<td><a href="/server/hal/61000">61000</a><td>0<td>0<td>0
114
+ </table>
115
+ EOF
116
+
117
+ assert_equal expected, @servlet.list
118
+ end
119
+
120
+ def test_server
121
+ server = RailsRemoteControl::Server.new 'name'
122
+ server.requests['RouteController#index'] = 2
123
+ server.requests['RouteController#route_markers'] = 1
124
+ RRCS.services = [RRCRS.new('cutie', 1000, server)]
125
+
126
+ expected = <<-EOF
127
+ <title>cutie pid 1000</title>
128
+ <h1>cutie pid 1000</h1>
129
+
130
+ <a href="/">Active Processes</a>
131
+
132
+ <table>
133
+ <tr><th>Log Level<td>0
134
+ <tr><th>Requests Attempted<td>0
135
+ <tr><th>Requests Handled<td>0
136
+ </table>
137
+
138
+ <form method="post" action="/server/cutie/1000/log_level">
139
+ <div>
140
+ <label for="log_level">Change Log Level</label>
141
+ <select id="log_level" name="log_level">
142
+ <option selected value="0">DEBUG</option>
143
+ <option value="1">INFO</option>
144
+ <option value="2">WARN</option>
145
+ <option value="3">ERROR</option>
146
+ <option value="4">FATAL</option>
147
+ <option value="5">UNKNOWN</option>
148
+ </select>
149
+ <input type="submit" value="Change">
150
+ </div>
151
+ </form>
152
+
153
+ <table>
154
+ <tr><th>Action<th>Requests Handled
155
+ <tr><td>RouteController#index<td>2
156
+ <tr><td>RouteController#route_markers<td>1
157
+ </table>
158
+ EOF
159
+
160
+ assert_equal expected, @servlet.server('cutie', 1000)
161
+ end
162
+
163
+ def test_server_dead
164
+ e = assert_raise WEBrick::HTTPStatus::NotFound do
165
+ @servlet.server 'hal', 61001
166
+ end
167
+
168
+ assert_equal 'hal:61001 is no longer reachable', e.message
169
+ end
170
+
171
+ def test_server_gone
172
+ util_test_gone :server
173
+ end
174
+
175
+ def test_server_no_requests
176
+ expected = <<-EOF
177
+ <title>cutie pid 1001</title>
178
+ <h1>cutie pid 1001</h1>
179
+
180
+ <a href="/">Active Processes</a>
181
+
182
+ <table>
183
+ <tr><th>Log Level<td>0
184
+ <tr><th>Requests Attempted<td>0
185
+ <tr><th>Requests Handled<td>0
186
+ </table>
187
+
188
+ <form method="post" action="/server/cutie/1001/log_level">
189
+ <div>
190
+ <label for="log_level">Change Log Level</label>
191
+ <select id="log_level" name="log_level">
192
+ <option selected value="0">DEBUG</option>
193
+ <option value="1">INFO</option>
194
+ <option value="2">WARN</option>
195
+ <option value="3">ERROR</option>
196
+ <option value="4">FATAL</option>
197
+ <option value="5">UNKNOWN</option>
198
+ </select>
199
+ <input type="submit" value="Change">
200
+ </div>
201
+ </form>
202
+ EOF
203
+
204
+ assert_equal expected, @servlet.server('cutie', 1001)
205
+ end
206
+
207
+ def test_set_log_level
208
+ @servlet.instance_variable_set :@res, WEBrick::HTTPResponse.new(@config)
209
+
210
+ assert_raise WEBrick::HTTPStatus::SeeOther do
211
+ @servlet.set_log_level 'cutie', 1000, 5
212
+ end
213
+
214
+ assert_equal 5, @server.log_level
215
+ end
216
+
217
+ def test_set_log_level_no_server
218
+ util_test_gone :set_log_level, 5
219
+ end
220
+
221
+ def util_test_gone(action, *args)
222
+ e = assert_raise WEBrick::HTTPStatus::NotFound do
223
+ @servlet.send(action, 'none', 0, *args)
224
+ end
225
+
226
+ assert_equal 'none:0 has gone away', e.message
227
+ end
228
+
229
+ end
230
+
@@ -0,0 +1,39 @@
1
+ require 'logger'
2
+ require 'rubygems'
3
+ require 'test/zentest_assertions'
4
+ require 'ringy_dingy/ring_server'
5
+ require 'rails_remote_control/server'
6
+
7
+ RAILS_DEFAULT_LOGGER = Logger.new '/dev/null'
8
+
9
+ class RingyDingy::RingServer
10
+
11
+ @s1 = RailsRemoteControl::Server.new '43places'
12
+ @s2 = RailsRemoteControl::Server.new '43places'
13
+ @s3 = RailsRemoteControl::Server.new '43things'
14
+
15
+ DEFAULT = {
16
+ 'druby://localhost:10000' => [
17
+ [:name, RailsRemoteControl::Server::RINGY_DINGY_SERVICE, @s1,
18
+ 'cutie_1000_43places'],
19
+ [:name, RailsRemoteControl::Server::RINGY_DINGY_SERVICE, @s2,
20
+ 'cutie_1001_43places'],
21
+ [:name, RailsRemoteControl::Server::RINGY_DINGY_SERVICE, @s3,
22
+ 'hal_61000_43places'],
23
+ ]
24
+ }
25
+
26
+ def self.default=(default)
27
+ @default = default
28
+ end
29
+
30
+ class << self
31
+ remove_method :list_services
32
+ end
33
+
34
+ def self.list_services
35
+ @default
36
+ end
37
+
38
+ end
39
+
metadata ADDED
@@ -0,0 +1,107 @@
1
+ --- !ruby/object:Gem::Specification
2
+ rubygems_version: 0.9.0.8
3
+ specification_version: 1
4
+ name: RailsRemoteControl
5
+ version: !ruby/object:Gem::Version
6
+ version: 1.0.0
7
+ date: 2007-01-02 00:00:00 -08:00
8
+ summary: Alter Rails log levels and monitor processes without restarts
9
+ require_paths:
10
+ - lib
11
+ email: drbrain@segment7.net
12
+ homepage: http://seattlerb.rubyforge.org/RailsRemoteControl
13
+ rubyforge_project: seattlerb
14
+ description: Rails Remote Control allows you to attach to running Rails processes using DRb and change the log level without restarts. Also, view actions handled per process.
15
+ autorequire:
16
+ default_executable:
17
+ bindir: bin
18
+ has_rdoc: true
19
+ required_ruby_version: !ruby/object:Gem::Version::Requirement
20
+ requirements:
21
+ - - ">"
22
+ - !ruby/object:Gem::Version
23
+ version: 0.0.0
24
+ version:
25
+ platform: ruby
26
+ signing_key:
27
+ cert_chain:
28
+ post_install_message:
29
+ authors:
30
+ - Eric Hodel
31
+ files:
32
+ - History.txt
33
+ - LICENSE.txt
34
+ - Manifest.txt
35
+ - README.txt
36
+ - Rakefile
37
+ - bin/rails_remote_control
38
+ - lib/rails_remote_control.rb
39
+ - lib/rails_remote_control/http_server.rb
40
+ - lib/rails_remote_control/process.rb
41
+ - lib/rails_remote_control/remote.rb
42
+ - lib/rails_remote_control/remote/server.rb
43
+ - lib/rails_remote_control/server.rb
44
+ - lib/rails_remote_control/servlet.rb
45
+ - test/test_rails_remote_control.rb
46
+ - test/test_rails_remote_control_http_server.rb
47
+ - test/test_rails_remote_control_process.rb
48
+ - test/test_rails_remote_control_remote.rb
49
+ - test/test_rails_remote_control_remote_server.rb
50
+ - test/test_rails_remote_control_server.rb
51
+ - test/test_rails_remote_control_servlet.rb
52
+ - test/util.rb
53
+ test_files:
54
+ - test/test_rails_remote_control.rb
55
+ - test/test_rails_remote_control_http_server.rb
56
+ - test/test_rails_remote_control_process.rb
57
+ - test/test_rails_remote_control_remote.rb
58
+ - test/test_rails_remote_control_remote_server.rb
59
+ - test/test_rails_remote_control_server.rb
60
+ - test/test_rails_remote_control_servlet.rb
61
+ rdoc_options: []
62
+
63
+ extra_rdoc_files: []
64
+
65
+ executables:
66
+ - rails_remote_control
67
+ extensions: []
68
+
69
+ requirements: []
70
+
71
+ dependencies:
72
+ - !ruby/object:Gem::Dependency
73
+ name: hoe
74
+ version_requirement:
75
+ version_requirements: !ruby/object:Gem::Version::Requirement
76
+ requirements:
77
+ - - ">="
78
+ - !ruby/object:Gem::Version
79
+ version: 1.1.6
80
+ version:
81
+ - !ruby/object:Gem::Dependency
82
+ name: RingyDingy
83
+ version_requirement:
84
+ version_requirements: !ruby/object:Gem::Version::Requirement
85
+ requirements:
86
+ - - ">="
87
+ - !ruby/object:Gem::Version
88
+ version: 1.2.0
89
+ version:
90
+ - !ruby/object:Gem::Dependency
91
+ name: ZenTest
92
+ version_requirement:
93
+ version_requirements: !ruby/object:Gem::Version::Requirement
94
+ requirements:
95
+ - - ">="
96
+ - !ruby/object:Gem::Version
97
+ version: 3.4.2
98
+ version:
99
+ - !ruby/object:Gem::Dependency
100
+ name: actionpack
101
+ version_requirement:
102
+ version_requirements: !ruby/object:Gem::Version::Requirement
103
+ requirements:
104
+ - - ">="
105
+ - !ruby/object:Gem::Version
106
+ version: 1.12.5
107
+ version: