rails-idle 0.0.9
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.
- 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
|