Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings
This repository was archived by the owner on Jul 19, 2025. It is now read-only.

Commit c092735

Browse files
committed
Emit parser metrics for HTTP parsed languages
Porting similar logic to https://github.com/codeclimate/codeclimate-structure/pull/289 into duplication.
1 parent 88b02cc commit c092735

File tree

8 files changed

+140
-8
lines changed

8 files changed

+140
-8
lines changed

‎lib/cc/engine/analyzers/analyzer_base.rb‎

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,8 +28,9 @@ class Base
2828

2929
MAJOR_SEVERITY_THRESHOLD = 120 * POINTS_PER_MINUTE
3030

31-
def initialize(engine_config:)
31+
def initialize(engine_config:,parse_metrics:)
3232
@engine_config = engine_config
33+
@parse_metrics = parse_metrics
3334
end
3435

3536
def run(file)
@@ -97,7 +98,7 @@ def use_sexp_lines?
9798

9899
private
99100

100-
attr_reader :engine_config
101+
attr_reader :engine_config,:parse_metrics
101102

102103
def base_points
103104
self.class::BASE_POINTS
@@ -131,6 +132,7 @@ def skip?(_path)
131132

132133
def parse(file, request_path)
133134
processed_source = ProcessedSource.new(file, request_path)
135+
parse_metrics.incr(:succeeded)
134136
SexpBuilder.new(processed_source.ast, file).build
135137
rescue => ex
136138
handle_exception(processed_source, ex)
@@ -144,11 +146,14 @@ def handle_exception(processed_source, ex)
144146
CC.logger.warn("Skipping #{processed_source.path} due to #{ex.class}")
145147
CC.logger.warn("Response status: #{ex.response_status}")
146148
CC.logger.debug { "Response:\n#{ex.response_body}" }
149+
parse_metrics.incr(ex.code.to_sym)
147150
when ex.is_a?(CC::Parser::Client::EncodingError)
148151
CC.logger.warn("Skipping #{processed_source.path} due to #{ex.class}: #{ex.message}")
152+
parse_metrics.incr(:encoding_error)
149153
when ex.is_a?(CC::Parser::Client::NestingDepthError)
150154
CC.logger.warn("Skipping #{processed_source.path} due to #{ex.class}")
151155
CC.logger.warn(ex.message)
156+
parse_metrics.incr(:client_nesting_depth_error)
152157
else
153158
CC.logger.error("Error processing file: #{processed_source.path}")
154159
CC.logger.error(ex.message)

‎lib/cc/engine/duplication.rb‎

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
# frozen_string_literal: true
22

33
require "bundler/setup"
4+
require "cc/engine/parse_metrics"
45
require "cc/engine/analyzers/ruby/main"
56
require "cc/engine/analyzers/java/main"
67
require "cc/engine/analyzers/javascript/main"
@@ -34,9 +35,17 @@ def run
3435

3536
Dir.chdir(directory) do
3637
languages_to_analyze.each do |language|
37-
engine = LANGUAGES[language].new(engine_config: engine_config)
38+
parse_metrics = ParseMetrics.new(
39+
language: language,
40+
io: io,
41+
)
42+
engine = LANGUAGES[language].new(
43+
engine_config: engine_config,
44+
parse_metrics: parse_metrics,
45+
)
3846
reporter = CC::Engine::Analyzers::Reporter.new(engine_config, engine, io)
3947
reporter.run
48+
parse_metrics.report
4049
end
4150
end
4251
end

‎lib/cc/engine/parse_metrics.rb‎

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
module CC
2+
module Engine
3+
class ParseMetrics
4+
def initialize(language:, io:)
5+
@language = language
6+
@io = io
7+
@counts = Hash.new(0)
8+
end
9+
10+
def incr(result_type)
11+
counts[result_type] += 1
12+
end
13+
14+
def report
15+
counts.each do |result_type, count|
16+
doc = metric_doc(result_type, count)
17+
# puts allows a race between content newline, use print
18+
io.print("#{JSON.generate(doc)}0円\n")
19+
end
20+
end
21+
22+
private
23+
24+
attr_reader :counts, :io, :language
25+
26+
def metric_doc(result_type, count)
27+
{
28+
name: "#{language}.parse.#{result_type}",
29+
type: "measurement",
30+
value: count,
31+
}
32+
end
33+
end
34+
end
35+
end

‎spec/cc/engine/analyzers/analyzer_base_spec.rb‎

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,15 @@ class DummyAnalyzer < Base
1515
include AnalyzerSpecHelpers
1616

1717
let(:engine_config) { EngineConfig.new({}) }
18-
let(:analyzer) { DummyAnalyzer.new(engine_config: engine_config) }
18+
let(:analyzer) do
19+
DummyAnalyzer.new(
20+
engine_config: engine_config,
21+
parse_metrics: CC::Engine::ParseMetrics.new(
22+
language: "dummy",
23+
io: StringIO.new,
24+
),
25+
)
26+
end
1927

2028
before(:each) do
2129
create_source_file("foo.a", "")

