airbrake_symbolicate 0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2010 Brett Gibson
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,23 @@
1
+ = airbrake_symbolicate
2
+
3
+ lib and cli tool to download airbrake iOS crash reports via the api and symbolicate them
4
+
5
+ The idea is:
6
+ * Find all the XCode Archive files via spotlight
7
+ * Pull the GCGitCommitHash (or failing that CFBundleVersion) out of the Info.plist for each binary and map that to a dSYM file
8
+ * Given an ActiveResource Error object from the Airbrake API match it up to a dSYM file and try to symbolicate the stack trace
9
+
10
+
11
+ So far, I've only tried it out so far on ruby 1.9.2
12
+
13
+ == Basic Usage
14
+
15
+ Install the gem:
16
+ gem install airbrake_symbolicate
17
+
18
+ Run the cli:
19
+ airbrake_symbolicate airbrake_account_name airbrake_api_auth_token
20
+ Where the account name is your subdomain on airbrake (as in http://airbrake_account_name.airbrakeapp.com) and the API key is the one available on the Airbrake account admin's user page (NOT the reporting API key for the project).
21
+ This should spit out all the errors available via the API and the symbolicated backtrace if an appropriate dSYM is found. There's not much error handling.
22
+
23
+ See bin/airbrake_symbolicate for general usage from ruby.
@@ -0,0 +1,2 @@
1
+ require 'bundler'
2
+ Bundler::GemHelper.install_tasks
@@ -0,0 +1,55 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'colored'
4
+
5
+ if File.exists?(File.join(File.expand_path('../..', __FILE__), '.git'))
6
+ $:.unshift(File.expand_path('../../lib', __FILE__))
7
+ end
8
+ require "airbrake_symbolicate"
9
+
10
+ include AirbrakeSymbolicate
11
+
12
+ Airbrake.account = ENV['AIRBRAKE_ACCOUNT'] || ARGV[0]
13
+ Airbrake.auth_token = ENV['AIRBRAKE_AUTH_TOKEN'] || ARGV[1]
14
+
15
+ unless Airbrake.site && Airbrake.auth_token
16
+ puts "\tUsage: airbrake_symbolicate airbrake_account airbrake_auth_token"
17
+ puts "\tOr set AIRBRAKE_ACCOUNT and AIRBRAKE_AUTH_TOKEN environment variables."
18
+ puts
19
+ puts "\tAirbrake account and auth token must be specfied!"
20
+ puts "\texiting..."
21
+ exit
22
+ end
23
+
24
+ DIVIDER = "*" * 40
25
+ META_FORMAT = "%20s: %s"
26
+
27
+ page = 1
28
+ begin
29
+ errors = Error.find(:all, :params => {:page => page})
30
+ errors.each do |e|
31
+ e.reload
32
+
33
+ puts DIVIDER
34
+ puts META_FORMAT % ['message', e.error_message]
35
+ puts META_FORMAT % ['notices count', e.notices_count]
36
+ puts META_FORMAT % ['operating system', e.environment.operating_system]
37
+ puts META_FORMAT % ['app version', e.environment.app_version]
38
+ puts META_FORMAT % ['url', Error.site + Error.element_path(e.id).sub(/\.xml$/, '')]
39
+
40
+ if bt = Symbolicator.symbolicated_backtrace(e)
41
+ puts "Backtrace:"
42
+ bt.each do |l|
43
+ if STDOUT.tty?
44
+ # symbolicated lines start with [
45
+ puts l.send(l[/^\[/] ? :red : :green)
46
+ else
47
+ puts l
48
+ end
49
+ end
50
+ else
51
+ puts "\tNo dSYM found"
52
+ end
53
+ end
54
+ page += 1
55
+ end until errors.empty?
@@ -0,0 +1,92 @@
1
+ require 'active_resource'
2
+ module AirbrakeSymbolicate
3
+ class DsymFinder
4
+ @@dsyms = nil
5
+
6
+ class << self
7
+ def dsym_for_error(error)
8
+ find_dsyms unless @@dsyms
9
+
10
+ @@dsyms[error.environment.git_commit] || @@dsyms[error.environment.app_version]
11
+ end
12
+
13
+ private
14
+
15
+ # use spotlight to find all the xcode archives
16
+ # then use the Info.plist inside those archives to try and look up a git commit hash
17
+ def find_dsyms
18
+ @@dsyms = {}
19
+
20
+ files = `mdfind 'kMDItemKind = "Xcode Archive"'`.split("\n")
21
+ files.each do |f|
22
+ # puts `ls '#{f.chomp}'`
23
+ info = `find '#{f}/Products' -name Info.plist`.chomp
24
+
25
+ if commit = plist_val(info, 'GCGitCommitHash')
26
+ if bin_file = Dir[File.join(f, '/dSYMs/*.dSYM/**/DWARF/*')].first
27
+ @@dsyms[commit] = bin_file
28
+ end
29
+ else
30
+ short_version = plist_val(info, 'CFBundleShortVersionString')
31
+ long_version = plist_val(info, 'CFBundleVersion')
32
+ # this is the format in HTApplicationVersion() in hoptoad-ios
33
+ @@dsyms["#{CFBundleShortVersionString} (#{CFBundleVersion})"] = bin_file
34
+ end
35
+ end
36
+ end
37
+
38
+ def plist_val(plist, key)
39
+ `/usr/libexec/PlistBuddy -c 'Print :#{key}' '#{plist}' 2>/dev/null`.chomp
40
+ end
41
+ end
42
+ end
43
+
44
+ class Symbolicator
45
+ class << self
46
+ def symbolicated_backtrace(error)
47
+ if dsym = DsymFinder.dsym_for_error(error)
48
+ error.backtrace.line.map {|l| Symbolicator.symbolicate_line(dsym, l)}
49
+ end
50
+ end
51
+
52
+ def symbolicate_line(dsym_file, line)
53
+ binname = File.basename(dsym_file)
54
+ if line[/#{binname}/] && loc = line[/0x\w+/]
55
+ `/usr/bin/atos -arch armv7 -o "#{dsym_file}" #{loc}`.sub(/^[-_]+/, '')
56
+ else
57
+ line
58
+ end.chomp
59
+ end
60
+ end
61
+ end
62
+
63
+ class Airbrake < ActiveResource::Base
64
+ cattr_accessor :auth_token
65
+
66
+ class << self
67
+ def account=(a)
68
+ self.site = "http://#{a}.airbrakeapp.com/" if a
69
+ end
70
+
71
+ def find(*arguments)
72
+ arguments = append_auth_token_to_params(*arguments)
73
+ super(*arguments)
74
+ end
75
+
76
+ def append_auth_token_to_params(*arguments)
77
+ raise RuntimeError.new("Airbrake.auth_token must be set!") if !auth_token
78
+
79
+ opts = arguments.last.is_a?(Hash) ? arguments.pop : {}
80
+ opts = opts.has_key?(:params) ? opts : opts.merge(:params => {})
81
+ opts[:params] = opts[:params].merge(:auth_token => auth_token)
82
+ arguments << opts
83
+ arguments
84
+ end
85
+ end
86
+
87
+ end
88
+
89
+ class Error < Airbrake
90
+ end
91
+
92
+ end
metadata ADDED
@@ -0,0 +1,108 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: airbrake_symbolicate
3
+ version: !ruby/object:Gem::Version
4
+ prerelease: false
5
+ segments:
6
+ - 0
7
+ - 1
8
+ version: "0.1"
9
+ platform: ruby
10
+ authors:
11
+ - Brett Gibson
12
+ autorequire:
13
+ bindir: bin
14
+ cert_chain: []
15
+
16
+ date: 2011-08-03 00:00:00 -07:00
17
+ default_executable:
18
+ dependencies:
19
+ - !ruby/object:Gem::Dependency
20
+ name: activeresource
21
+ prerelease: false
22
+ requirement: &id001 !ruby/object:Gem::Requirement
23
+ none: false
24
+ requirements:
25
+ - - ">="
26
+ - !ruby/object:Gem::Version
27
+ segments:
28
+ - 3
29
+ - 0
30
+ version: "3.0"
31
+ type: :runtime
32
+ version_requirements: *id001
33
+ - !ruby/object:Gem::Dependency
34
+ name: colored
35
+ prerelease: false
36
+ requirement: &id002 !ruby/object:Gem::Requirement
37
+ none: false
38
+ requirements:
39
+ - - ">="
40
+ - !ruby/object:Gem::Version
41
+ segments:
42
+ - 1
43
+ - 2
44
+ version: "1.2"
45
+ type: :runtime
46
+ version_requirements: *id002
47
+ - !ruby/object:Gem::Dependency
48
+ name: bundler
49
+ prerelease: false
50
+ requirement: &id003 !ruby/object:Gem::Requirement
51
+ none: false
52
+ requirements:
53
+ - - ">="
54
+ - !ruby/object:Gem::Version
55
+ segments:
56
+ - 0
57
+ version: "0"
58
+ type: :development
59
+ version_requirements: *id003
60
+ description: lib and cli tool to download airbrake iOS crash reports via the api and symbolicate them
61
+ email:
62
+ - brettdgibson@gmail.com
63
+ executables:
64
+ - airbrake_symbolicate
65
+ extensions: []
66
+
67
+ extra_rdoc_files: []
68
+
69
+ files:
70
+ - bin/airbrake_symbolicate
71
+ - lib/airbrake_symbolicate.rb
72
+ - LICENSE.txt
73
+ - README.rdoc
74
+ - Rakefile
75
+ has_rdoc: true
76
+ homepage: ""
77
+ licenses:
78
+ - MIT
79
+ post_install_message:
80
+ rdoc_options: []
81
+
82
+ require_paths:
83
+ - lib
84
+ required_ruby_version: !ruby/object:Gem::Requirement
85
+ none: false
86
+ requirements:
87
+ - - ">="
88
+ - !ruby/object:Gem::Version
89
+ segments:
90
+ - 0
91
+ version: "0"
92
+ required_rubygems_version: !ruby/object:Gem::Requirement
93
+ none: false
94
+ requirements:
95
+ - - ">="
96
+ - !ruby/object:Gem::Version
97
+ segments:
98
+ - 0
99
+ version: "0"
100
+ requirements: []
101
+
102
+ rubyforge_project:
103
+ rubygems_version: 1.3.7
104
+ signing_key:
105
+ specification_version: 3
106
+ summary: symbolicate airbrake iOS crash reports
107
+ test_files: []
108
+