code_metric_fu 4.14.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.
- checksums.yaml +7 -0
- data/.gitignore +28 -0
- data/.metrics +3 -0
- data/.rspec +2 -0
- data/.rubocop.yml +15 -0
- data/.rubocop_todo.yml +69 -0
- data/.simplecov +74 -0
- data/.travis.yml +22 -0
- data/.yardopts +4 -0
- data/AUTHORS +12 -0
- data/CONTRIBUTING.md +47 -0
- data/CONTRIBUTORS +76 -0
- data/DEV.md +76 -0
- data/Gemfile +74 -0
- data/Guardfile +30 -0
- data/HISTORY.md +705 -0
- data/MIT-LICENSE +22 -0
- data/README.md +299 -0
- data/Rakefile +27 -0
- data/TODO.md +118 -0
- data/appveyor.yml +31 -0
- data/bin/metric_fu +9 -0
- data/bin/mf-cane +10 -0
- data/bin/mf-churn +10 -0
- data/bin/mf-flay +10 -0
- data/bin/mf-reek +10 -0
- data/bin/mf-roodi +10 -0
- data/bin/mf-saikuro +10 -0
- data/certs/bf4.pem +22 -0
- data/checksum/.gitkeep +0 -0
- data/checksum/metric_fu-4.10.0.gem.sha512 +1 -0
- data/checksum/metric_fu-4.11.0.gem.sha512 +1 -0
- data/checksum/metric_fu-4.11.1.gem.sha512 +1 -0
- data/checksum/metric_fu-4.11.2.gem.sha512 +1 -0
- data/checksum/metric_fu-4.11.3.gem.sha512 +1 -0
- data/checksum/metric_fu-4.11.4.gem.sha512 +1 -0
- data/checksum/metric_fu-4.12.0.gem.sha512 +1 -0
- data/checksum/metric_fu-4.2.0.gem.sha512 +1 -0
- data/checksum/metric_fu-4.2.1.gem.sha512 +1 -0
- data/checksum/metric_fu-4.3.0.gem.sha512 +1 -0
- data/checksum/metric_fu-4.3.1.gem.sha512 +1 -0
- data/checksum/metric_fu-4.4.0.gem.sha512 +1 -0
- data/checksum/metric_fu-4.4.1.gem.sha512 +1 -0
- data/checksum/metric_fu-4.4.2.gem.sha512 +1 -0
- data/checksum/metric_fu-4.4.3.gem.sha512 +1 -0
- data/checksum/metric_fu-4.4.4.gem.sha512 +1 -0
- data/checksum/metric_fu-4.5.0.gem.sha512 +1 -0
- data/checksum/metric_fu-4.5.1.gem.sha512 +1 -0
- data/checksum/metric_fu-4.5.2.gem.sha512 +1 -0
- data/checksum/metric_fu-4.6.0.gem.sha512 +1 -0
- data/checksum/metric_fu-4.7.0.gem.sha512 +1 -0
- data/checksum/metric_fu-4.7.1.gem.sha512 +1 -0
- data/checksum/metric_fu-4.7.2.gem.sha512 +1 -0
- data/checksum/metric_fu-4.7.3.gem.sha512 +1 -0
- data/checksum/metric_fu-4.7.4.gem.sha512 +1 -0
- data/checksum/metric_fu-4.8.0.gem.sha512 +1 -0
- data/checksum/metric_fu-4.9.0.gem.sha512 +1 -0
- data/config/roodi_config.yml +22 -0
- data/config/rubocop.yml +269 -0
- data/gem_tasks/build.rake +197 -0
- data/gem_tasks/rubocop.rake +10 -0
- data/gem_tasks/usage_test.rake +19 -0
- data/gem_tasks/yard.rake +24 -0
- data/lib/metric_fu/calculate.rb +10 -0
- data/lib/metric_fu/cli/client.rb +26 -0
- data/lib/metric_fu/cli/helper.rb +80 -0
- data/lib/metric_fu/cli/parser.rb +138 -0
- data/lib/metric_fu/configuration.rb +150 -0
- data/lib/metric_fu/constantize.rb +57 -0
- data/lib/metric_fu/data_structures/line_numbers.rb +112 -0
- data/lib/metric_fu/data_structures/location.rb +110 -0
- data/lib/metric_fu/data_structures/sexp_node.rb +107 -0
- data/lib/metric_fu/environment.rb +129 -0
- data/lib/metric_fu/errors/analysis_error.rb +4 -0
- data/lib/metric_fu/formatter/html.rb +96 -0
- data/lib/metric_fu/formatter/syntax.rb +45 -0
- data/lib/metric_fu/formatter/yaml.rb +18 -0
- data/lib/metric_fu/formatter.rb +40 -0
- data/lib/metric_fu/gem_run.rb +70 -0
- data/lib/metric_fu/gem_version.rb +92 -0
- data/lib/metric_fu/generator.rb +135 -0
- data/lib/metric_fu/io.rb +132 -0
- data/lib/metric_fu/loader.rb +105 -0
- data/lib/metric_fu/logger.rb +62 -0
- data/lib/metric_fu/logging/mf_debugger.rb +23 -0
- data/lib/metric_fu/metric.rb +143 -0
- data/lib/metric_fu/metrics/cane/generator.rb +95 -0
- data/lib/metric_fu/metrics/cane/grapher.rb +37 -0
- data/lib/metric_fu/metrics/cane/metric.rb +34 -0
- data/lib/metric_fu/metrics/cane/report.html.erb +87 -0
- data/lib/metric_fu/metrics/cane/violations.rb +46 -0
- data/lib/metric_fu/metrics/churn/generator.rb +37 -0
- data/lib/metric_fu/metrics/churn/hotspot.rb +43 -0
- data/lib/metric_fu/metrics/churn/metric.rb +29 -0
- data/lib/metric_fu/metrics/churn/report.html.erb +58 -0
- data/lib/metric_fu/metrics/flay/generator.rb +51 -0
- data/lib/metric_fu/metrics/flay/grapher.rb +37 -0
- data/lib/metric_fu/metrics/flay/hotspot.rb +52 -0
- data/lib/metric_fu/metrics/flay/metric.rb +28 -0
- data/lib/metric_fu/metrics/flay/report.html.erb +29 -0
- data/lib/metric_fu/metrics/flog/generator.rb +113 -0
- data/lib/metric_fu/metrics/flog/grapher.rb +77 -0
- data/lib/metric_fu/metrics/flog/hotspot.rb +46 -0
- data/lib/metric_fu/metrics/flog/metric.rb +29 -0
- data/lib/metric_fu/metrics/flog/report.html.erb +50 -0
- data/lib/metric_fu/metrics/hotspots/analysis/analyzed_problems.rb +34 -0
- data/lib/metric_fu/metrics/hotspots/analysis/analyzer_tables.rb +114 -0
- data/lib/metric_fu/metrics/hotspots/analysis/grouping.rb +23 -0
- data/lib/metric_fu/metrics/hotspots/analysis/groupings.rb +12 -0
- data/lib/metric_fu/metrics/hotspots/analysis/problems.rb +20 -0
- data/lib/metric_fu/metrics/hotspots/analysis/ranked_problem_location.rb +70 -0
- data/lib/metric_fu/metrics/hotspots/analysis/ranking.rb +29 -0
- data/lib/metric_fu/metrics/hotspots/analysis/rankings.rb +91 -0
- data/lib/metric_fu/metrics/hotspots/analysis/record.rb +32 -0
- data/lib/metric_fu/metrics/hotspots/analysis/scoring_strategies.rb +24 -0
- data/lib/metric_fu/metrics/hotspots/analysis/table.rb +67 -0
- data/lib/metric_fu/metrics/hotspots/generator.rb +40 -0
- data/lib/metric_fu/metrics/hotspots/hotspot.rb +87 -0
- data/lib/metric_fu/metrics/hotspots/hotspot_analyzer.rb +61 -0
- data/lib/metric_fu/metrics/hotspots/metric.rb +20 -0
- data/lib/metric_fu/metrics/hotspots/report.html.erb +60 -0
- data/lib/metric_fu/metrics/rails_best_practices/generator.rb +47 -0
- data/lib/metric_fu/metrics/rails_best_practices/grapher.rb +38 -0
- data/lib/metric_fu/metrics/rails_best_practices/metric.rb +31 -0
- data/lib/metric_fu/metrics/rails_best_practices/report.html.erb +22 -0
- data/lib/metric_fu/metrics/rcov/external_client.rb +22 -0
- data/lib/metric_fu/metrics/rcov/generator.rb +75 -0
- data/lib/metric_fu/metrics/rcov/grapher.rb +37 -0
- data/lib/metric_fu/metrics/rcov/hotspot.rb +46 -0
- data/lib/metric_fu/metrics/rcov/metric.rb +61 -0
- data/lib/metric_fu/metrics/rcov/rcov_format_coverage.rb +149 -0
- data/lib/metric_fu/metrics/rcov/rcov_line.rb +48 -0
- data/lib/metric_fu/metrics/rcov/report.html.erb +40 -0
- data/lib/metric_fu/metrics/rcov/simplecov_formatter.rb +74 -0
- data/lib/metric_fu/metrics/reek/generator.rb +97 -0
- data/lib/metric_fu/metrics/reek/grapher.rb +55 -0
- data/lib/metric_fu/metrics/reek/hotspot.rb +95 -0
- data/lib/metric_fu/metrics/reek/metric.rb +26 -0
- data/lib/metric_fu/metrics/reek/report.html.erb +35 -0
- data/lib/metric_fu/metrics/roodi/generator.rb +41 -0
- data/lib/metric_fu/metrics/roodi/grapher.rb +37 -0
- data/lib/metric_fu/metrics/roodi/hotspot.rb +39 -0
- data/lib/metric_fu/metrics/roodi/metric.rb +24 -0
- data/lib/metric_fu/metrics/roodi/report.html.erb +22 -0
- data/lib/metric_fu/metrics/saikuro/generator.rb +145 -0
- data/lib/metric_fu/metrics/saikuro/hotspot.rb +51 -0
- data/lib/metric_fu/metrics/saikuro/metric.rb +31 -0
- data/lib/metric_fu/metrics/saikuro/parsing_element.rb +37 -0
- data/lib/metric_fu/metrics/saikuro/report.html.erb +71 -0
- data/lib/metric_fu/metrics/saikuro/scratch_file.rb +108 -0
- data/lib/metric_fu/metrics/stats/generator.rb +82 -0
- data/lib/metric_fu/metrics/stats/grapher.rb +40 -0
- data/lib/metric_fu/metrics/stats/hotspot.rb +35 -0
- data/lib/metric_fu/metrics/stats/metric.rb +28 -0
- data/lib/metric_fu/metrics/stats/report.html.erb +44 -0
- data/lib/metric_fu/reporter.rb +37 -0
- data/lib/metric_fu/reporting/graphs/graph.rb +69 -0
- data/lib/metric_fu/reporting/graphs/grapher.rb +66 -0
- data/lib/metric_fu/reporting/result.rb +59 -0
- data/lib/metric_fu/run.rb +82 -0
- data/lib/metric_fu/tasks/metric_fu.rake +54 -0
- data/lib/metric_fu/templates/_gem_info.html.erb +8 -0
- data/lib/metric_fu/templates/_graph.html.erb +2 -0
- data/lib/metric_fu/templates/_report_footer.html.erb +1 -0
- data/lib/metric_fu/templates/configuration.rb +25 -0
- data/lib/metric_fu/templates/css/bluff.css +15 -0
- data/lib/metric_fu/templates/css/buttons.css +82 -0
- data/lib/metric_fu/templates/css/default.css +43 -0
- data/lib/metric_fu/templates/css/integrity.css +337 -0
- data/lib/metric_fu/templates/css/rcov.css +32 -0
- data/lib/metric_fu/templates/css/reset.css +7 -0
- data/lib/metric_fu/templates/css/syntax.css +19 -0
- data/lib/metric_fu/templates/index.html.erb +13 -0
- data/lib/metric_fu/templates/javascripts/bluff-min.js +1 -0
- data/lib/metric_fu/templates/javascripts/bluff_graph.js +15 -0
- data/lib/metric_fu/templates/javascripts/excanvas.js +35 -0
- data/lib/metric_fu/templates/javascripts/highcharts.js +294 -0
- data/lib/metric_fu/templates/javascripts/highcharts_graph.js +38 -0
- data/lib/metric_fu/templates/javascripts/js-class.js +1 -0
- data/lib/metric_fu/templates/javascripts/standalone-framework.js +17 -0
- data/lib/metric_fu/templates/javascripts/utils.js +9 -0
- data/lib/metric_fu/templates/layout.html.erb +41 -0
- data/lib/metric_fu/templates/metrics_template.rb +86 -0
- data/lib/metric_fu/templates/report.html.erb +31 -0
- data/lib/metric_fu/templates/report.rb +41 -0
- data/lib/metric_fu/templates/template.rb +247 -0
- data/lib/metric_fu/utility.rb +79 -0
- data/lib/metric_fu/version.rb +9 -0
- data/lib/metric_fu.rb +143 -0
- data/metric_fu.gemspec +72 -0
- data/spec/capture_warnings.rb +55 -0
- data/spec/cli/helper_spec.rb +165 -0
- data/spec/dummy/.gitignore +1 -0
- data/spec/dummy/.gitkeep +0 -0
- data/spec/dummy/.metrics +4 -0
- data/spec/dummy/lib/.gitkeep +0 -0
- data/spec/dummy/lib/bad_encoding.rb +6 -0
- data/spec/dummy/spec/.gitkeep +0 -0
- data/spec/fixtures/20090630.yml +7922 -0
- data/spec/fixtures/coverage-153.rb +11 -0
- data/spec/fixtures/coverage.rb +13 -0
- data/spec/fixtures/exit0.sh +3 -0
- data/spec/fixtures/exit1.sh +3 -0
- data/spec/fixtures/hotspots/flog.yml +86 -0
- data/spec/fixtures/hotspots/generator.yml +47 -0
- data/spec/fixtures/hotspots/generator_analysis.yml +53 -0
- data/spec/fixtures/hotspots/reek.yml +14 -0
- data/spec/fixtures/hotspots/roodi.yml +13 -0
- data/spec/fixtures/hotspots/saikuro.yml +27 -0
- data/spec/fixtures/hotspots/several_metrics.yml +47 -0
- data/spec/fixtures/hotspots/stats.yml +4 -0
- data/spec/fixtures/hotspots/three_metrics_on_same_file.yml +36 -0
- data/spec/fixtures/line_numbers/foo.rb +33 -0
- data/spec/fixtures/line_numbers/module.rb +11 -0
- data/spec/fixtures/line_numbers/module_surrounds_class.rb +15 -0
- data/spec/fixtures/line_numbers/two_classes.rb +11 -0
- data/spec/fixtures/metric_missing.yml +1 -0
- data/spec/fixtures/rcov_output.txt +135 -0
- data/spec/fixtures/saikuro/app/controllers/sessions_controller.rb_cyclo.html +10 -0
- data/spec/fixtures/saikuro/app/controllers/users_controller.rb_cyclo.html +16 -0
- data/spec/fixtures/saikuro/index_cyclo.html +155 -0
- data/spec/fixtures/saikuro_sfiles/thing.rb_cyclo.html +11 -0
- data/spec/metric_fu/calculate_spec.rb +21 -0
- data/spec/metric_fu/configuration_spec.rb +90 -0
- data/spec/metric_fu/data_structures/line_numbers_spec.rb +63 -0
- data/spec/metric_fu/data_structures/location_spec.rb +110 -0
- data/spec/metric_fu/formatter/configuration_spec.rb +44 -0
- data/spec/metric_fu/formatter/html_spec.rb +138 -0
- data/spec/metric_fu/formatter/yaml_spec.rb +61 -0
- data/spec/metric_fu/formatter_spec.rb +49 -0
- data/spec/metric_fu/gem_version_spec.rb +12 -0
- data/spec/metric_fu/generator_spec.rb +130 -0
- data/spec/metric_fu/loader_spec.rb +10 -0
- data/spec/metric_fu/metric_spec.rb +46 -0
- data/spec/metric_fu/metrics/cane/configuration_spec.rb +22 -0
- data/spec/metric_fu/metrics/cane/generator_spec.rb +184 -0
- data/spec/metric_fu/metrics/churn/configuration_spec.rb +13 -0
- data/spec/metric_fu/metrics/churn/generator_spec.rb +64 -0
- data/spec/metric_fu/metrics/flay/configuration_spec.rb +13 -0
- data/spec/metric_fu/metrics/flay/generator_spec.rb +105 -0
- data/spec/metric_fu/metrics/flay/grapher_spec.rb +57 -0
- data/spec/metric_fu/metrics/flog/configuration_spec.rb +18 -0
- data/spec/metric_fu/metrics/flog/generator_spec.rb +77 -0
- data/spec/metric_fu/metrics/flog/grapher_spec.rb +107 -0
- data/spec/metric_fu/metrics/hotspots/analysis/analyzed_problems_spec.rb +104 -0
- data/spec/metric_fu/metrics/hotspots/analysis/analyzer_tables_spec.rb +71 -0
- data/spec/metric_fu/metrics/hotspots/analysis/ranking_spec.rb +30 -0
- data/spec/metric_fu/metrics/hotspots/analysis/rankings_spec.rb +97 -0
- data/spec/metric_fu/metrics/hotspots/analysis/table_spec.rb +6 -0
- data/spec/metric_fu/metrics/hotspots/generator_spec.rb +46 -0
- data/spec/metric_fu/metrics/hotspots/hotspot_analyzer_spec.rb +10 -0
- data/spec/metric_fu/metrics/hotspots/hotspot_spec.rb +16 -0
- data/spec/metric_fu/metrics/rails_best_practices/configuration_spec.rb +55 -0
- data/spec/metric_fu/metrics/rails_best_practices/generator_spec.rb +33 -0
- data/spec/metric_fu/metrics/rails_best_practices/grapher_spec.rb +62 -0
- data/spec/metric_fu/metrics/rcov/configuration_spec.rb +28 -0
- data/spec/metric_fu/metrics/rcov/generator_spec.rb +22 -0
- data/spec/metric_fu/metrics/rcov/grapher_spec.rb +57 -0
- data/spec/metric_fu/metrics/rcov/hotspot_spec.rb +20 -0
- data/spec/metric_fu/metrics/rcov/rcov_line_spec.rb +89 -0
- data/spec/metric_fu/metrics/rcov/simplecov_formatter_spec.rb +67 -0
- data/spec/metric_fu/metrics/reek/configuration_spec.rb +13 -0
- data/spec/metric_fu/metrics/reek/generator_spec.rb +169 -0
- data/spec/metric_fu/metrics/reek/grapher_spec.rb +66 -0
- data/spec/metric_fu/metrics/roodi/configuration_spec.rb +14 -0
- data/spec/metric_fu/metrics/roodi/generator_spec.rb +82 -0
- data/spec/metric_fu/metrics/roodi/grapher_spec.rb +57 -0
- data/spec/metric_fu/metrics/saikuro/configuration_spec.rb +25 -0
- data/spec/metric_fu/metrics/saikuro/generator_spec.rb +71 -0
- data/spec/metric_fu/metrics/stats/generator_spec.rb +96 -0
- data/spec/metric_fu/metrics/stats/grapher_spec.rb +69 -0
- data/spec/metric_fu/reporter_spec.rb +41 -0
- data/spec/metric_fu/reporting/graphs/graph_spec.rb +44 -0
- data/spec/metric_fu/reporting/graphs/grapher_spec.rb +24 -0
- data/spec/metric_fu/reporting/result_spec.rb +50 -0
- data/spec/metric_fu/run_spec.rb +197 -0
- data/spec/metric_fu/templates/configuration_spec.rb +51 -0
- data/spec/metric_fu/templates/metrics_template_spec.rb +11 -0
- data/spec/metric_fu/templates/report_spec.rb +15 -0
- data/spec/metric_fu/templates/template_spec.rb +233 -0
- data/spec/metric_fu/utility_spec.rb +12 -0
- data/spec/metric_fu_spec.rb +33 -0
- data/spec/quality_spec.rb +114 -0
- data/spec/shared/configured.rb +45 -0
- data/spec/shared/test_coverage.rb +95 -0
- data/spec/spec_helper.rb +54 -0
- data/spec/support/deferred_garbaged_collection.rb +33 -0
- data/spec/support/helper_methods.rb +32 -0
- data/spec/support/matcher_create_file.rb +37 -0
- data/spec/support/matcher_create_files.rb +43 -0
- data/spec/support/suite.rb +26 -0
- data/spec/support/test_fixtures.rb +37 -0
- data/spec/support/timeout.rb +7 -0
- data/spec/support/usage_test.rb +150 -0
- data/spec/usage_test_spec.rb +93 -0
- metadata +757 -0
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
class MetricFu::FlogHotspot < MetricFu::Hotspot
|
|
2
|
+
COLUMNS = %w{score}
|
|
3
|
+
|
|
4
|
+
def columns
|
|
5
|
+
COLUMNS
|
|
6
|
+
end
|
|
7
|
+
|
|
8
|
+
def name
|
|
9
|
+
:flog
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def map_strategy
|
|
13
|
+
:score
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def reduce_strategy
|
|
17
|
+
:average
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def score_strategy
|
|
21
|
+
:identity
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def generate_records(data, table)
|
|
25
|
+
return if data == nil
|
|
26
|
+
Array(data[:method_containers]).each do |method_container|
|
|
27
|
+
Array(method_container[:methods]).each do |entry|
|
|
28
|
+
file_path = entry[1][:path].sub(%r{^/}, "") if entry[1][:path]
|
|
29
|
+
location = MetricFu::Location.for(entry.first)
|
|
30
|
+
table << {
|
|
31
|
+
"metric" => name,
|
|
32
|
+
"score" => entry[1][:score],
|
|
33
|
+
"file_path" => file_path,
|
|
34
|
+
"class_name" => location.class_name,
|
|
35
|
+
"method_name" => location.method_name
|
|
36
|
+
}
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def present_group(group)
|
|
42
|
+
occurences = group.size
|
|
43
|
+
complexity = get_mean(group.column("score"))
|
|
44
|
+
"#{'average ' if occurences > 1}complexity is %.1f" % complexity
|
|
45
|
+
end
|
|
46
|
+
end
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
module MetricFu
|
|
2
|
+
class MetricFlog < Metric
|
|
3
|
+
def name
|
|
4
|
+
:flog
|
|
5
|
+
end
|
|
6
|
+
|
|
7
|
+
def default_run_options
|
|
8
|
+
{ dirs_to_flog: MetricFu::Io::FileSystem.directory("code_dirs"), continue: true, all: true, quiet: true }
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def has_graph?
|
|
12
|
+
true
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def enable
|
|
16
|
+
if MetricFu.configuration.mri?
|
|
17
|
+
super
|
|
18
|
+
else
|
|
19
|
+
MetricFu.logger.debug("Flog is only available in MRI due to flog tasks")
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def activate
|
|
24
|
+
activate_library "flog"
|
|
25
|
+
activate_library "flog_cli"
|
|
26
|
+
super
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
<h3>Flog Results</h3>
|
|
2
|
+
<p><a href='http://ruby.sadi.st/Flog.html'>Flog</a> measures code complexity.</p>
|
|
3
|
+
|
|
4
|
+
<%= render_partial 'graph', {:graph_name => 'flog'} %>
|
|
5
|
+
|
|
6
|
+
<h2>Total Flog score for all methods: <%= round_to_tenths @flog[:total]%></h2>
|
|
7
|
+
<h2>Average Flog score for all methods: <%= round_to_tenths @flog[:average]%></h2>
|
|
8
|
+
|
|
9
|
+
<table>
|
|
10
|
+
<tr>
|
|
11
|
+
<th>File</th>
|
|
12
|
+
<th>Total score</th>
|
|
13
|
+
<th>Methods</th>
|
|
14
|
+
<th>Average score</th>
|
|
15
|
+
<th>Highest score</th>
|
|
16
|
+
</tr>
|
|
17
|
+
<% @flog[:method_containers].each do |method_container| %>
|
|
18
|
+
<tr>
|
|
19
|
+
<td><a href="#<%= method_container[:path].gsub(/[^a-z]+/, '_') %>"><%= method_container[:path] %></a></td>
|
|
20
|
+
<td><%= round_to_tenths method_container[:total_score] %></td>
|
|
21
|
+
<td><%= method_container[:methods].size %></td>
|
|
22
|
+
<td><%= round_to_tenths method_container[:average_score] %></td>
|
|
23
|
+
<td><%= round_to_tenths method_container[:highest_score] %></td>
|
|
24
|
+
</tr>
|
|
25
|
+
<% end %>
|
|
26
|
+
</table>
|
|
27
|
+
|
|
28
|
+
<% @flog[:method_containers].each do |method_container| %>
|
|
29
|
+
<h2 id="<%= method_container[:path].gsub(/[^a-z]+/, '_') %>"><%= link_to_filename(method_container[:path]) %></h2>
|
|
30
|
+
|
|
31
|
+
<% method_container[:methods].each do |full_method_name, method_info| %>
|
|
32
|
+
<% path, line = method_info[:path].split(":") if method_info[:path] %>
|
|
33
|
+
<p><%= link_to_filename(path, line, full_method_name) %></p>
|
|
34
|
+
<p>Total Score: <%= round_to_tenths method_info[:score]%></p>
|
|
35
|
+
<table>
|
|
36
|
+
<tr>
|
|
37
|
+
<th>Score</th>
|
|
38
|
+
<th>Operator</th>
|
|
39
|
+
</tr>
|
|
40
|
+
<% method_info[:operators].each do |operator, score| %>
|
|
41
|
+
<tr>
|
|
42
|
+
<td><%= round_to_tenths score %></td>
|
|
43
|
+
<td><%= operator %></td>
|
|
44
|
+
</tr>
|
|
45
|
+
<% end %>
|
|
46
|
+
</table>
|
|
47
|
+
<% end %>
|
|
48
|
+
<% end %>
|
|
49
|
+
|
|
50
|
+
<%= render_partial 'report_footer' %>
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
module MetricFu
|
|
2
|
+
class HotspotAnalyzedProblems
|
|
3
|
+
MetricFu.metrics_require { "hotspots/analysis/ranked_problem_location" }
|
|
4
|
+
|
|
5
|
+
def initialize(hotspot_rankings, analyzer_tables)
|
|
6
|
+
@hotspot_rankings = hotspot_rankings
|
|
7
|
+
@analyzer_tables = analyzer_tables
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def worst_items
|
|
11
|
+
worst_items = {}
|
|
12
|
+
worst_items[:files] = worst(@hotspot_rankings.worst_files, :file)
|
|
13
|
+
worst_items[:classes] = worst(@hotspot_rankings.worst_classes, :class)
|
|
14
|
+
worst_items[:methods] = worst(@hotspot_rankings.worst_methods, :method)
|
|
15
|
+
worst_items
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
private
|
|
19
|
+
|
|
20
|
+
# @param rankings [Array<MetricFu::HotspotRankings>]
|
|
21
|
+
# @param granularity [Symbol] one of :class, :method, :file
|
|
22
|
+
def worst(rankings, granularity)
|
|
23
|
+
rankings.map do |ranked_item_name|
|
|
24
|
+
sub_table = get_sub_table(granularity, ranked_item_name)
|
|
25
|
+
MetricFu::HotspotRankedProblemLocation.new(sub_table, granularity)
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def get_sub_table(granularity, ranked_item_name)
|
|
30
|
+
tables = @analyzer_tables.tables_for(granularity)
|
|
31
|
+
tables[ranked_item_name]
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
end
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
module MetricFu
|
|
2
|
+
class AnalyzerTables
|
|
3
|
+
%w(table).each do |path|
|
|
4
|
+
MetricFu.metrics_require { "hotspots/analysis/#{path}" }
|
|
5
|
+
end
|
|
6
|
+
|
|
7
|
+
def initialize(analyzer_columns)
|
|
8
|
+
@columns = analyzer_columns
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def generate_records
|
|
12
|
+
build_lookups!
|
|
13
|
+
process_rows!
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def tool_tables
|
|
17
|
+
@tool_tables ||= make_table_hash(@columns)
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def table
|
|
21
|
+
@table ||= make_table(@columns)
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def tables_for(item)
|
|
25
|
+
{
|
|
26
|
+
class: @class_tables,
|
|
27
|
+
method: @method_tables,
|
|
28
|
+
file: @file_tables,
|
|
29
|
+
tool: @tool_tables
|
|
30
|
+
}.fetch(item) do
|
|
31
|
+
raise ArgumentError, "Item must be :class, :method, or :file, but was #{item}"
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
private
|
|
36
|
+
|
|
37
|
+
def make_table(columns)
|
|
38
|
+
MetricFu::Table.new(column_names: columns)
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def make_table_hash(columns)
|
|
42
|
+
Hash.new { |hash, key|
|
|
43
|
+
hash[key] = make_table(columns)
|
|
44
|
+
}
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
# COLLECT AND PROCESS RAW HOTSPOT METRICS
|
|
48
|
+
def build_lookups!
|
|
49
|
+
@class_and_method_to_file ||= {}
|
|
50
|
+
# Build a mapping from [class,method] => filename
|
|
51
|
+
# (and make sure the mapping is unique)
|
|
52
|
+
table.each do |row|
|
|
53
|
+
# We know that Saikuro provides the wrong data
|
|
54
|
+
# TODO inject Saikuro reference
|
|
55
|
+
next if row["metric"] == :saikuro
|
|
56
|
+
key = [row["class_name"], row["method_name"]]
|
|
57
|
+
file_path = row["file_path"]
|
|
58
|
+
@class_and_method_to_file[key] ||= file_path
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
# COLLECT AND PROCESS RAW HOTSPOT METRICS
|
|
63
|
+
def process_rows!
|
|
64
|
+
# Correct incorrect rows in the table
|
|
65
|
+
table.each do |row|
|
|
66
|
+
row_metric = row["metric"] # perf optimization
|
|
67
|
+
# TODO inject Saikuro reference
|
|
68
|
+
if row_metric == :saikuro
|
|
69
|
+
fix_row_file_path!(row)
|
|
70
|
+
end
|
|
71
|
+
tool_tables[row_metric] << row
|
|
72
|
+
file_tables[row["file_path"]] << row
|
|
73
|
+
class_tables[row["class_name"]] << row
|
|
74
|
+
method_tables[row["method_name"]] << row
|
|
75
|
+
end
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
# COLLECT AND PROCESS RAW HOTSPOT METRICS
|
|
79
|
+
def fix_row_file_path!(row)
|
|
80
|
+
# We know that Saikuro rows are broken
|
|
81
|
+
# next unless row['metric'] == :saikuro
|
|
82
|
+
key = [row["class_name"], row["method_name"]]
|
|
83
|
+
current_file_path = row["file_path"].to_s
|
|
84
|
+
correct_file_path = @class_and_method_to_file[key]
|
|
85
|
+
if !correct_file_path.nil? && correct_file_path.include?(current_file_path)
|
|
86
|
+
row["file_path"] = correct_file_path
|
|
87
|
+
else
|
|
88
|
+
# There wasn't an exact match, so we can do a substring match
|
|
89
|
+
matching_file_path = file_paths.detect {|file_path|
|
|
90
|
+
!file_path.nil? && file_path.include?(current_file_path)
|
|
91
|
+
}
|
|
92
|
+
if matching_file_path
|
|
93
|
+
row["file_path"] = matching_file_path
|
|
94
|
+
end
|
|
95
|
+
end
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
def file_paths
|
|
99
|
+
@file_paths ||= @table.column("file_path").uniq
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
def file_tables
|
|
103
|
+
@file_tables ||= make_table_hash(@columns)
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
def class_tables
|
|
107
|
+
@class_tables ||= make_table_hash(@columns)
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
def method_tables
|
|
111
|
+
@method_tables ||= make_table_hash(@columns)
|
|
112
|
+
end
|
|
113
|
+
end
|
|
114
|
+
end
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
%w(table).each do |path|
|
|
2
|
+
MetricFu.metrics_require { "hotspots/analysis/#{path}" }
|
|
3
|
+
end
|
|
4
|
+
module MetricFu
|
|
5
|
+
class Grouping
|
|
6
|
+
def initialize(table, opts)
|
|
7
|
+
column_name = opts.fetch(:by)
|
|
8
|
+
hash = {}
|
|
9
|
+
if column_name.to_sym == :metric # special optimized case
|
|
10
|
+
hash = table.group_by_metric
|
|
11
|
+
else
|
|
12
|
+
raise "Unexpected column_name #{column_name}"
|
|
13
|
+
end
|
|
14
|
+
@arr = hash.to_a
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def each
|
|
18
|
+
@arr.each do |value, rows|
|
|
19
|
+
yield value, rows
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
MetricFu.metrics_require { "hotspots/analysis/groupings" }
|
|
2
|
+
module MetricFu
|
|
3
|
+
class HotspotProblems
|
|
4
|
+
def initialize(sub_table)
|
|
5
|
+
@grouping = group_by(sub_table, "metric")
|
|
6
|
+
end
|
|
7
|
+
|
|
8
|
+
def problems
|
|
9
|
+
problems = {}
|
|
10
|
+
@grouping.each do |metric, table|
|
|
11
|
+
problems[metric] = MetricFu::Hotspot.analyzer_for_metric(metric).present_group(table)
|
|
12
|
+
end
|
|
13
|
+
problems
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def group_by(sub_table, by = "metric")
|
|
17
|
+
MetricFu::HotspotGroupings.new(sub_table, by: by).get_grouping
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
MetricFu.lib_require { "errors/analysis_error" }
|
|
2
|
+
MetricFu.metrics_require { "hotspots/analysis/problems" }
|
|
3
|
+
module MetricFu
|
|
4
|
+
class HotspotRankedProblemLocation
|
|
5
|
+
MetricFu.data_structures_require { "location" }
|
|
6
|
+
attr_reader :sub_table, :granularity
|
|
7
|
+
def initialize(sub_table, granularity)
|
|
8
|
+
@sub_table = sub_table
|
|
9
|
+
@granularity = granularity
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def to_hash
|
|
13
|
+
{
|
|
14
|
+
"location" => location.to_hash,
|
|
15
|
+
"details" => MetricFu::Utility.stringify_keys(problems),
|
|
16
|
+
}
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
# @todo redo as item,value, options = {}
|
|
20
|
+
# Note that the other option for 'details' is :detailed (this isn't
|
|
21
|
+
# at all clear from this method itself
|
|
22
|
+
def problems
|
|
23
|
+
@problems ||= MetricFu::HotspotProblems.new(sub_table).problems
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def location
|
|
27
|
+
@location ||= case granularity
|
|
28
|
+
when :class then class_location
|
|
29
|
+
when :method then method_location
|
|
30
|
+
when :file then file_location
|
|
31
|
+
else raise ArgumentError, "Item must be :class, :method, or :file"
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def file_path
|
|
36
|
+
first_row.file_path
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def class_name
|
|
40
|
+
first_row.class_name
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def method_name
|
|
44
|
+
first_row.method_name
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def file_location
|
|
48
|
+
MetricFu::Location.get(file_path, nil, nil)
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
def method_location
|
|
52
|
+
MetricFu::Location.get(file_path, class_name, method_name)
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
def class_location
|
|
56
|
+
MetricFu::Location.get(file_path, class_name, nil)
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
def first_row
|
|
60
|
+
assert_sub_table_has_data
|
|
61
|
+
@first_row ||= sub_table[0]
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
def assert_sub_table_has_data
|
|
65
|
+
if (sub_table.length == 0)
|
|
66
|
+
raise MetricFu::AnalysisError, "The #{item} '#{value}' does not have any rows in the analysis table"
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
end
|
|
70
|
+
end
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
require "forwardable"
|
|
2
|
+
module MetricFu
|
|
3
|
+
class Ranking
|
|
4
|
+
extend Forwardable
|
|
5
|
+
|
|
6
|
+
def initialize
|
|
7
|
+
@items_to_score = {}
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def top
|
|
11
|
+
sorted_items
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def percentile(item)
|
|
15
|
+
index = sorted_items.index(item)
|
|
16
|
+
worse_item_count = (length - (index + 1))
|
|
17
|
+
worse_item_count.to_f / length
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def_delegator :@items_to_score, :has_key?, :scored?
|
|
21
|
+
def_delegators :@items_to_score, :[], :[]=, :length, :each, :delete, :fetch
|
|
22
|
+
|
|
23
|
+
private
|
|
24
|
+
|
|
25
|
+
def sorted_items
|
|
26
|
+
@sorted_items ||= @items_to_score.sort_by { |_item, score| -score }.map { |item, _score| item }
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
MetricFu.metrics_require do
|
|
2
|
+
[
|
|
3
|
+
"hotspots/analysis/ranking"
|
|
4
|
+
]
|
|
5
|
+
end
|
|
6
|
+
module MetricFu
|
|
7
|
+
class HotspotRankings
|
|
8
|
+
def initialize(tool_tables)
|
|
9
|
+
@tool_tables = tool_tables
|
|
10
|
+
@file_ranking = MetricFu::Ranking.new
|
|
11
|
+
@class_ranking = MetricFu::Ranking.new
|
|
12
|
+
@method_ranking = MetricFu::Ranking.new
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def calculate_scores(tool_analyzers, granularities)
|
|
16
|
+
tool_analyzers.each do |analyzer|
|
|
17
|
+
calculate_scores_by_granularities(analyzer, granularities)
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def worst_methods
|
|
22
|
+
@method_ranking.delete(nil)
|
|
23
|
+
@method_ranking.top
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def worst_classes
|
|
27
|
+
@class_ranking.delete(nil)
|
|
28
|
+
@class_ranking.top
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def worst_files
|
|
32
|
+
@file_ranking.delete(nil)
|
|
33
|
+
@file_ranking.top
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
private
|
|
37
|
+
|
|
38
|
+
def calculate_scores_by_granularities(analyzer, granularities)
|
|
39
|
+
granularities.each do |granularity|
|
|
40
|
+
calculate_score_for_granularity(analyzer, granularity)
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def calculate_score_for_granularity(analyzer, granularity)
|
|
45
|
+
metric_ranking = calculate_metric_scores(granularity, analyzer)
|
|
46
|
+
|
|
47
|
+
add_to_master_ranking(
|
|
48
|
+
ranking(granularity),
|
|
49
|
+
metric_ranking,
|
|
50
|
+
analyzer
|
|
51
|
+
)
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
# CALCULATES METRIC HOTSPOT SCORES / RANKINGS PER map/reduce in HOTSPOT subclasses
|
|
55
|
+
def calculate_metric_scores(granularity, analyzer)
|
|
56
|
+
metric_ranking = MetricFu::Ranking.new
|
|
57
|
+
metric_violations = @tool_tables[analyzer.name]
|
|
58
|
+
metric_violations.each do |row|
|
|
59
|
+
location = row[granularity]
|
|
60
|
+
metric_ranking[location] ||= []
|
|
61
|
+
metric_ranking[location] << analyzer.map(row)
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
metric_ranking.each do |item, scores|
|
|
65
|
+
metric_ranking[item] = analyzer.reduce(scores)
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
metric_ranking
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
def ranking(column_name)
|
|
72
|
+
case column_name
|
|
73
|
+
when "file_path"
|
|
74
|
+
@file_ranking
|
|
75
|
+
when "class_name"
|
|
76
|
+
@class_ranking
|
|
77
|
+
when "method_name"
|
|
78
|
+
@method_ranking
|
|
79
|
+
else
|
|
80
|
+
raise ArgumentError, "Invalid column name #{column_name}"
|
|
81
|
+
end
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
def add_to_master_ranking(master_ranking, metric_ranking, analyzer)
|
|
85
|
+
metric_ranking.each do |item, _|
|
|
86
|
+
master_ranking[item] ||= 0
|
|
87
|
+
master_ranking[item] += analyzer.score(metric_ranking, item) # scaling? Do we just add in the raw score?
|
|
88
|
+
end
|
|
89
|
+
end
|
|
90
|
+
end
|
|
91
|
+
end
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
module MetricFu
|
|
2
|
+
class Record
|
|
3
|
+
attr_reader :data
|
|
4
|
+
|
|
5
|
+
def initialize(data, _columns)
|
|
6
|
+
@data = data
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
def method_missing(name, *args, &block)
|
|
10
|
+
key = name.to_s
|
|
11
|
+
if key == "fetch"
|
|
12
|
+
@data.send(name, *args, &block)
|
|
13
|
+
elsif @data.has_key?(key)
|
|
14
|
+
@data[key]
|
|
15
|
+
else
|
|
16
|
+
super(name, *args, &block)
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def []=(key, value)
|
|
21
|
+
@data[key] = value
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def [](key)
|
|
25
|
+
@data[key]
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def has_key?(key)
|
|
29
|
+
@data.has_key?(key)
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
end
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
module MetricFu
|
|
2
|
+
module HotspotScoringStrategies
|
|
3
|
+
module_function
|
|
4
|
+
|
|
5
|
+
# per project score percentile
|
|
6
|
+
def percentile(ranking, item)
|
|
7
|
+
ranking.percentile(item)
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
# Use the score you got
|
|
11
|
+
# (ex flog score of 20 is not bad even if it is the top one in project)
|
|
12
|
+
def identity(ranking, item)
|
|
13
|
+
ranking.fetch(item)
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def sum(scores)
|
|
17
|
+
scores.inject(&:+)
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def average(scores)
|
|
21
|
+
sum(scores).to_f / scores.size.to_f
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
%w(record).each do |path|
|
|
2
|
+
MetricFu.metrics_require { "hotspots/analysis/#{path}" }
|
|
3
|
+
end
|
|
4
|
+
|
|
5
|
+
module MetricFu
|
|
6
|
+
class Table
|
|
7
|
+
include Enumerable
|
|
8
|
+
|
|
9
|
+
def initialize(opts = {})
|
|
10
|
+
@rows = []
|
|
11
|
+
@columns = opts.fetch(:column_names)
|
|
12
|
+
|
|
13
|
+
@make_index = opts.fetch(:make_index) { true }
|
|
14
|
+
@metric_index = {}
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def <<(row)
|
|
18
|
+
record = nil
|
|
19
|
+
if row.is_a?(MetricFu::Record)
|
|
20
|
+
record = row
|
|
21
|
+
else
|
|
22
|
+
record = MetricFu::Record.new(row, @columns)
|
|
23
|
+
end
|
|
24
|
+
@rows << record
|
|
25
|
+
updated_key_index(record) if @make_index
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def each
|
|
29
|
+
@rows.each do |row|
|
|
30
|
+
yield row
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def size
|
|
35
|
+
length
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def length
|
|
39
|
+
@rows.length
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def [](index)
|
|
43
|
+
@rows[index]
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def column(column_name)
|
|
47
|
+
arr = []
|
|
48
|
+
@rows.each do |row|
|
|
49
|
+
arr << row[column_name]
|
|
50
|
+
end
|
|
51
|
+
arr
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
def group_by_metric
|
|
55
|
+
@metric_index.to_a
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
private
|
|
59
|
+
|
|
60
|
+
def updated_key_index(record)
|
|
61
|
+
if record.has_key?("metric")
|
|
62
|
+
@metric_index[record.metric] ||= MetricFu::Table.new(column_names: @columns, make_index: false)
|
|
63
|
+
@metric_index[record.metric] << record
|
|
64
|
+
end
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
end
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
MetricFu.metrics_require { "hotspots/hotspot_analyzer" }
|
|
2
|
+
module MetricFu
|
|
3
|
+
class HotspotsGenerator < Generator
|
|
4
|
+
def self.metric
|
|
5
|
+
:hotspots
|
|
6
|
+
end
|
|
7
|
+
|
|
8
|
+
def initialize(options = {})
|
|
9
|
+
MetricFu::Metric.enabled_metrics.each do |metric|
|
|
10
|
+
require_hotspot(metric.name)
|
|
11
|
+
end
|
|
12
|
+
super
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def emit
|
|
16
|
+
# no-op
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def analyze
|
|
20
|
+
analyzer = MetricFu::HotspotAnalyzer.new(MetricFu.result.result_hash)
|
|
21
|
+
@hotspots = analyzer.hotspots
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def to_h
|
|
25
|
+
result = { hotspots: {} }
|
|
26
|
+
@hotspots.each do |granularity, hotspots|
|
|
27
|
+
result[:hotspots][granularity.to_s] = hotspots.map(&:to_hash)
|
|
28
|
+
end
|
|
29
|
+
result
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
private
|
|
33
|
+
|
|
34
|
+
def require_hotspot(metric_name)
|
|
35
|
+
require "metric_fu/metrics/#{metric_name}/hotspot"
|
|
36
|
+
rescue LoadError
|
|
37
|
+
mf_debug "*** No hotspot for #{metric_name}"
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
end
|