‎spec/cc/engine/analyzers/ruby/main_spec.rb‎

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
require 'spec_helper'
2-
require 'cc/engine/analyzers/ruby/main'
32
require 'cc/engine/analyzers/engine_config'
3+
require 'cc/engine/analyzers/ruby/main'
4+
require 'cc/engine/parse_metrics'
45

56
module CC::Engine::Analyzers
67
RSpec.describe Ruby::Main, in_tmpdir: true do
@@ -228,7 +229,7 @@ def identical
228229
end
229230

230231
describe "#calculate_points" do
231-
let(:analyzer) { Ruby::Main.new(engine_config: engine_conf) }
232+
let(:analyzer) { new_analyzer }
232233
let(:base_points) { Ruby::Main::BASE_POINTS }
233234
let(:points_per) { Ruby::Main::POINTS_PER_OVERAGE }
234235
let(:threshold) { Ruby::Main::DEFAULT_MASS_THRESHOLD }
@@ -274,7 +275,7 @@ def identical
274275
end
275276

276277
describe "#calculate_severity(points)" do
277-
let(:analyzer) { Ruby::Main.new(engine_config: engine_conf) }
278+
let(:analyzer) { new_analyzer }
278279
let(:base_points) { Ruby::Main::BASE_POINTS }
279280
let(:points_per) { Ruby::Main::POINTS_PER_OVERAGE }
280281
let(:threshold) { Ruby::Main::DEFAULT_MASS_THRESHOLD }
@@ -307,6 +308,16 @@ def identical
307308
end
308309
end
309310

311+
def new_analyzer
312+
Ruby::Main.new(
313+
engine_config: engine_conf,
314+
parse_metrics: CC::Engine::ParseMetrics.new(
315+
language: "ruby",
316+
io: StringIO.new,
317+
),
318+
)
319+
end
320+
310321
def engine_conf
311322
EngineConfig.new({})
312323
end

‎spec/cc/engine/duplication_spec.rb‎

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22
require "cc/engine/duplication"
33

44
RSpec.describe(CC::Engine::Duplication) do
5+
include AnalyzerSpecHelpers
6+
57
describe "#run" do
68
it "skips analysis when all duplication checks are disabled" do
79
dir = "foo"
@@ -24,5 +26,25 @@
2426
directory: dir, engine_config: config, io: double,
2527
).run
2628
end
29+
30+
it "emits parse metrics for HTTP parsed languages", in_tmpdir: true do
31+
create_source_file("foo.js", <<-EOJS)
32+
console.log("hello JS!");
33+
EOJS
34+
35+
stdout = StringIO.new
36+
37+
CC::Engine::Duplication.new(
38+
directory: @code, engine_config: {}, io: stdout,
39+
).run
40+
41+
expect(stdout.string).not_to be_empty
42+
measurement = JSON.parse(stdout.string.strip)
43+
expect(measurement).to eq(
44+
"name" => "javascript.parse.succeeded",
45+
"type" => "measurement",
46+
"value" => 1,
47+
)
48+
end
2749
end
2850
end

‎spec/cc/engine/parse_metrics_spec.rb‎

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
require "spec_helper"
2+
3+
require "cc/engine/parse_metrics"
4+
5+
RSpec.describe CC::Engine::ParseMetrics do
6+
it "sends issues to stdout" do
7+
stdout = StringIO.new
8+
metrics = CC::Engine::ParseMetrics.new(
9+
language: "intercal",
10+
io: stdout,
11+
)
12+
13+
metrics.incr(:source_minified)
14+
metrics.incr(:parse_error)
15+
metrics.incr(:source_minified)
16+
17+
metrics.report
18+
19+
out_pieces = stdout.string.split("0円\n").map(&:strip)
20+
expect(out_pieces.count).to eq(2)
21+
22+
expect(JSON.parse(out_pieces[0])).to eq({
23+
"name" => "intercal.parse.source_minified",
24+
"type" => "measurement",
25+
"value" => 2,
26+
})
27+
28+
expect(JSON.parse(out_pieces[1])).to eq({
29+
"name" => "intercal.parse.parse_error",
30+
"type" => "measurement",
31+
"value" => 1,
32+
})
33+
end
34+
end

‎spec/support/helpers/analyzer_spec_helpers.rb‎

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
require 'cc/engine/parse_metrics'
2+
13
module AnalyzerSpecHelpers
24
def create_source_file(path, content)
35
raise "Must use in_tmpdir tag" unless @code
@@ -11,7 +13,13 @@ def fixture_path(fixture_name)
1113
def run_engine(config = nil)
1214
io = StringIO.new
1315

14-
engine = described_class.new(engine_config: config)
16+
engine = described_class.new(
17+
engine_config: config,
18+
parse_metrics: CC::Engine::ParseMetrics.new(
19+
language: described_class::LANGUAGE,
20+
io: StringIO.new,
21+
),
22+
)
1523
reporter = ::CC::Engine::Analyzers::Reporter.new(config, engine, io)
1624

1725
reporter.run

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /