airbrake_tools 0.0.1

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.
data/.travis.yml ADDED
@@ -0,0 +1,4 @@
1
+ rvm:
2
+ - ree
3
+ - 1.9.2
4
+ - 1.9.3
data/Gemfile ADDED
@@ -0,0 +1,8 @@
1
+ source :rubygems
2
+ gemspec
3
+
4
+ gem "bump"
5
+ gem "rake"
6
+ gem "rspec", "~>2"
7
+ gem "airbrake-api", ">= 4.2.2"
8
+
data/Gemfile.lock ADDED
@@ -0,0 +1,44 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ airbrake_tools (0.0.1)
5
+
6
+ GEM
7
+ remote: http://rubygems.org/
8
+ specs:
9
+ airbrake-api (4.2.2)
10
+ faraday_middleware (~> 0.8)
11
+ hashie
12
+ mash
13
+ multi_xml
14
+ parallel (~> 0.5.0)
15
+ bump (0.3.5)
16
+ diff-lcs (1.1.3)
17
+ faraday (0.8.4)
18
+ multipart-post (~> 1.1)
19
+ faraday_middleware (0.9.0)
20
+ faraday (>= 0.7.4, < 0.9)
21
+ hashie (1.2.0)
22
+ mash (0.1.1)
23
+ multi_xml (0.5.1)
24
+ multipart-post (1.1.5)
25
+ parallel (0.5.19)
26
+ rake (0.9.2.2)
27
+ rspec (2.11.0)
28
+ rspec-core (~> 2.11.0)
29
+ rspec-expectations (~> 2.11.0)
30
+ rspec-mocks (~> 2.11.0)
31
+ rspec-core (2.11.1)
32
+ rspec-expectations (2.11.3)
33
+ diff-lcs (~> 1.1.3)
34
+ rspec-mocks (2.11.3)
35
+
36
+ PLATFORMS
37
+ ruby
38
+
39
+ DEPENDENCIES
40
+ airbrake-api (>= 4.2.2)
41
+ airbrake_tools!
42
+ bump
43
+ rake
44
+ rspec (~> 2)
data/Rakefile ADDED
@@ -0,0 +1,6 @@
1
+ require "bundler/gem_tasks"
2
+ require "bump/tasks"
3
+
4
+ task :default do
5
+ sh "rspec spec/"
6
+ end
data/Readme.md ADDED
@@ -0,0 +1,18 @@
1
+ Power tools for Airbrake
2
+
3
+ Install
4
+ =======
5
+
6
+ gem install airbrake_tools
7
+
8
+ Usage
9
+ =====
10
+
11
+ CODE EXAMPLE
12
+
13
+ Author
14
+ ======
15
+ [Jonathan Cheatham](http://github.com/jcheatham)<br/>
16
+ coaxis@gmail.com<br/>
17
+ License: MIT<br/>
18
+ [![Build Status](https://travis-ci.org/jcheatham/airbrake_tools.png)](https://travis-ci.org/jcheatham/airbrake_tools)
@@ -0,0 +1,12 @@
1
+ $LOAD_PATH.unshift File.expand_path("../lib", __FILE__)
2
+ name = "airbrake_tools"
3
+ require "#{name}/version"
4
+
5
+ Gem::Specification.new name, AirbrakeTools::VERSION do |s|
6
+ s.summary = "Power tools for Airbrake"
7
+ s.authors = ["Jonathan Cheatham"]
8
+ s.email = "coaxis@gmail.com"
9
+ s.homepage = "http://github.com/jcheatham/#{name}"
10
+ s.files = `git ls-files`.split("\n")
11
+ s.license = "MIT"
12
+ end
@@ -0,0 +1,3 @@
1
+ module AirbrakeTools
2
+ VERSION = "0.0.1"
3
+ end
@@ -0,0 +1,117 @@
1
+ require "airbrake_tools/version"
2
+ require "airbrake-api"
3
+
4
+ module AirbrakeTools
5
+ class << self
6
+ def cli(argv)
7
+ options = extract_options(argv)
8
+
9
+ AirbrakeAPI.account = ARGV[0]
10
+ AirbrakeAPI.auth_token = ARGV[1]
11
+ AirbrakeAPI.secure = true
12
+
13
+ if AirbrakeAPI.account.to_s.empty? || AirbrakeAPI.auth_token.to_s.empty?
14
+ puts "Usage instructions: airbrake-tools --help"
15
+ return 1
16
+ end
17
+
18
+ hot(options) || 0
19
+ end
20
+
21
+ def hot(options)
22
+ puts "Calling hot with #{AirbrakeAPI.account}, #{AirbrakeAPI.auth_token}, #{options.inspect}"
23
+
24
+ pages = 1
25
+
26
+ errors = []
27
+ pages.times do |i|
28
+ errors.concat (AirbrakeAPI.errors(:page => i+1) || []).select{|e| e.rails_env == "production" }
29
+ end
30
+
31
+ errors = Parallel.map(errors, :in_threads => 10) do |error|
32
+ begin
33
+ notices = AirbrakeAPI.notices(error.id, :pages => 1, :raw => true).compact
34
+ print "."
35
+ [error, notices]
36
+ rescue Faraday::Error::ParsingError
37
+ $stderr.puts "Ignoring #{summary(error)}, got 500 from http://#{AirbrakeAPI.account}.airbrake.io/errors/#{error.id}"
38
+ end
39
+ end.compact
40
+
41
+ $stderr.puts
42
+
43
+ errors.sort_by{|e,n| frequency(n) }.reverse.each_with_index do |(error, notices), index|
44
+ puts "##{(index+1).to_s.ljust(2)} #{frequency(notices).to_s.rjust(8)}/hour #{error.notices_count.to_s.rjust(6)}:total #{sparkline(notices, :slots => 60, :interval => 60)}"
45
+ puts " --> id: #{error.id} -- first: #{error.created_at} -- #{error.error_class} -- #{error.error_message}"
46
+ end
47
+
48
+ return 0
49
+ end
50
+
51
+ private
52
+
53
+ def frequency(notices)
54
+ hour = 60 * 60
55
+ sum_of_ages = notices.map { |n| Time.now - n.created_at }.inject(&:+)
56
+ average_age = sum_of_ages / notices.size
57
+ time_to_error = average_age / notices.size
58
+ rate = 1 / time_to_error
59
+ (rate * hour).round(1)
60
+ end
61
+
62
+ def summary(error)
63
+ "id:#{error.id} -- first:#{error.created_at} -- #{error.error_class} -- #{error.error_message}"
64
+ end
65
+
66
+ def extract_options(argv)
67
+ options = {
68
+ }
69
+ OptionParser.new do |opts|
70
+ opts.banner = <<-BANNER.gsub(" "*12, "")
71
+ Get the hotest airbrake errors
72
+
73
+ Usage:
74
+ airbrake-tools subdomain token [options]
75
+ token: go to airbrake -> settings, copy your auth token
76
+
77
+ Options:
78
+ BANNER
79
+ opts.on("-h", "--help", "Show this.") { puts opts; exit }
80
+ opts.on("-v", "--version", "Show Version"){ puts "airbrake-tools #{VERSION}"; exit }
81
+ end.parse!(argv)
82
+ options
83
+ end
84
+
85
+ def run(cmd)
86
+ all = ""
87
+ puts cmd
88
+ IO.popen(cmd) do |pipe|
89
+ while str = pipe.gets
90
+ all << str
91
+ puts str
92
+ end
93
+ end
94
+ [$?.success?, all]
95
+ end
96
+
97
+ def run!(command)
98
+ raise "Command failed #{command}" unless run(command).first
99
+ end
100
+
101
+ def sparkline_data(notices, options)
102
+ last = notices.last.created_at
103
+ now = Time.now
104
+ Array.new(options[:slots]).each_with_index.map do |_, i|
105
+ slot_end = now - (i * options[:interval])
106
+ slot_start = slot_end - 1 * options[:interval]
107
+ next if last > slot_end # do not show empty lines when we actually have no data
108
+ notices.select { |n| n.created_at.between?(slot_start, slot_end) }.size
109
+ end
110
+ end
111
+
112
+ def sparkline(notices, options)
113
+ `#{File.expand_path('../../spark.sh',__FILE__)} #{sparkline_data(notices, options).join(" ")}`.strip
114
+ end
115
+
116
+ end
117
+ end
@@ -0,0 +1,52 @@
1
+ require 'yaml'
2
+
3
+ ROOT = File.expand_path('../../', __FILE__)
4
+
5
+ describe "airbrake-tools" do
6
+ def run(command, options={})
7
+ result = `#{command} 2>&1`
8
+ message = (options[:fail] ? "SUCCESS BUT SHOULD FAIL" : "FAIL")
9
+ raise "[#{message}] #{result} [#{command}]" if $?.success? == !!options[:fail]
10
+ result
11
+ end
12
+
13
+ def airbrake_tools(args, options={})
14
+ run "#{ROOT}/bin/airbrake-tools #{args}", options
15
+ end
16
+
17
+ let(:config) { YAML.load(File.read("spec/fixtures.yml")) }
18
+
19
+ before do
20
+ Dir.chdir ROOT
21
+ end
22
+
23
+ describe "basics" do
24
+ it "shows its usage without arguments" do
25
+ airbrake_tools("", :fail => true).should include("Usage")
26
+ end
27
+
28
+ it "shows its usage with -h" do
29
+ airbrake_tools("-h").should include("Usage")
30
+ end
31
+
32
+ it "shows its usage with --help" do
33
+ airbrake_tools("--help").should include("Usage")
34
+ end
35
+
36
+ it "shows its version with -v" do
37
+ airbrake_tools("-v").should =~ /^airbrake-tools \d+\.\d+\.\d+$/
38
+ end
39
+
40
+ it "shows its version with --version" do
41
+ airbrake_tools("-v").should =~ /^airbrake-tools \d+\.\d+\.\d+$/
42
+ end
43
+ end
44
+
45
+ describe "hot" do
46
+ it "kinda works" do
47
+ output = airbrake_tools("#{config["subdomain"]} #{config["auth_token"]}")
48
+ output.should =~ /#\d+\s+\d+\.\d+\/hour\s+\d+:total/
49
+ end
50
+ end
51
+ end
52
+
@@ -0,0 +1 @@
1
+ require "airbrake_tools"
metadata ADDED
@@ -0,0 +1,55 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: airbrake_tools
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Jonathan Cheatham
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2012-11-07 00:00:00.000000000 Z
13
+ dependencies: []
14
+ description:
15
+ email: coaxis@gmail.com
16
+ executables: []
17
+ extensions: []
18
+ extra_rdoc_files: []
19
+ files:
20
+ - .travis.yml
21
+ - Gemfile
22
+ - Gemfile.lock
23
+ - Rakefile
24
+ - Readme.md
25
+ - airbrake_tools.gemspec
26
+ - lib/airbrake_tools.rb
27
+ - lib/airbrake_tools/version.rb
28
+ - spec/airbrake_tools_spec.rb
29
+ - spec/spec_helper.rb
30
+ homepage: http://github.com/jcheatham/airbrake_tools
31
+ licenses:
32
+ - MIT
33
+ post_install_message:
34
+ rdoc_options: []
35
+ require_paths:
36
+ - lib
37
+ required_ruby_version: !ruby/object:Gem::Requirement
38
+ none: false
39
+ requirements:
40
+ - - ! '>='
41
+ - !ruby/object:Gem::Version
42
+ version: '0'
43
+ required_rubygems_version: !ruby/object:Gem::Requirement
44
+ none: false
45
+ requirements:
46
+ - - ! '>='
47
+ - !ruby/object:Gem::Version
48
+ version: '0'
49
+ requirements: []
50
+ rubyforge_project:
51
+ rubygems_version: 1.8.23
52
+ signing_key:
53
+ specification_version: 3
54
+ summary: Power tools for Airbrake
55
+ test_files: []