failtale-reporter 0.2.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.
data/LICENSE ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2009 Mr.Henry
2
+
3
+ Permission is hereby granted, free of charge, to any person
4
+ obtaining a copy of this software and associated documentation
5
+ files (the "Software"), to deal in the Software without
6
+ restriction, including without limitation the rights to use,
7
+ copy, modify, merge, publish, distribute, sublicense, and/or sell
8
+ copies of the Software, and to permit persons to whom the
9
+ Software is furnished to do so, subject to the following
10
+ conditions:
11
+
12
+ The above copyright notice and this permission notice shall be
13
+ included in all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
17
+ OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
19
+ HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
20
+ WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21
+ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
22
+ OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1 @@
1
+ # Failtale Reporter
@@ -0,0 +1 @@
1
+ require File.expand_path('../failtale_reporter', __FILE__)
@@ -0,0 +1,60 @@
1
+ module FailtaleReporter
2
+
3
+ require 'digest/sha1'
4
+ require 'httparty'
5
+
6
+ require 'failtale_reporter/version'
7
+ require 'failtale_reporter/error'
8
+ require 'failtale_reporter/client'
9
+ require 'failtale_reporter/configuration'
10
+ require 'failtale_reporter/backtrace_cleaner'
11
+ require 'failtale_reporter/information_collector'
12
+ require 'failtale_reporter/adapters'
13
+
14
+
15
+ include HTTParty
16
+ extend FailtaleReporter::Adapters
17
+ extend FailtaleReporter::Configuration
18
+ extend FailtaleReporter::BacktraceCleaner
19
+ extend FailtaleReporter::InformationCollector
20
+
21
+ base_uri 'failtale.be'
22
+ format :xml
23
+
24
+ default_reporter 'ruby'
25
+
26
+ backtrace_cleaner do |line|
27
+ if FailtaleReporter.application_root
28
+ line.sub! FailtaleReporter.application_root, "[APP]"
29
+ end
30
+ end
31
+
32
+ if defined?(Gem)
33
+ class << self
34
+ def gem_backtrace_cleaner(spec)
35
+ @gem_backtrace_cleaner ||= {}
36
+ unless @gem_backtrace_cleaner[spec.full_name]
37
+ @gem_backtrace_cleaner[spec.full_name] = {
38
+ :regexp => backtrace_cleaner_regexp(spec.full_gem_path),
39
+ :label => "[GEM: #{spec.name} @#{spec.version.to_s}]"
40
+ }
41
+ end
42
+ @gem_backtrace_cleaner[spec.full_name]
43
+ end
44
+ end
45
+ backtrace_cleaner do |line|
46
+ cleaned_line = nil
47
+ Gem.loaded_specs.values.each do |spec|
48
+ options = FailtaleReporter.gem_backtrace_cleaner(spec)
49
+ cleaned_line = line.sub!(options[:regexp], options[:label])
50
+ break if cleaned_line
51
+ end
52
+ cleaned_line
53
+ end
54
+ end
55
+
56
+ def self.report(error=nil, *ctxs, &block)
57
+ Client.new.report(error, *ctxs, &block)
58
+ end
59
+
60
+ end
@@ -0,0 +1,7 @@
1
+ module FailtaleReporter::Adapters
2
+
3
+ def self.load_adapter(name)
4
+ require "failtale_reporter/adapters/#{name}"
5
+ end
6
+
7
+ end
@@ -0,0 +1,51 @@
1
+
2
+ module FailtaleReporter
3
+ module Adapters
4
+
5
+ module Rails
6
+
7
+ IGNORED_EXCEPTIONS = ['ActiveRecord::RecordNotFound',
8
+ 'ActionController::RoutingError',
9
+ 'ActionController::InvalidAuthenticityToken',
10
+ 'CGI::Session::CookieStore::TamperedWithCookie']
11
+
12
+ IGNORED_EXCEPTIONS.map!{|e| eval(e) rescue nil }.compact!
13
+ IGNORED_EXCEPTIONS.freeze
14
+
15
+ def self.included(target)
16
+ target.send :alias_method_chain, :rescue_action_in_public, :failtale
17
+
18
+ FailtaleReporter.configure do |config|
19
+ config.ignored_exceptions IGNORED_EXCEPTIONS
20
+ config.default_reporter "rails"
21
+ config.application_root RAILS_ROOT
22
+ config.information_collector do |error, controller|
23
+ env = error.environment
24
+ env = env.merge(controller.request.env)
25
+
26
+ env.delete('action_controller.rescue.response')
27
+ env.delete('action_controller.rescue.request')
28
+ error.environment = env
29
+ end
30
+ end
31
+ end
32
+
33
+ def rescue_action_in_public_with_failtale(exception)
34
+ FailtaleReporter.report(exception, self) unless is_private?
35
+ rescue_action_in_public_without_failtale(exception)
36
+ end
37
+
38
+ protected
39
+
40
+ def is_private? #nodoc:
41
+ if defined?(RAILS_ENV)
42
+ ['development', 'test'].include?(RAILS_ENV)
43
+ end
44
+ end
45
+
46
+ end
47
+
48
+ end
49
+ end
50
+
51
+ ::ActionController::Base.send :include, FailtaleReporter::Adapters::Rails
@@ -0,0 +1,32 @@
1
+ module FailtaleReporter::BacktraceCleaner
2
+
3
+ def clean_backtrace(backtrace)
4
+ backtrace.collect do |line|
5
+ path = File.expand_path(line.split(':').first)
6
+ if File.exist?(path)
7
+ line = File.expand_path(line)
8
+ cleaned_line = nil
9
+ backtrace_cleaners.each do |proc|
10
+ cleaned_line = proc.call(line)
11
+ break if cleaned_line
12
+ end
13
+ cleaned_line || line
14
+ else
15
+ line
16
+ end
17
+ end
18
+ end
19
+
20
+ def backtrace_cleaners
21
+ @backtrace_cleaners ||= []
22
+ end
23
+
24
+ def backtrace_cleaner(&block)
25
+ backtrace_cleaners.push(block)
26
+ end
27
+
28
+ def backtrace_cleaner_regexp(path)
29
+ Regexp.new("^#{Regexp.escape(File.expand_path(path))}")
30
+ end
31
+
32
+ end
@@ -0,0 +1,30 @@
1
+ class FailtaleReporter::Client
2
+
3
+ def report(error=nil, *ctxs)
4
+ error = handle_exception(error, ctxs)
5
+ yield if block_given? and error.nil?
6
+ rescue Exception => exception
7
+ error = handle_exception(exception, ctxs)
8
+ ensure
9
+ post_report(error) unless error.nil?
10
+ raise exception unless exception.nil?
11
+ end
12
+
13
+ private
14
+
15
+ def handle_exception(exception, ctxs)
16
+ return exception if exception.is_a? FailtaleReporter::Error
17
+ return nil if exception.nil?
18
+ return nil unless FailtaleReporter.reportable_exceptions.any? {|c| exception.is_a? c }
19
+ return nil if FailtaleReporter.ignored_exceptions.any? {|c| exception.is_a? c }
20
+ FailtaleReporter::Error.new(exception, ctxs)
21
+ rescue Exception => e
22
+ puts "#{e.class}: #{e.message}"
23
+ puts e.backtrace
24
+ end
25
+
26
+ def post_report(error)
27
+ response = FailtaleReporter.post('/reports.xml', :body => error.to_param)
28
+ end
29
+
30
+ end
@@ -0,0 +1,30 @@
1
+ module FailtaleReporter::Configuration
2
+
3
+ def reportable_exceptions(*arr)
4
+ arr = [Exception] if (arr || []).empty?
5
+ @reportable_exceptions ||= arr.flatten
6
+ end
7
+
8
+ def ignored_exceptions(*arr)
9
+ @ignored_exceptions ||= arr.flatten
10
+ end
11
+
12
+ def api_token(token=nil)
13
+ @api_token ||= token
14
+ end
15
+
16
+ def default_reporter(reporter=nil)
17
+ @default_reporter = reporter if reporter
18
+ @default_reporter
19
+ end
20
+
21
+ def application_root(path=nil)
22
+ @application_root = backtrace_cleaner_regexp(path) if path
23
+ @application_root
24
+ end
25
+
26
+ def configure
27
+ yield self
28
+ end
29
+
30
+ end
@@ -0,0 +1,50 @@
1
+ class FailtaleReporter::Error
2
+
3
+ attr_accessor :api_token
4
+ attr_accessor :hash_string
5
+ attr_accessor :name
6
+ attr_accessor :reporter
7
+ attr_accessor :description
8
+ attr_accessor :properties
9
+ attr_accessor :backtrace
10
+ attr_accessor :environment
11
+
12
+ def initialize(exception, ctxs=[])
13
+ self.api_token = FailtaleReporter.api_token
14
+ self.reporter = FailtaleReporter.default_reporter
15
+
16
+ self.name = "#{exception.class} #{exception.message}"
17
+ self.description = exception.message
18
+ self.backtrace = FailtaleReporter.clean_backtrace(exception.backtrace).join("\n")
19
+ self.environment = ENV.to_hash
20
+ self.hash_string = Digest::SHA1.hexdigest(
21
+ [exception.class, exception.backtrace.first].join('--')
22
+ )
23
+ FailtaleReporter.collect_information(self, ctxs)
24
+
25
+ self.backtrace = self.backtrace.inspect unless self.backtrace.is_a? String
26
+ self.environment = self.environment.inject({}) do |m,(k,v)|
27
+ k = k.inspect unless k.is_a? String
28
+ v = v.inspect unless v.is_a? String
29
+ m[k] = v
30
+ m
31
+ end
32
+ end
33
+
34
+ def to_param
35
+ { :report =>
36
+ { :project => {
37
+ :api_token => self.api_token
38
+ },:error => {
39
+ :hash_string => self.hash_string
40
+ },:occurence => {
41
+ :name => self.name,
42
+ :reporter => self.reporter,
43
+ :description => self.description,
44
+ :backtrace => self.backtrace,
45
+ :properties => self.environment
46
+ } }
47
+ }
48
+ end
49
+
50
+ end
@@ -0,0 +1,17 @@
1
+ module FailtaleReporter::InformationCollector
2
+
3
+ def collect_information(error, ctxs)
4
+ information_collectors.each do |proc|
5
+ proc.call(error, *ctxs)
6
+ end
7
+ end
8
+
9
+ def information_collectors
10
+ @information_collectors ||= []
11
+ end
12
+
13
+ def information_collector(&block)
14
+ information_collectors.push(block)
15
+ end
16
+
17
+ end
@@ -0,0 +1,3 @@
1
+ module FailtaleReporter
2
+ VERSION = "0.2.0"
3
+ end
@@ -0,0 +1,2 @@
1
+
2
+ ::FailtaleReporter.load_adapter('rails')
@@ -0,0 +1,33 @@
1
+
2
+ describe "ErrorReporter" do
3
+
4
+ it "should send error reports" do
5
+ ErrorReporter.should_receive(:post).with('/reports.xml', an_instance_of(Hash))
6
+ lambda do
7
+ ErrorReporter.report do
8
+ raise "hello"
9
+ end
10
+ end.should raise_error(RuntimeError, "hello")
11
+ end
12
+
13
+ it "should send error reports for selected exceptions" do
14
+ ErrorReporter.should_receive(:post).with('/reports.xml', an_instance_of(Hash))
15
+ ErrorReporter.reportable_exceptions ArgumentError
16
+ lambda do
17
+ ErrorReporter.report do
18
+ raise ArgumentError, "hello"
19
+ end
20
+ end.should raise_error(ArgumentError, "hello")
21
+ end
22
+
23
+ it "should not send error reports for non-selected exceptions" do
24
+ ErrorReporter.should_not_receive(:post)
25
+ ErrorReporter.reportable_exceptions ArgumentError
26
+ lambda do
27
+ ErrorReporter.report do
28
+ raise RuntimeError, "hello"
29
+ end
30
+ end.should raise_error(RuntimeError, "hello")
31
+ end
32
+
33
+ end
@@ -0,0 +1,22 @@
1
+
2
+ require File.dirname(__FILE__)+'/../lib/failtale_reporter'
3
+
4
+ describe "ErrorReporter::Error" do
5
+
6
+ describe "#to_param" do
7
+
8
+ it "should generate valid data" do
9
+ begin
10
+ raise "hello"
11
+ rescue Exception => exception
12
+ error = ErrorReporter::Error.new(exception)
13
+
14
+ error.backtrace.should be_eql(exception.backtrace.join("\n"))
15
+ error.description.should be_eql(exception.message)
16
+ error.name.should be_eql("#{exception.class} raised at #{exception.backtrace.first}")
17
+ end
18
+ end
19
+
20
+ end
21
+
22
+ end
metadata ADDED
@@ -0,0 +1,90 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: failtale-reporter
3
+ version: !ruby/object:Gem::Version
4
+ prerelease: false
5
+ segments:
6
+ - 0
7
+ - 2
8
+ - 0
9
+ version: 0.2.0
10
+ platform: ruby
11
+ authors:
12
+ - Simon Menke
13
+ autorequire:
14
+ bindir: bin
15
+ cert_chain: []
16
+
17
+ date: 2010-05-20 00:00:00 +02:00
18
+ default_executable:
19
+ dependencies:
20
+ - !ruby/object:Gem::Dependency
21
+ prerelease: false
22
+ name: httparty
23
+ requirement: &id001 !ruby/object:Gem::Requirement
24
+ requirements:
25
+ - - ">="
26
+ - !ruby/object:Gem::Version
27
+ segments:
28
+ - 0
29
+ version: "0"
30
+ type: :runtime
31
+ version_requirements: *id001
32
+ description: A Ruby error reporter for the Failtale service
33
+ email:
34
+ - simon.menke@gmail.com
35
+ executables: []
36
+
37
+ extensions: []
38
+
39
+ extra_rdoc_files: []
40
+
41
+ files:
42
+ - lib/failtale-reporter.rb
43
+ - lib/failtale_reporter/adapters/rails.rb
44
+ - lib/failtale_reporter/adapters.rb
45
+ - lib/failtale_reporter/backtrace_cleaner.rb
46
+ - lib/failtale_reporter/client.rb
47
+ - lib/failtale_reporter/configuration.rb
48
+ - lib/failtale_reporter/error.rb
49
+ - lib/failtale_reporter/information_collector.rb
50
+ - lib/failtale_reporter/version.rb
51
+ - lib/failtale_reporter.rb
52
+ - rails/init.rb
53
+ - spec/error_reporter_spec.rb
54
+ - spec/error_spec.rb
55
+ - LICENSE
56
+ - README.md
57
+ has_rdoc: true
58
+ homepage: http://github.com/mrhenry
59
+ licenses: []
60
+
61
+ post_install_message:
62
+ rdoc_options: []
63
+
64
+ require_paths:
65
+ - lib
66
+ required_ruby_version: !ruby/object:Gem::Requirement
67
+ requirements:
68
+ - - ">="
69
+ - !ruby/object:Gem::Version
70
+ segments:
71
+ - 0
72
+ version: "0"
73
+ required_rubygems_version: !ruby/object:Gem::Requirement
74
+ requirements:
75
+ - - ">="
76
+ - !ruby/object:Gem::Version
77
+ segments:
78
+ - 1
79
+ - 3
80
+ - 6
81
+ version: 1.3.6
82
+ requirements: []
83
+
84
+ rubyforge_project: failtale_reporter
85
+ rubygems_version: 1.3.6
86
+ signing_key:
87
+ specification_version: 3
88
+ summary: A ruby reporter for Failtale
89
+ test_files: []
90
+