diff --git a/app/interactors/notice_refingerprinter.rb b/app/interactors/notice_refingerprinter.rb index bf2652b..f966b95 100644 --- a/app/interactors/notice_refingerprinter.rb +++ b/app/interactors/notice_refingerprinter.rb @@ -15,19 +15,21 @@ class NoticeRefingerprinter end puts 'Finished generating notice fingerprints' - end + puts 'Destroying orphaned err records' + + Err.each { |e| e.destroy if e.notices.size == 0 } - def self.apps - @apps ||= App.all.index_by(&:id) + puts 'Finished destroying orphaned err records' end def self.refingerprint(notice) - app = apps[notice.try(:err).try(:problem).try(:app_id)] - app.find_or_create_err!( + app = notice.app + notice.err = app.find_or_create_err!( error_class: notice.error_class, environment: notice.environment_name, fingerprint: app.notice_fingerprinter.generate(app.api_key, notice, notice.backtrace) ) + notice.save! end def self.puts(*args) diff --git a/app/models/app.rb b/app/models/app.rb index dbc1463..186f796 100644 --- a/app/models/app.rb +++ b/app/models/app.rb @@ -65,16 +65,15 @@ class App # * :fingerprint - a unique value identifying the notice # def find_or_create_err!(attrs) - Err.where( - :fingerprint => attrs[:fingerprint] - ).first || ( - problem = problems.create!( - error_class: attrs[:error_class], - environment: attrs[:environment], - app_name: name - ) - problem.errs.create!(attrs.slice(:fingerprint, :problem_id)) + err = Err.where(fingerprint: attrs[:fingerprint]).first + return err if err + + problem = problems.create!( + error_class: attrs[:error_class], + environment: attrs[:environment], + app_name: name ) + problem.errs.create!(attrs.slice(:fingerprint, :problem_id)) end # Mongoid Bug: find(id) on association proxies returns an Enumerator diff --git a/app/models/notice.rb b/app/models/notice.rb index 889369b..5fa5b0a 100644 --- a/app/models/notice.rb +++ b/app/models/notice.rb @@ -29,9 +29,7 @@ class Notice scope :ordered, ->{ order_by(:created_at.asc) } scope :reverse_ordered, ->{ order_by(:created_at.desc) } scope :for_errs, Proc.new { |errs| - if (ids = errs.all.map(&:id)) && ids.present? - where(:err_id.in => ids) - end + where(:err_id.in => errs.all.map(&:id)) } def user_agent diff --git a/app/models/notice_fingerprinter.rb b/app/models/notice_fingerprinter.rb index f3aa115..0bdc7c9 100644 --- a/app/models/notice_fingerprinter.rb +++ b/app/models/notice_fingerprinter.rb @@ -14,7 +14,7 @@ class NoticeFingerprinter embedded_in :site_config def generate(api_key, notice, backtrace) - material = [] + material = [ api_key ] material << notice.error_class if error_class material << notice.filtered_message if message material << notice.component if component diff --git a/spec/fabricators/backtrace_fabricator.rb b/spec/fabricators/backtrace_fabricator.rb index dc9e3bb..62b51cb 100644 --- a/spec/fabricators/backtrace_fabricator.rb +++ b/spec/fabricators/backtrace_fabricator.rb @@ -7,13 +7,3 @@ Fabricator :backtrace do } end end - -Fabricator :short_backtrace do - lines(:count => 5) do - { - number: rand(999), - file: "/path/to/file/#{SecureRandom.hex(4)}.rb", - method: ActiveSupport.methods.shuffle.first - } - end -end diff --git a/spec/fabricators/notice_fabricator.rb b/spec/fabricators/notice_fabricator.rb index 90e79c7..d7f2bf0 100644 --- a/spec/fabricators/notice_fabricator.rb +++ b/spec/fabricators/notice_fabricator.rb @@ -1,4 +1,5 @@ Fabricator :notice do + app err error_class 'FooError' message 'Too Much Bar' diff --git a/spec/interactors/notice_refingerprinter_spec.rb b/spec/interactors/notice_refingerprinter_spec.rb index 22c8d7c..afbec40 100644 --- a/spec/interactors/notice_refingerprinter_spec.rb +++ b/spec/interactors/notice_refingerprinter_spec.rb @@ -1,16 +1,52 @@ describe NoticeRefingerprinter do + let(:app) { Fabricate(:app) } let(:backtrace) do Fabricate(:backtrace) end - let(:notices) do - 5.times.map do - Fabricate(:notice, backtrace: backtrace) + before do + notices + end + + context 'identical backtraces' do + let(:notices) do + 5.times.map do + notice = Fabricate(:notice, backtrace: backtrace, app: app) + notice.save! + notice + end + end + + it 'has only one err' do + described_class.run + expect(Err.count).to eq(1) end end - it 'shits' do - binding.pry - 1 + context 'minor backtrace differences' do + let(:notices) do + line_numbers = [1, 1, 2, 2, 3] + 5.times.map do + b = backtrace.clone + b.lines[5][:number] = line_numbers.shift + b.save! + notice = Fabricate(:notice, backtrace: b, app: app) + notice.save! + end + end + + it 'has three errs with default fingerprinter' do + described_class.run + expect(Err.count).to eq(3) + end + + it 'has one err when limiting backtrace line count' do + fingerprinter = app.notice_fingerprinter + fingerprinter.backtrace_lines = 4 + fingerprinter.save! + + described_class.run + expect(Err.count).to eq(1) + end end end diff --git a/spec/interactors/problem_recacher_spec.rb b/spec/interactors/problem_recacher_spec.rb new file mode 100644 index 0000000..8c364fc --- /dev/null +++ b/spec/interactors/problem_recacher_spec.rb @@ -0,0 +1,38 @@ +describe ProblemRecacher do + let(:app) { Fabricate(:app) } + let(:backtrace) do + Fabricate(:backtrace) + end + + before do + notices + + NoticeRefingerprinter.run + described_class.run + end + + context 'minor backtrace differences' do + let(:notices) do + line_numbers = [1, 1, 2, 2, 3] + 5.times.map do + b = backtrace.clone + b.lines[5][:number] = line_numbers.shift + b.save! + notice = Fabricate(:notice, backtrace: b, app: app) + notice.save! + notice + end + end + + it 'has three problems for the five notices' do + expect(Notice.count).to eq(5) + expect(Problem.count).to eq(3) + end + + it 'the problems have the right cached attributes' do + problem = notices.first.reload.problem + + expect(problem.notices_count).to eq(2) + end + end +end -- libgit2 0.21.2