dead_view_catcher 0.1
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/CHANGELOG.rdoc +3 -0
- data/MIT-LICENSE +20 -0
- data/README.rdoc +45 -0
- data/init.rb +1 -0
- data/lib/dead_view_catcher.rb +169 -0
- metadata +72 -0
data/CHANGELOG.rdoc
ADDED
data/MIT-LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2011 Guillaume Luccisano - g-mai|: guillaume.luccisano
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.rdoc
ADDED
@@ -0,0 +1,45 @@
|
|
1
|
+
= DeadViewCatcher
|
2
|
+
|
3
|
+
DeadViewCatcher is a gem for Ruby on Rails giving you an easy way to find which views you are not using anymore in your app.
|
4
|
+
This might be really useful for big Rails app maintained by a large team.
|
5
|
+
|
6
|
+
Works with Rails 2.3 (Will be tested against Rails3 soon)
|
7
|
+
|
8
|
+
== Usage
|
9
|
+
|
10
|
+
Simply load the gem in your rails app.
|
11
|
+
|
12
|
+
Then instantiate DeadViewCatcher during the boot:
|
13
|
+
|
14
|
+
DeadViewCatcher.watch!
|
15
|
+
|
16
|
+
Now, at any time, you can send a TRAP signal to your rails instance in order to generate a dump of your views status:
|
17
|
+
|
18
|
+
kill -s TRAP pid_of_your_instance
|
19
|
+
|
20
|
+
If you want to generate a consolidated dump gathering data from all your Rails instances, just choose one instance and send it the URG signal:
|
21
|
+
|
22
|
+
kill -s URG pid_of_one_of_your_instances
|
23
|
+
|
24
|
+
== Options
|
25
|
+
|
26
|
+
The watch! method accepts some options :
|
27
|
+
|
28
|
+
# The correct grep string in order to select instances of your app for consolidated dumps
|
29
|
+
# This option is mandatory if you plan to use the consolidated dump feature
|
30
|
+
DeadViewCatcher.watch!(:grep => 'unicorn_rails worker')
|
31
|
+
|
32
|
+
# Change the default signal
|
33
|
+
DeadViewCatcher.watch!(:signal => 'USR1')
|
34
|
+
|
35
|
+
# Change the consolidated default signal
|
36
|
+
DeadViewCatcher.watch!(:all_instances_signal => 'USR2')
|
37
|
+
|
38
|
+
# Change the default file for the dump
|
39
|
+
DeadViewCatcher.watch!(:file => '/tmp/somewhere.txt')
|
40
|
+
|
41
|
+
|
42
|
+
When customizing the signal you want to catch, be careful when picking one, as your server might already catch some (like Unicorn does for USR1 and USR2).
|
43
|
+
|
44
|
+
|
45
|
+
Copyright (c) 2011 Guillaume Luccisano - g-mai|: guillaume.luccisano, released under the MIT license
|
data/init.rb
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require 'dead_view_catcher'
|
@@ -0,0 +1,169 @@
|
|
1
|
+
module DeadViewCatcher
|
2
|
+
|
3
|
+
# DeadViewCatcher help you find easily not used views in your Rails app.
|
4
|
+
# It's not really Thread safe and using globals, but it's on purpose.
|
5
|
+
|
6
|
+
# Usage:
|
7
|
+
#
|
8
|
+
# Send a signal (TRAP by default) to one of your rails instance in order to create a dump of the dead views in tmp/dead_views.txt
|
9
|
+
# kill -s TRAP pid
|
10
|
+
#
|
11
|
+
# If you want a more globalized stats, you can use the all instances signal (URG by default)
|
12
|
+
# This signal will agregate the results of all instances by sending to all instances the TRAP signal.
|
13
|
+
# Then it will dump the consolidated stats in tmp/dead_views.txt (the default file)
|
14
|
+
#
|
15
|
+
# Note: SIGUSR1 and SIGUSR2 is not used as it's used by unicorn :/
|
16
|
+
|
17
|
+
DefaultOptions = {:signal => 'TRAP', :file => 'tmp/dead_views.txt', :all_instances_signal => 'URG'}
|
18
|
+
|
19
|
+
def self.watch!(opts = {})
|
20
|
+
options = DefaultOptions.merge(opts)
|
21
|
+
|
22
|
+
$dead_view_catcher_started_on = Time.now
|
23
|
+
$dead_view_catcher_nb_render = 0
|
24
|
+
$dead_view_catcher_views = build_views_hash
|
25
|
+
$dead_view_last_exception = nil
|
26
|
+
|
27
|
+
watch_signal!(options)
|
28
|
+
watch_all_instances_signal!(options) if !options[:grep].blank?
|
29
|
+
|
30
|
+
ActionView::Template.send :include, DeadViewCatcher::Extensions::ActionView
|
31
|
+
end
|
32
|
+
|
33
|
+
# Building the views hash (Only using app/views folders)
|
34
|
+
def self.build_views_hash
|
35
|
+
views = ActiveSupport::OrderedHash.new
|
36
|
+
|
37
|
+
Dir.glob(File.join(Rails.root, 'app', 'views', '**', '*')).each do |v|
|
38
|
+
if File.stat(v).file?
|
39
|
+
views[v.gsub(Rails.root, '').gsub(/^\//, '')] = 0
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
return views
|
44
|
+
end
|
45
|
+
|
46
|
+
def self.watch_signal!(options)
|
47
|
+
Signal.trap(options[:signal]) do
|
48
|
+
begin
|
49
|
+
puts ">> Dumping dead views..."
|
50
|
+
open(File.join(Rails.root, options[:file]), 'w+') do |fd|
|
51
|
+
fd.write(dump_hash($dead_view_catcher_views).to_yaml)
|
52
|
+
end
|
53
|
+
puts ">> Dead views dumped to #{options[:file]}"
|
54
|
+
rescue Exception => e
|
55
|
+
puts e.to_s + "\n" + e.backtrace.join("\n")
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
def self.watch_all_instances_signal!(options)
|
61
|
+
Signal.trap(options[:all_instances_signal]) do
|
62
|
+
begin
|
63
|
+
puts ">> Starting gathering consolidated dead views..."
|
64
|
+
# Getting all process pids :
|
65
|
+
ps = `ps aux | grep -i "#{options[:grep]}"`.split("\n").select { |l| !l.index('grep') }
|
66
|
+
pids = ps.collect { |l| (l.split(/ +/, 2)[1].to_i rescue nil) }.compact - [Process.pid]
|
67
|
+
|
68
|
+
last_pid = Process.pid
|
69
|
+
total_hash = dump_hash
|
70
|
+
total_hash[:pids] = [last_pid]
|
71
|
+
total_hash[:nb_instances] = 1
|
72
|
+
|
73
|
+
pids.each do |p|
|
74
|
+
# Sending the signal to other instances
|
75
|
+
`kill -s #{options[:signal]} #{p}`
|
76
|
+
|
77
|
+
# Now waiting for the output
|
78
|
+
i = 0; l = nil
|
79
|
+
while (!(l = YAML.load_file(options[:file]) rescue nil) or l[:pid] != p) and i < 15
|
80
|
+
sleep 0.1
|
81
|
+
i += 1
|
82
|
+
end
|
83
|
+
|
84
|
+
if l and l[:pid] and l[:pid] != last_pid
|
85
|
+
puts " >> Agregating data from pid #{l[:pid]}"
|
86
|
+
|
87
|
+
# Agregating datas...
|
88
|
+
total_hash[:running_hours] += l[:running_hours]
|
89
|
+
total_hash[:views_rendered] += l[:views_rendered]
|
90
|
+
total_hash[:exception_caught] += l[:exception_caught]
|
91
|
+
total_hash[:pids] << l[:pid]
|
92
|
+
total_hash[:nb_instances] = total_hash[:pids].size
|
93
|
+
l[:complete_stats].each do |k, v|
|
94
|
+
total_hash[:complete_stats][k] += v
|
95
|
+
end
|
96
|
+
|
97
|
+
last_pid = l[:pid]
|
98
|
+
else
|
99
|
+
puts " >> pid #{l[:pid]} skiped.."
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
total_hash[:dead_views] = dead_views(total_hash[:complete_stats])
|
104
|
+
|
105
|
+
open(File.join(Rails.root, options[:file]), 'w+') do |fd|
|
106
|
+
fd.write(total_hash.to_yaml)
|
107
|
+
end
|
108
|
+
puts ">> Consolidated Dead views dumped to #{options[:file]}"
|
109
|
+
rescue Exception => e
|
110
|
+
puts e.to_s + "\n" + e.backtrace.join("\n")
|
111
|
+
end
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
def self.dead_views(h = nil)
|
116
|
+
h ||= $dead_view_catcher_views
|
117
|
+
deads = ActiveSupport::OrderedHash.new
|
118
|
+
h.keys.sort.each do |k|
|
119
|
+
if h[k] == 0
|
120
|
+
deads[k] = h[k]
|
121
|
+
end
|
122
|
+
end
|
123
|
+
deads
|
124
|
+
end
|
125
|
+
|
126
|
+
def self.dump_hash(dead_views_hash = nil)
|
127
|
+
dump = ActiveSupport::OrderedHash.new
|
128
|
+
|
129
|
+
dump[:running_hours] = ((Time.now - $dead_view_catcher_started_on) / 3600).round(2)
|
130
|
+
dump[:views_rendered] = $dead_view_catcher_nb_render
|
131
|
+
dump[:time] = Time.now
|
132
|
+
dump[:pid] = Process.pid
|
133
|
+
dump[:exception_caught] = [$dead_view_last_exception].compact
|
134
|
+
dump[:dead_views] = dead_views(dead_views_hash)
|
135
|
+
dump[:complete_stats] = $dead_view_catcher_views
|
136
|
+
dump
|
137
|
+
end
|
138
|
+
|
139
|
+
module Extensions
|
140
|
+
module ActionView
|
141
|
+
|
142
|
+
def self.included(mod)
|
143
|
+
mod.send :alias_method, :dead_view_catcher_render, :render
|
144
|
+
mod.send :define_method, :render do |*opts|
|
145
|
+
view_catcher_rendered
|
146
|
+
dead_view_catcher_render(*opts)
|
147
|
+
end
|
148
|
+
end
|
149
|
+
|
150
|
+
def view_catcher_rendered
|
151
|
+
begin
|
152
|
+
rp = relative_path
|
153
|
+
if rp and rp.index('app/views') == 0
|
154
|
+
$dead_view_catcher_nb_render += 1
|
155
|
+
#Rails.logger.info "Rendering and counting: #{rp}"
|
156
|
+
begin
|
157
|
+
$dead_view_catcher_views[rp] += 1
|
158
|
+
rescue
|
159
|
+
raise "Index: #{rp} doesn't exist in dead_view_catcher_views Hash"
|
160
|
+
end
|
161
|
+
end
|
162
|
+
rescue Exception => e
|
163
|
+
$dead_view_last_exception = e.to_s + "\n" + e.backtrace.join("\n")
|
164
|
+
end
|
165
|
+
end
|
166
|
+
|
167
|
+
end
|
168
|
+
end
|
169
|
+
end
|
metadata
ADDED
@@ -0,0 +1,72 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: dead_view_catcher
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
hash: 9
|
5
|
+
prerelease:
|
6
|
+
segments:
|
7
|
+
- 0
|
8
|
+
- 1
|
9
|
+
version: "0.1"
|
10
|
+
platform: ruby
|
11
|
+
authors:
|
12
|
+
- Guillaume Luccisano
|
13
|
+
autorequire:
|
14
|
+
bindir: bin
|
15
|
+
cert_chain: []
|
16
|
+
|
17
|
+
date: 2011-01-12 00:00:00 -08:00
|
18
|
+
default_executable:
|
19
|
+
dependencies: []
|
20
|
+
|
21
|
+
description: DeadViewCatcher is a gem for Ruby on Rails giving you an easy way to find which views you are not using anymore in your app. Might be really useful for big Rails app.
|
22
|
+
email: guillaume.luccisano@gmail.com
|
23
|
+
executables: []
|
24
|
+
|
25
|
+
extensions: []
|
26
|
+
|
27
|
+
extra_rdoc_files: []
|
28
|
+
|
29
|
+
files:
|
30
|
+
- lib/dead_view_catcher.rb
|
31
|
+
- CHANGELOG.rdoc
|
32
|
+
- MIT-LICENSE
|
33
|
+
- README.rdoc
|
34
|
+
- init.rb
|
35
|
+
has_rdoc: true
|
36
|
+
homepage: http://github.com/kwi/dead_view_catcher
|
37
|
+
licenses: []
|
38
|
+
|
39
|
+
post_install_message:
|
40
|
+
rdoc_options: []
|
41
|
+
|
42
|
+
require_paths:
|
43
|
+
- lib
|
44
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
45
|
+
none: false
|
46
|
+
requirements:
|
47
|
+
- - ">="
|
48
|
+
- !ruby/object:Gem::Version
|
49
|
+
hash: 3
|
50
|
+
segments:
|
51
|
+
- 0
|
52
|
+
version: "0"
|
53
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
54
|
+
none: false
|
55
|
+
requirements:
|
56
|
+
- - ">="
|
57
|
+
- !ruby/object:Gem::Version
|
58
|
+
hash: 19
|
59
|
+
segments:
|
60
|
+
- 1
|
61
|
+
- 3
|
62
|
+
- 4
|
63
|
+
version: 1.3.4
|
64
|
+
requirements: []
|
65
|
+
|
66
|
+
rubyforge_project: dead_view_catcher
|
67
|
+
rubygems_version: 1.4.1
|
68
|
+
signing_key:
|
69
|
+
specification_version: 3
|
70
|
+
summary: Find easily wich views you are not using anymore in your Rails app.
|
71
|
+
test_files: []
|
72
|
+
|