passenger_monitor 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 8bd9f81728f7936c57c6b33e432dd01ac8c5fc05
4
+ data.tar.gz: 1e69bfc416b5f071d2e22ad3387281e2960b587a
5
+ SHA512:
6
+ metadata.gz: 2e21c97df5604ecd32cc45e8305bb0430d59e111e90672312f74603dc8a168bcb5616dcfe2c28585d7ccfbae72ce1a2abfee80497641b181069e7310d0f4158d
7
+ data.tar.gz: f1d6f40ed111dff31334205ab22cf7ce0656c9210593217fa53b1cc7cd56f0db1f9e970a1e82d4e7d2091d6a82ec284de3530861e5f898659eb473a1de6bf6a0
data/.gitignore ADDED
@@ -0,0 +1,14 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
10
+ *.bundle
11
+ *.so
12
+ *.o
13
+ *.a
14
+ mkmf.log
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in passenger-monitor.gemspec
4
+ gemspec
data/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2016 VinSol
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2016 Akshay Vishnoi
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,68 @@
1
+ # PassengerMonitor
2
+
3
+ [![Code Climate](https://codeclimate.com/github/vinsol/passenger-monitor/badges/gpa.svg)](https://codeclimate.com/github/vinsol/passenger-monitor)
4
+
5
+ This gem monitors passenger workers of your application and if the workers exceed the memory limit then it kills them (first gracefully, waits and then forcefully). It fetches the memory of the passenger workers from the system command `passenger-memory-stats`, checks the memory of each worker **concurrently (using threads)** and kills them if it finds them bloated. First, it kills the process gracefully and wait for it to die, if the process still appears then it kills it forcefully
6
+
7
+ ## Installation
8
+
9
+ Add this line to your application's `Gemfile`:
10
+
11
+ ```ruby
12
+ gem 'passenger-monitor'
13
+ ```
14
+
15
+ And then execute:
16
+
17
+ $ bundle
18
+
19
+ Or install it yourself as:
20
+
21
+ $ gem install passenger-monitor
22
+
23
+ ## Usage
24
+
25
+ The gem provides a service class which can be initialized to check the passenger workers.
26
+
27
+ ```ruby
28
+ PassengerMonitor.run({:memory_limit=>"150",
29
+ :log_file=>"passenger_config.log",
30
+ :wait_time=>"15",
31
+ :process_name_regex=>"passenger"})
32
+ ```
33
+
34
+ **Parameters options:**
35
+ 1. **:memory_limit**: allowed memory limit for a passenger worker
36
+ 2. **:log_file**: the name of the log file
37
+ 3. **:wait_time**: the time to wait to kill the worker forcefully
38
+ 4. **:process_name_regex**: regex for the passenger worker of the application
39
+
40
+ ### Use Rake task
41
+ It also provides a rake task which can be scheduled in cron tasks. To load tasks add following lines in your `Rakefile`:
42
+
43
+ ```ruby
44
+ spec = Gem::Specification.find_by_name 'passenger_monitor'
45
+ Dir.glob("#{spec.gem_dir}/lib/tasks/*.rake").each { |task_file| load task_file }
46
+ ```
47
+ Now rake task `passenger:monitor` will be available. For custom configuration, send arguments in task in following order: `:memory_limit, :log_file, :wait_time, :process_name_regex`:
48
+
49
+ ```system
50
+ bundle exec rake passenger:monitor[150,"passenger_config.log",15,"Passenger RubyApp"]
51
+ ```
52
+
53
+ That's it, now never think of bloated passengers.
54
+
55
+ ## Contributing
56
+
57
+ 1. Fork it ( https://github.com/[my-github-username]/passenger-monitor/fork )
58
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
59
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
60
+ 4. Push to the branch (`git push origin my-new-feature`)
61
+ 5. Create a new Pull Request
62
+
63
+ Credits
64
+ -------
65
+
66
+ [![vinsol.com: Ruby on Rails, iOS and Android developers](http://vinsol.com/vin_logo.png "Ruby on Rails, iOS and Android developers")](http://vinsol.com)
67
+
68
+ Copyright (c) 2014 [vinsol.com](http://vinsol.com "Ruby on Rails, iOS and Android developers"), released under the New MIT License
data/Rakefile ADDED
@@ -0,0 +1 @@
1
+ require "bundler/gem_tasks"
@@ -0,0 +1,148 @@
1
+ module PassengerMonitor
2
+ class Monitor
3
+ # Default allowed memory limit for a passenger worker (MB)
4
+ DEFAULT_MEMORY_LIMIT = 150 # in MB
5
+ # Default log file name
6
+ DEFAULT_LOG_FILE = 'passenger_monitoring.log'
7
+ # default waiting time after graceful kill attempt to kill process forcefully
8
+ DEFAULT_WAIT_TIME = 10 # in Seconds
9
+ # Passenger Process Name Regex
10
+ DEFAULT_PROCESS_NAME_REGEX = /Passenger RubyApp:/
11
+
12
+ # Initialize the service and apply a check on all passenger processes
13
+ # given `configurations` (defaults to `{}`)
14
+ #
15
+ # == Parameters:
16
+ # config::
17
+ # Hash which includes the configurations keys i.e.
18
+ # 1. :memory_limit - allowed memory limit for a passenger worker
19
+ # 2. :log_file - the name of the log file
20
+ # 3. :wait_time - the time to wait to kill the worker forcefully
21
+ # 4. :process_name_regex - regex for the passenger worker of the application
22
+ #
23
+ def self.run(config = {})
24
+ new(config).check
25
+ end
26
+
27
+ # Sets memory limit, log file, wait time, process name regex and logger
28
+ #
29
+ def initialize(params = {})
30
+ @memory_limit = fetch_memory_limit(params)
31
+ @log_file = fetch_log_file(params)
32
+ @wait_time = fetch_wait_time(params)
33
+ @process_name_regex = fetch_process_name_regex(params)
34
+ @logger = Logger.new(@log_file)
35
+ end
36
+
37
+ # Checks memory of all the passenger processes and for bloadted workers
38
+ # it creates thread for each to kill it.
39
+ #
40
+ def check
41
+ @logger.info 'Checking bloated Passenger workers'
42
+
43
+ threads = []
44
+
45
+ passenger_workers_details.each_line do |line|
46
+ next unless (line =~ @process_name_regex)
47
+
48
+ pid, memory_usage = extract_stats(line)
49
+
50
+ # If a given passenger process is bloated try to
51
+ # kill it gracefully and if it fails, force killing it
52
+ if bloated?(pid, memory_usage)
53
+ threads << Thread.new { self.handle_bloated_process(pid) }
54
+ end
55
+ end
56
+
57
+ threads.map(&:join)
58
+ @logger.info 'Finished checking for bloated Passenger workers'
59
+ end
60
+
61
+ # Handles bloated processes:
62
+ #
63
+ # 1. Kill it gracefully
64
+ # 2. Wait for the given time
65
+ # 3. if it still exists then kill it forcefully.
66
+ #
67
+ # == Parameters:
68
+ # pid::
69
+ # Process ID.
70
+ #
71
+ def handle_bloated_process(pid)
72
+ kill(pid)
73
+ wait
74
+ kill!(pid) if process_running?(pid)
75
+ end
76
+
77
+ private
78
+
79
+ def fetch_memory_limit(params)
80
+ params.key?(:memory_limit) ? params[:memory_limit].to_f : DEFAULT_MEMORY_LIMIT
81
+ end
82
+
83
+ def fetch_log_file(params)
84
+ params.key?(:log_file) ? params[:log_file] : DEFAULT_LOG_FILE
85
+ end
86
+
87
+ def fetch_wait_time(params)
88
+ params.key?(:wait_time) ? params[:wait_time].to_i : DEFAULT_WAIT_TIME
89
+ end
90
+
91
+ def fetch_process_name_regex(params)
92
+ if params.key?(:process_name_regex)
93
+ Regexp.new(params[:process_name_regex].to_s)
94
+ else
95
+ DEFAULT_PROCESS_NAME_REGEX
96
+ end
97
+ end
98
+
99
+ # Fetches the stats of passenger-memory-stats from system.
100
+ # Using `env -i` to remove surrounding environment of bundle.
101
+ def passenger_workers_details
102
+ passenger_memory_status_path = `env -i which passenger-memory-stats`
103
+ `env -i #{ passenger_memory_status_path }`
104
+ end
105
+
106
+ # Checks if a given process is still running
107
+ # == Parameters:
108
+ # pid::
109
+ # Process ID.
110
+ #
111
+ def process_running?(pid)
112
+ Process.getpgid(pid) != -1
113
+ rescue Errno::ESRCH
114
+ false
115
+ end
116
+
117
+ # Wait for process to be killed
118
+ def wait
119
+ @logger.error "Waiting for worker to shutdown..."
120
+ sleep(DEFAULT_WAIT_TIME)
121
+ end
122
+
123
+ # Kill it gracefully
124
+ def kill(pid)
125
+ @logger.error "Trying to kill #{pid} gracefully..."
126
+ Process.kill("SIGUSR1", pid)
127
+ end
128
+
129
+ # Kill it forcefully
130
+ def kill!(pid)
131
+ @logger.fatal "Force kill: #{pid}"
132
+ Process.kill("TERM", pid)
133
+ end
134
+
135
+ # Extracts pid and memory usage of a single Passenger worker
136
+ def extract_stats(line)
137
+ stats = line.split
138
+ return stats[0].to_i, stats[3].to_f
139
+ end
140
+
141
+ # Check if a given process is exceeding memory limit
142
+ def bloated?(pid, size)
143
+ bloated = size > @memory_limit
144
+ @logger.error "Found bloated worker: #{pid} - #{size}MB" if bloated
145
+ bloated
146
+ end
147
+ end
148
+ end
@@ -0,0 +1,4 @@
1
+ module PassengerMonitor
2
+ # Specifies the version of the gem.
3
+ VERSION = "0.0.1"
4
+ end
@@ -0,0 +1,6 @@
1
+ require 'passenger_monitor/monitor'
2
+ require 'passenger_monitor/version'
3
+ require 'logger'
4
+
5
+ module PassengerMonitor
6
+ end
@@ -0,0 +1,6 @@
1
+ namespace :passenger do
2
+ desc "monitors passenger workers and kill bloated ones"
3
+ task :monitor, [:memory_limit, :log_file, :wait_time, :process_name_regex] do |t, args|
4
+ PassengerMonitor::Monitor.run args
5
+ end
6
+ end
@@ -0,0 +1,26 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'passenger_monitor/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "passenger_monitor"
8
+ spec.version = PassengerMonitor::VERSION
9
+ spec.authors = ["Akshay Vishnoi"]
10
+ spec.email = ["akshay.vishnoi@yahoo.com"]
11
+ spec.summary = %q{Monitors passenger workers and kill bloated ones}
12
+ spec.description = %q{Monitors passenger workers of your application and if
13
+ the workers exceeds the memory limit then it kills it (first gracefully, wait and
14
+ then forcefully).}
15
+ spec.homepage = "https://github.com/vinsol/passenger-monitor"
16
+ spec.license = "MIT"
17
+
18
+ spec.files = `git ls-files -z`.split("\x0")
19
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
20
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
21
+ spec.require_paths = ["lib"]
22
+
23
+ spec.add_development_dependency "bundler", "~> 1.7"
24
+ spec.add_development_dependency "rake", "~> 10.0"
25
+ spec.add_development_dependency "rspec", "~> 3.4"
26
+ end
@@ -0,0 +1,130 @@
1
+ require 'spec_helper'
2
+
3
+ def stub_system_command(response = '')
4
+ response = !response.empty? ? response : %Q{
5
+ 25096 637.9 MB 165.4 MB Passenger RubyApp:
6
+ 25097 637.9 MB 100.4 MB Passenger RubyApp:
7
+ 25098 637.9 MB 120.4 MB Passenger RubyApp:
8
+ }
9
+
10
+ allow_any_instance_of(PassengerMonitor::Monitor).to receive(:`).and_return(response)
11
+ end
12
+
13
+ def stub_process_status(response = -1)
14
+ allow(Process).to receive(:getpgid).and_return(response)
15
+ end
16
+
17
+ def stub_process_kill(method_name, signal, pid)
18
+ allow(Process).to receive(method_name).with(signal, pid)
19
+ end
20
+
21
+ def stub_wait(time = 10)
22
+ allow_any_instance_of(PassengerMonitor::Monitor).to receive(:sleep).with(time)
23
+ end
24
+
25
+ describe PassengerMonitor::Monitor do
26
+ let(:params) { {
27
+ :memory_limit=>"200",
28
+ :log_file=>"passenger_monitor.log",
29
+ :wait_time=>"15",
30
+ :process_name_regex=>"passenger"}}
31
+
32
+ let(:object_with_params) { PassengerMonitor::Monitor.new(params) }
33
+ let(:object_without_params) { PassengerMonitor::Monitor.new }
34
+
35
+ after do
36
+ ["passenger_monitoring.log", "passenger_monitor.log"].each do |file_name|
37
+ `rm #{file_name}`
38
+ end
39
+ end
40
+
41
+ describe 'Constants' do
42
+ it 'PassengerMonitor::Monitor::DEFAULT_MEMORY_LIMIT => 150' do
43
+ expect(PassengerMonitor::Monitor::DEFAULT_MEMORY_LIMIT).to eq(150)
44
+ end
45
+ it "PassengerMonitor::Monitor::DEFAULT_LOG_FILE => 'passenger_monitoring.log'" do
46
+ expect(PassengerMonitor::Monitor::DEFAULT_LOG_FILE).to eq('passenger_monitoring.log')
47
+ end
48
+ it 'PassengerMonitor::Monitor::DEFAULT_WAIT_TIME => 10' do
49
+ expect(PassengerMonitor::Monitor::DEFAULT_WAIT_TIME).to eq(10)
50
+ end
51
+ it 'PassengerMonitor::Monitor::DEFAULT_PROCESS_NAME_REGEX => /Passenger RubyApp:/' do
52
+ expect(PassengerMonitor::Monitor::DEFAULT_PROCESS_NAME_REGEX).to eq(/Passenger RubyApp:/)
53
+ end
54
+ end
55
+
56
+ describe 'Parameters' do
57
+ before do
58
+ stub_system_command
59
+ end
60
+
61
+ context 'when params are not provided' do
62
+ it 'picks up default configurations' do
63
+ expect(object_without_params.instance_variable_get(:@memory_limit)).to eq(150)
64
+ expect(object_without_params.instance_variable_get(:@log_file)).to eq('passenger_monitoring.log')
65
+ expect(object_without_params.instance_variable_get(:@wait_time)).to eq(10)
66
+ expect(object_without_params.instance_variable_get(:@process_name_regex)).to eq(/Passenger RubyApp:/)
67
+ end
68
+ end
69
+
70
+ context 'when params are provided' do
71
+ it 'picks up custom params' do
72
+ expect(object_with_params.instance_variable_get(:@memory_limit)).to eq(200)
73
+ expect(object_with_params.instance_variable_get(:@log_file)).to eq('passenger_monitor.log')
74
+ expect(object_with_params.instance_variable_get(:@wait_time)).to eq(15)
75
+ expect(object_with_params.instance_variable_get(:@process_name_regex)).to eq(/passenger/)
76
+ end
77
+ end
78
+ end
79
+
80
+ describe 'passenger workers' do
81
+ after do
82
+ PassengerMonitor::Monitor.run
83
+ end
84
+
85
+ context 'when workers are bloated' do
86
+ before do
87
+ stub_system_command
88
+ stub_process_kill(:kill, 'SIGUSR1', 25096)
89
+ stub_process_status
90
+ stub_wait
91
+ end
92
+
93
+ it 'tries to kill them gracefully' do
94
+ expect(Process).to receive(:kill).with('SIGUSR1', 25096)
95
+ end
96
+
97
+ it 'waits for the workers to get killed' do
98
+ expect_any_instance_of(PassengerMonitor::Monitor).to receive(:sleep).with(10)
99
+ end
100
+
101
+ context 'when workers are killed gracefully' do
102
+ it 'doesn\'t try to kill them forcefully' do
103
+ expect(Process).not_to receive(:kill).with('TERM', 25096)
104
+ end
105
+ end
106
+
107
+ context 'when workers are not killed gracefully' do
108
+ before do
109
+ stub_process_status(1)
110
+ end
111
+
112
+ it 'tries to kill them forcefully' do
113
+ expect(Process).to receive(:kill).with('TERM', 25096)
114
+ end
115
+ end
116
+ end
117
+
118
+ context 'when workers are not bloated' do
119
+ before { stub_system_command(%Q{
120
+ 25096 637.9 MB 105.4 MB Passenger RubyApp:
121
+ 25098 637.9 MB 120.4 MB Passenger RubyApp:
122
+ })
123
+ }
124
+
125
+ it 'doesn\'t create threads' do
126
+ expect(Thread).not_to receive(:new)
127
+ end
128
+ end
129
+ end
130
+ end
@@ -0,0 +1,8 @@
1
+ require 'bundler/setup'
2
+ Bundler.setup
3
+
4
+ require 'passenger_monitor'
5
+
6
+ RSpec.configure do |config|
7
+ # some (optional) config here
8
+ end
metadata ADDED
@@ -0,0 +1,104 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: passenger_monitor
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Akshay Vishnoi
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2016-12-04 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.7'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.7'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '10.0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '10.0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rspec
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '3.4'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '3.4'
55
+ description: |-
56
+ Monitors passenger workers of your application and if
57
+ the workers exceeds the memory limit then it kills it (first gracefully, wait and
58
+ then forcefully).
59
+ email:
60
+ - akshay.vishnoi@yahoo.com
61
+ executables: []
62
+ extensions: []
63
+ extra_rdoc_files: []
64
+ files:
65
+ - ".gitignore"
66
+ - Gemfile
67
+ - LICENSE
68
+ - LICENSE.txt
69
+ - README.md
70
+ - Rakefile
71
+ - lib/passenger_monitor.rb
72
+ - lib/passenger_monitor/monitor.rb
73
+ - lib/passenger_monitor/version.rb
74
+ - lib/tasks/schedule.rake
75
+ - passenger-monitor.gemspec
76
+ - spec/passenger_monitor/monitor_spec.rb
77
+ - spec/spec_helper.rb
78
+ homepage: https://github.com/vinsol/passenger-monitor
79
+ licenses:
80
+ - MIT
81
+ metadata: {}
82
+ post_install_message:
83
+ rdoc_options: []
84
+ require_paths:
85
+ - lib
86
+ required_ruby_version: !ruby/object:Gem::Requirement
87
+ requirements:
88
+ - - ">="
89
+ - !ruby/object:Gem::Version
90
+ version: '0'
91
+ required_rubygems_version: !ruby/object:Gem::Requirement
92
+ requirements:
93
+ - - ">="
94
+ - !ruby/object:Gem::Version
95
+ version: '0'
96
+ requirements: []
97
+ rubyforge_project:
98
+ rubygems_version: 2.4.3
99
+ signing_key:
100
+ specification_version: 4
101
+ summary: Monitors passenger workers and kill bloated ones
102
+ test_files:
103
+ - spec/passenger_monitor/monitor_spec.rb
104
+ - spec/spec_helper.rb