rails-idle 0.0.9
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +2 -0
- data/LICENSE +22 -0
- data/lib/rails-idle.rb +68 -0
- data/lib/rails-idle/collector.rb +21 -0
- data/lib/rails-idle/collector/base.rb +39 -0
- data/lib/rails-idle/collector/views.rb +92 -0
- data/lib/rails-idle/init.rb +22 -0
- data/lib/rails-idle/railtie.rb +9 -0
- data/lib/rails-idle/report.rb +42 -0
- data/lib/rails-idle/storage.rb +9 -0
- data/lib/rails-idle/storage/base.rb +33 -0
- data/lib/rails-idle/storage/rails_cache.rb +39 -0
- data/lib/rails-idle/tree_builder.rb +33 -0
- data/lib/rails-idle/version.rb +3 -0
- data/lib/rails-idle/web.rb +23 -0
- data/lib/rails-idle/web_helpers.rb +49 -0
- data/rails-idle.gemspec +22 -0
- data/web/assets/fonts/glyphicons-halflings-regular.eot +0 -0
- data/web/assets/fonts/glyphicons-halflings-regular.svg +288 -0
- data/web/assets/fonts/glyphicons-halflings-regular.ttf +0 -0
- data/web/assets/fonts/glyphicons-halflings-regular.woff +0 -0
- data/web/assets/fonts/glyphicons-halflings-regular.woff2 +0 -0
- data/web/assets/javascripts/jquery.min.js +4 -0
- data/web/assets/javascripts/jquery.treegrid.bootstrap3.js +4 -0
- data/web/assets/javascripts/jquery.treegrid.min.js +2 -0
- data/web/assets/stylesheets/bootstrap.min.css +5 -0
- data/web/assets/stylesheets/jquery.treegrid.css +6 -0
- data/web/views/dashboard.haml +21 -0
- data/web/views/layout.haml +18 -0
- metadata +114 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: f58b55e40ca14d9ba36db82d076cc50dc3ccba46
|
4
|
+
data.tar.gz: 8bde64f72b2e5dbd54d034132abe534ba2553d1f
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: ddffde060b6413844c73918b96440a479096c8e53212c2e93f8a7b3d1233148b8c341673ad5d80e9a56793b0b462c091095435d38848f4b975697cb275fb3f84
|
7
|
+
data.tar.gz: c5aae1b3eb90f11b0fbf95f8409a3d8efd6ad11529c2123ccdfba2f0a25d47ff71bcfbb16f043d8cb7da08bac3d77bdb422537bd7a74bb00c1d7a4066f3ee9ba
|
data/.gitignore
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
The MIT License (MIT)
|
2
|
+
|
3
|
+
Copyright (c) 2015 Vitalik Danchenko
|
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.
|
22
|
+
|
data/lib/rails-idle.rb
ADDED
@@ -0,0 +1,68 @@
|
|
1
|
+
require 'pathname'
|
2
|
+
require 'active_support/core_ext/hash'
|
3
|
+
require 'active_support/core_ext/string'
|
4
|
+
|
5
|
+
module RailsIdle
|
6
|
+
autoload :Storage, 'rails-idle/storage'
|
7
|
+
autoload :Collector, 'rails-idle/collector'
|
8
|
+
autoload :TreeBuilder, 'rails-idle/tree_builder'
|
9
|
+
autoload :Report, 'rails-idle/report'
|
10
|
+
autoload :Web, 'rails-idle/web'
|
11
|
+
|
12
|
+
DEFAULTS = {
|
13
|
+
collectors: RailsIdle::Collector.list,
|
14
|
+
reset: false,
|
15
|
+
cache: {
|
16
|
+
:views => Pathname.new('/tmp/cache/rails-idle/views.cache'),
|
17
|
+
},
|
18
|
+
}
|
19
|
+
|
20
|
+
class << self
|
21
|
+
|
22
|
+
def options
|
23
|
+
@options ||= DEFAULTS.dup
|
24
|
+
end
|
25
|
+
|
26
|
+
def options=(opts)
|
27
|
+
@options = opts
|
28
|
+
end
|
29
|
+
|
30
|
+
def configure
|
31
|
+
yield self
|
32
|
+
end
|
33
|
+
|
34
|
+
def collectors
|
35
|
+
options[:collectors]
|
36
|
+
end
|
37
|
+
|
38
|
+
def collectors=(list)
|
39
|
+
options[:collectors] = list.map(&:to_sym).select{|c| DEFAULTS[:collectors].include? c}
|
40
|
+
end
|
41
|
+
|
42
|
+
def cache=(hash)
|
43
|
+
hash.select{|key, _| DEFAULTS[:collectors].include? key}
|
44
|
+
_cache = hash.symbolize_keys.select{|c, _| DEFAULTS[:collectors].include? c}
|
45
|
+
options[:cache].merge!(_cache)
|
46
|
+
end
|
47
|
+
|
48
|
+
def reset?
|
49
|
+
options[:reset]
|
50
|
+
end
|
51
|
+
|
52
|
+
def reset=(value)
|
53
|
+
options[:reset] = value
|
54
|
+
end
|
55
|
+
|
56
|
+
def stylesheets
|
57
|
+
@stylesheets ||= []
|
58
|
+
end
|
59
|
+
|
60
|
+
def stylesheets=(sheets = [])
|
61
|
+
@stylesheets = sheets
|
62
|
+
end
|
63
|
+
|
64
|
+
end
|
65
|
+
|
66
|
+
end
|
67
|
+
|
68
|
+
require 'rails-idle/railtie' if defined?(::Rails)
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module RailsIdle
|
2
|
+
module Collector
|
3
|
+
autoload :Base, 'rails-idle/collector/base'
|
4
|
+
#autoload :Actions, 'rails-idle/collector/actions'
|
5
|
+
autoload :Views, 'rails-idle/collector/views'
|
6
|
+
# autoload :Stylesheets, 'rails-idle/collector/stylesheets'
|
7
|
+
|
8
|
+
class << self
|
9
|
+
|
10
|
+
def list
|
11
|
+
[:views]
|
12
|
+
end
|
13
|
+
|
14
|
+
def instance(key)
|
15
|
+
return RailsIdle::Collector::Views.instance if key == :views
|
16
|
+
# return RailsIdle::Collector::Stylesheets.instance if key == :stylesheets
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
require 'singleton'
|
2
|
+
|
3
|
+
module RailsIdle
|
4
|
+
module Collector
|
5
|
+
class Base
|
6
|
+
include Singleton
|
7
|
+
|
8
|
+
def collect
|
9
|
+
raise NotImplementedError
|
10
|
+
end
|
11
|
+
|
12
|
+
def subscribe
|
13
|
+
raise NotImplementedError
|
14
|
+
end
|
15
|
+
|
16
|
+
def push(item, execution_time = 1)
|
17
|
+
storage.add(item, execution_time)
|
18
|
+
end
|
19
|
+
|
20
|
+
def storage
|
21
|
+
@starage ||= RailsIdle::Storage::RailsCache.new
|
22
|
+
end
|
23
|
+
|
24
|
+
protected
|
25
|
+
|
26
|
+
def collector_key
|
27
|
+
self.class.to_s.demodulize.downcase.to_sym
|
28
|
+
end
|
29
|
+
|
30
|
+
private
|
31
|
+
|
32
|
+
def _collect(path)
|
33
|
+
storage.reset(path) if RailsIdle.reset?
|
34
|
+
storage.add(path)
|
35
|
+
end
|
36
|
+
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,92 @@
|
|
1
|
+
module RailsIdle
|
2
|
+
module Collector
|
3
|
+
class Views < Base
|
4
|
+
def collect
|
5
|
+
view_paths.each do |path|
|
6
|
+
views = Dir[path + '/**/*.*']
|
7
|
+
views.each do |view|
|
8
|
+
view = modify_prefix(view)
|
9
|
+
next unless view
|
10
|
+
if view =~ extensions_regexp
|
11
|
+
_collect view
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
def subscribe
|
18
|
+
%w{render_template render_partial render_collection}.each do |event|
|
19
|
+
ActiveSupport::Notifications.subscribe("#{event}.action_view") do |name, started, finished, unique_id, payload|
|
20
|
+
orig_prefix = ''
|
21
|
+
view = modify_prefix payload[:identifier], orig_prefix
|
22
|
+
next unless view
|
23
|
+
execution_time = finished.to_f - started.to_f
|
24
|
+
push(view, execution_time)
|
25
|
+
if payload[:layout] && view =~ /\.\w+\.\w+$/
|
26
|
+
# just_view = extract_view payload[:identifier], view
|
27
|
+
# prefix = payload[:identifier].gsub(just_view, '')
|
28
|
+
extension = view.match(/\.\w+\.\w+$/)[0]
|
29
|
+
layout = orig_prefix + '/' + payload[:layout] + extension
|
30
|
+
layout = modify_prefix layout
|
31
|
+
push(layout, execution_time) if layout
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
private
|
38
|
+
|
39
|
+
def view_paths
|
40
|
+
ActionController::Base.new.view_paths.map(&:to_path)
|
41
|
+
end
|
42
|
+
|
43
|
+
def extensions_regexp
|
44
|
+
@extensions_regexp ||= build_extensions_regexp
|
45
|
+
end
|
46
|
+
|
47
|
+
def build_extensions_regexp
|
48
|
+
formats = %w(html text)
|
49
|
+
handlers = ActionView::Template.template_handler_extensions
|
50
|
+
exts = view_extentions.join('|').gsub(/\./, '\.')
|
51
|
+
Regexp.new "(#{exts})$"
|
52
|
+
end
|
53
|
+
|
54
|
+
def view_extentions
|
55
|
+
@view_extentions ||= build_view_extentions
|
56
|
+
end
|
57
|
+
|
58
|
+
def build_view_extentions
|
59
|
+
extentions = []
|
60
|
+
format_extensions = %w(html text)
|
61
|
+
handler_extensions = ActionView::Template.template_handler_extensions
|
62
|
+
handler_extensions.each do |handler_ext|
|
63
|
+
extentions << ".#{handler_ext}"
|
64
|
+
format_extensions.each do |format_ext|
|
65
|
+
extentions << ".#{format_ext}.#{handler_ext}"
|
66
|
+
end
|
67
|
+
end
|
68
|
+
extentions
|
69
|
+
end
|
70
|
+
|
71
|
+
def modify_prefix(identifier, orig_prefix = '')
|
72
|
+
view_paths.each do |path|
|
73
|
+
orig_prefix.replace path
|
74
|
+
return identifier.gsub(path, path.gsub('/', '/')) if identifier.start_with?(path)
|
75
|
+
end
|
76
|
+
orig_prefix.replace ''
|
77
|
+
nil
|
78
|
+
end
|
79
|
+
|
80
|
+
# def extract_view(orig_prefix, modified_prefix)
|
81
|
+
# idx = 1
|
82
|
+
# view = ''
|
83
|
+
# while (idx <= orig_prefix.size && idx <= modified_prefix.size && orig_prefix[-idx] == modified_prefix[-idx])
|
84
|
+
# view = modified_prefix[-idx] + view
|
85
|
+
# idx += 1
|
86
|
+
# end
|
87
|
+
# view
|
88
|
+
# end
|
89
|
+
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
module RailsIdle
|
2
|
+
class << self
|
3
|
+
def init!
|
4
|
+
collect
|
5
|
+
subscribe
|
6
|
+
end
|
7
|
+
|
8
|
+
private
|
9
|
+
|
10
|
+
def _collectors
|
11
|
+
Hash[*(RailsIdle::Collector.list.map{|c| [c, RailsIdle::Collector.instance(c)]}.flatten)]
|
12
|
+
end
|
13
|
+
|
14
|
+
def collect
|
15
|
+
_collectors.select{|k, _| options[:collectors].include? k}.each_value(&:collect)
|
16
|
+
end
|
17
|
+
|
18
|
+
def subscribe
|
19
|
+
_collectors.select{|k, _| options[:collectors].include? k}.each_value(&:subscribe)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
module RailsIdle
|
2
|
+
class Report
|
3
|
+
CALCULATED_KEY = :calculated
|
4
|
+
COUNTER_KEY = RailsIdle::Storage::COUNTER_KEY
|
5
|
+
|
6
|
+
def initialize(collector)
|
7
|
+
@tree = TreeBuilder.new(collector).tree
|
8
|
+
end
|
9
|
+
|
10
|
+
def prepare
|
11
|
+
calc_counter!(@tree)
|
12
|
+
#sort!(@obj)
|
13
|
+
@tree
|
14
|
+
end
|
15
|
+
|
16
|
+
private
|
17
|
+
|
18
|
+
def calc_counter!(obj)
|
19
|
+
return obj[COUNTER_KEY] if obj[COUNTER_KEY].is_a?(Fixnum)
|
20
|
+
return obj[CALCULATED_KEY] if obj[CALCULATED_KEY].is_a?(Fixnum)
|
21
|
+
obj[CALCULATED_KEY] = obj.inject(0) do |sum, (key, nested_obj)|
|
22
|
+
sum + (key.is_a?(Symbol) ? 0 : calc_counter!(nested_obj))
|
23
|
+
end
|
24
|
+
obj[CALCULATED_KEY]
|
25
|
+
end
|
26
|
+
|
27
|
+
def sort!(obj)
|
28
|
+
obj.each do |k, v|
|
29
|
+
obj[k] = sort!(v) if v.is_a?(Hash)
|
30
|
+
end
|
31
|
+
obj.sort_by do |k, v|
|
32
|
+
if v.is_a?(Hash)
|
33
|
+
v[CALCULATED_KEY] || v[COUNTER_KEY] || 0
|
34
|
+
else
|
35
|
+
Float::INFINITY
|
36
|
+
end
|
37
|
+
end.to_h
|
38
|
+
end
|
39
|
+
|
40
|
+
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
module RailsIdle
|
2
|
+
module Storage
|
3
|
+
class Base
|
4
|
+
|
5
|
+
def add(path, execution_time = nil)
|
6
|
+
add_to_list path
|
7
|
+
end
|
8
|
+
|
9
|
+
def get(path, key)
|
10
|
+
raise NotImplementedError
|
11
|
+
end
|
12
|
+
|
13
|
+
def reset(path)
|
14
|
+
raise NotImplementedError
|
15
|
+
end
|
16
|
+
|
17
|
+
def objects_list
|
18
|
+
@objects_list ||= empty_list
|
19
|
+
end
|
20
|
+
|
21
|
+
private
|
22
|
+
|
23
|
+
def empty_list
|
24
|
+
[]
|
25
|
+
end
|
26
|
+
|
27
|
+
def add_to_list(path)
|
28
|
+
objects_list << path
|
29
|
+
end
|
30
|
+
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
module RailsIdle
|
2
|
+
module Storage
|
3
|
+
class RailsCache < Base
|
4
|
+
|
5
|
+
def add(path, execution_time = nil)
|
6
|
+
super
|
7
|
+
if execution_time
|
8
|
+
increment(path, COUNTER_KEY)
|
9
|
+
increment(path, EXECUTION_KEY, (execution_time * 1000).round)
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
def get(path, key)
|
14
|
+
begin
|
15
|
+
Rails.cache.read build_name(path, key)
|
16
|
+
rescue Exception => e # Redis workaround
|
17
|
+
(Rails.cache.read build_name(path, key), raw: true).to_i
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def reset(path)
|
22
|
+
[COUNTER_KEY, EXECUTION_KEY].each do |key|
|
23
|
+
Rails.cache.delete build_name(path, key)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
private
|
28
|
+
|
29
|
+
def increment(path, key, amount = 1)
|
30
|
+
Rails.cache.increment build_name(path, key), amount
|
31
|
+
end
|
32
|
+
|
33
|
+
def build_name(path, key)
|
34
|
+
"#{RailsIdle}.#{path}.#{key}"
|
35
|
+
end
|
36
|
+
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
module RailsIdle
|
2
|
+
class TreeBuilder
|
3
|
+
def initialize(collector)
|
4
|
+
@storage = collector.storage
|
5
|
+
end
|
6
|
+
|
7
|
+
def tree
|
8
|
+
@tree ||= build_tree
|
9
|
+
end
|
10
|
+
|
11
|
+
private
|
12
|
+
|
13
|
+
def build_tree
|
14
|
+
root = {}
|
15
|
+
@storage.objects_list.each do |path|
|
16
|
+
items = parse_path(path)
|
17
|
+
tree = root
|
18
|
+
items.each do |item|
|
19
|
+
tree[item] = {} unless tree[item]
|
20
|
+
tree = tree[item]
|
21
|
+
end
|
22
|
+
tree[RailsIdle::Storage::COUNTER_KEY] = @storage.get(path, RailsIdle::Storage::COUNTER_KEY)
|
23
|
+
tree[RailsIdle::Storage::EXECUTION_KEY] = @storage.get(path, RailsIdle::Storage::EXECUTION_KEY)
|
24
|
+
end
|
25
|
+
root
|
26
|
+
end
|
27
|
+
|
28
|
+
def parse_path(path)
|
29
|
+
path.split(/,|\/|::/)
|
30
|
+
end
|
31
|
+
|
32
|
+
end
|
33
|
+
end
|