alexyoung-loom-exceptions-rails-plugin 2.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2008 [name of plugin creator]
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,35 @@
1
+ h2. Loom
2
+
3
+ This plugin provides exception reporting for "Loom":http://loomapp.com.
4
+
5
+ h2. Usage
6
+
7
+ You must sign up to Loom to use this plugin. Install as a gem or a plugin.
8
+
9
+ h3. Installation
10
+
11
+ As a gem:
12
+
13
+ <code>gem install loom-exceptions-rails-plugin --source=http://gems.github.com/</code>
14
+
15
+ As a plugin:
16
+
17
+ <code>script/plugin install git://github.com/alexyoung/loom-exceptions-rails-plugin.git</code>
18
+
19
+ Add this to <code>config/initializers/loom.rb</code>
20
+
21
+ <pre><code>
22
+ Helicoid::Loom.configure do |config|
23
+ config.api_key = 'xxx'
24
+ config.server = 'http://loomapp.com'
25
+ end
26
+ </code></pre>
27
+
28
+ The <code>server</code> option can be used with the open source version of Loom.
29
+
30
+ h2. Credits
31
+
32
+ * Created by Alex Young for Helicoid Limited (helicoid.net)
33
+ * Advice and additional development by Gabriel Gironda (annealer.org)
34
+
35
+ Copyright (c) 2008-2009 Helicoid Limited, released under the MIT license
@@ -0,0 +1,22 @@
1
+ require 'rake'
2
+ require 'rake/testtask'
3
+ require 'rake/rdoctask'
4
+
5
+ desc 'Default: run unit tests.'
6
+ task :default => :test
7
+
8
+ desc 'Test the loom plugin.'
9
+ Rake::TestTask.new(:test) do |t|
10
+ t.libs << 'lib'
11
+ t.pattern = 'test/**/*_test.rb'
12
+ t.verbose = true
13
+ end
14
+
15
+ desc 'Generate documentation for the loom plugin.'
16
+ Rake::RDocTask.new(:rdoc) do |rdoc|
17
+ rdoc.rdoc_dir = 'rdoc'
18
+ rdoc.title = 'Loom'
19
+ rdoc.options << '--line-numbers' << '--inline-source'
20
+ rdoc.rdoc_files.include('README')
21
+ rdoc.rdoc_files.include('lib/**/*.rb')
22
+ end
data/init.rb ADDED
@@ -0,0 +1,4 @@
1
+ require 'loom'
2
+ require 'loom_exception'
3
+
4
+ Helicoid::Loom.enable
@@ -0,0 +1 @@
1
+ # Install hook code here
@@ -0,0 +1,65 @@
1
+ module Helicoid
2
+ module Loom
3
+ class << self
4
+ attr_accessor :api_key, :server, :before_action, :user_id
5
+
6
+ def enable
7
+ ActionController::Base.class_eval do
8
+ include Reporter
9
+ end
10
+ end
11
+
12
+ def configure
13
+ yield self
14
+
15
+ self.server ||= 'http://loomapp.com'
16
+
17
+ if defined?(ActionController::Base) && !ActionController::Base.include?(Helicoid::Loom::Reporter)
18
+ enable
19
+ end
20
+ end
21
+ end
22
+
23
+ module Reporter
24
+ def self.included(base)
25
+ base.send(:alias_method, :original_rescue_action_in_public, :rescue_action_in_public)
26
+ base.send(:alias_method, :rescue_action_in_public, :send_to_loom)
27
+ end
28
+
29
+ def send_to_loom(exception)
30
+ raise if local_request?
31
+
32
+ send(Helicoid::Loom.before_action) if Helicoid::Loom.before_action
33
+
34
+ user_id = case Helicoid::Loom.user_id
35
+ when Proc
36
+ Helicoid::Loom.user_id.bind(self).call
37
+ when Symbol, String
38
+ send Helicoid::Loom.user_id
39
+ end
40
+
41
+ LoomException.log Helicoid::Loom.server, Helicoid::Loom.api_key do |loom|
42
+ loom.session = session.data
43
+ loom.remote_ip = request.remote_ip
44
+ loom.exception = exception
45
+ loom.cookies = request.cookies
46
+ loom.request_parameters = request.parameters
47
+ loom.url = request.request_uri
48
+ loom.user_id = user_id
49
+ end
50
+
51
+ original_rescue_action_in_public exception
52
+ end
53
+ end
54
+
55
+ module ClassMethods
56
+ def logger
57
+ ActiveRecord::Base.logger
58
+ end
59
+
60
+ def enable_loom(options = {})
61
+ logger.warn "enable_loom has been removed. Please use config/initializers/loom.rb."
62
+ end
63
+ end
64
+ end
65
+ end
@@ -0,0 +1,121 @@
1
+ require 'pp'
2
+ require 'net/http'
3
+
4
+ class LoomException
5
+ attr_accessor :session, :cookies, :request_parameters, :url, :user_id, :exception, :remote_ip
6
+
7
+ class LoomDown < Exception ; end
8
+ class LoomError < Exception ; end
9
+
10
+ def initialize(url, api_key)
11
+ @loom_login = { :url => url, :api_key => api_key }
12
+ end
13
+
14
+ def send_to_loom
15
+ response = post
16
+
17
+ if response.code.match /^2/
18
+ true
19
+ else
20
+ puts response.message
21
+ puts response.body
22
+ end
23
+ end
24
+
25
+ def self.log(url, api_key, &block)
26
+ loom = new url, api_key
27
+ yield loom
28
+ loom.send_to_loom
29
+ rescue LoomDown # TODO
30
+ # Timed out or Loom down. Log the error and optionally email the administrator.
31
+ rescue LoomError # TODO
32
+ # We sent an invalid request. Log the error and optionally email the administrator.
33
+ rescue Exception # TODO
34
+ # Something else happened, log it. The user will be shown an error page so they
35
+ # can acknowledge the issue and continue using the application.
36
+ end
37
+
38
+ private
39
+ def post
40
+ url = URI.parse "#{@loom_login[:url]}/report/#{@loom_login[:api_key]}"
41
+
42
+ req = Net::HTTP::Post.new url.path
43
+ req.add_field 'Accept', 'application/xml'
44
+ req.add_field 'Content-Type', 'application/xml'
45
+
46
+ connection = Net::HTTP.new(url.host, url.port)
47
+ connection.request req, loom_parameters_as_xml
48
+ end
49
+
50
+ def loom_parameters_as_xml
51
+ for_xml = loom_parameters.dup
52
+ for_xml[:details].each do |key, value|
53
+ # Convert parameters that can't be converted to XML
54
+ if value.kind_of? Hash
55
+ value.each do |value_key, value_value|
56
+ if incompatible_with_to_xml? value_value
57
+ for_xml[:details][key][value_key] = dump_to_string(value_value)
58
+ end
59
+ end
60
+ elsif incompatible_with_to_xml?(value)
61
+ for_xml[:details][key] = dump_to_string(value)
62
+ end
63
+ end
64
+
65
+ for_xml = convert_all_keys_to_valid_xml_keys(for_xml)
66
+ for_xml.to_xml(:root => 'remote_exception')
67
+ end
68
+
69
+ def incompatible_with_to_xml?(value)
70
+ if value.kind_of?(String) or value.kind_of?(Numeric)
71
+ return false
72
+ else
73
+ value.to_xml
74
+ end
75
+
76
+ return false
77
+ rescue Exception
78
+ return true
79
+ end
80
+
81
+ def dump_to_string(value)
82
+ PP.pp(value, "")
83
+ rescue Exception
84
+ "Loom error: Unable to parse value as XML"
85
+ end
86
+
87
+ # Removes keys like -session_id which will break the API
88
+ def convert_all_keys_to_valid_xml_keys(values)
89
+ returning Hash.new do |converted_values|
90
+ values.each do |key, value|
91
+ if value.kind_of? Hash
92
+ converted_values[convert_key_to_xml_key(key)] = convert_all_keys_to_valid_xml_keys(value)
93
+ else
94
+ converted_values[convert_key_to_xml_key(key)] = value
95
+ end
96
+ end
97
+ end
98
+ end
99
+
100
+ def convert_key_to_xml_key(key)
101
+ key.to_s.sub(/^[^[:alnum:]]/, '')
102
+ end
103
+
104
+ def loom_parameters
105
+ {
106
+ :title => "#{@exception.class}: #{@exception.to_s}",
107
+ :details => { :session_variables => @session.dup,
108
+ :cookies => @cookies.dup,
109
+ :request_parameters => @request_parameters.dup,
110
+ :url => @url,
111
+ :user_id => @user_id,
112
+ :remote_ip => @remote_ip,
113
+ :stack_trace => stack_trace }
114
+ }
115
+ end
116
+
117
+ def stack_trace
118
+ return '' unless @exception.backtrace
119
+ @exception.backtrace.join("\n")
120
+ end
121
+ end
@@ -0,0 +1,19 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ Gem::Specification.new do |s|
4
+ s.name = %q{loom-exceptions-rails-plugin}
5
+ s.version = "2.0"
6
+
7
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
8
+ s.authors = ["Alex R. Young"]
9
+ s.date = %q{2009-07-18}
10
+ s.description = %q{Loom is a helpdesk web app which supports exception handling and notifications.}
11
+ s.email = %q{tom@mojombo.com}
12
+ s.files = ["init.rb", "install.rb", "lib", "lib/loom.rb", "lib/loom_exception.rb", "loom-exceptions-rails-plugin.gemspec", "MIT-LICENSE", "Rakefile", "README.textile", "tasks", "tasks/loom_tasks.rake", "test", "test/exception_test.rb", "test/loom_test.rb", "uninstall.rb"]
13
+ s.has_rdoc = false
14
+ s.homepage = %q{http://loomapp.com}
15
+ s.require_paths = ["lib"]
16
+ s.rubygems_version = %q{1.3.0}
17
+ s.summary = %q{This gem provides exception notification handling for your Rails applications.}
18
+ end
19
+
@@ -0,0 +1,31 @@
1
+ # desc "Explaining what the task does"
2
+ # task :loom do
3
+ # # Task goes here
4
+ # end
5
+
6
+ namespace :loom do
7
+ desc "Sends a test exception so you can test your settings"
8
+ task :test do
9
+ require 'action_controller/test_process'
10
+ require 'app/controllers/application_controller'
11
+
12
+ class ApplicationController
13
+ def test
14
+ puts "Connecting to server: #{Helicoid::Loom.server} with API key: #{Helicoid::Loom.api_key}"
15
+ raise "This is a test error notification"
16
+ end
17
+
18
+ def rescue_action(exception)
19
+ rescue_action_in_public exception
20
+ end
21
+ end
22
+
23
+ request = ActionController::TestRequest.new
24
+ response = ActionController::TestResponse.new
25
+
26
+ request.action = 'test'
27
+ request.request_uri = '/test'
28
+
29
+ ApplicationController.process request, response
30
+ end
31
+ end
File without changes
@@ -0,0 +1,69 @@
1
+ require 'rubygems'
2
+ require 'active_support'
3
+ require 'ostruct'
4
+ require 'test/unit'
5
+ require 'mocha'
6
+ require File.dirname(__FILE__) + '/../lib/loom'
7
+ require File.dirname(__FILE__) + '/../lib/loom_exception'
8
+
9
+ class LoomTest < Test::Unit::TestCase
10
+ # Replace this with your real tests.
11
+
12
+ def setup
13
+ stub_loom_api
14
+ end
15
+
16
+ def test_catches_exception
17
+ end
18
+
19
+ def test_posts_to_loom
20
+ exception = mock_loom_exception :exception => mock_exception
21
+ assert exception.send_to_loom
22
+ end
23
+
24
+ def test_posts_to_loom_with_nil_backtrace
25
+ exception = mock_loom_exception
26
+ assert exception.send_to_loom
27
+ end
28
+
29
+ def test_configure
30
+ Helicoid::Loom.configure do |config|
31
+ config.api_key = 'xxx'
32
+ end
33
+
34
+ assert_equal 'xxx', Helicoid::Loom.api_key
35
+ assert_equal 'http://loomapp.com', Helicoid::Loom.server
36
+ end
37
+
38
+ private
39
+
40
+ def mocked_response(options = {})
41
+ OpenStruct.new :code => '200'
42
+ end
43
+
44
+ def stub_loom_api
45
+ Net::HTTP.any_instance.stubs(:request).returns mocked_response
46
+ end
47
+
48
+ def mock_exception
49
+ exception = nil
50
+ begin
51
+ 1 / 0
52
+ rescue Exception => e
53
+ exception = e
54
+ end
55
+ exception
56
+ end
57
+
58
+ def mock_loom_exception(options = {})
59
+ exception = LoomException.new 'helicoid', 'xxx'
60
+ exception.session = OpenStruct.new :user_id => '1'
61
+ exception.cookies = []
62
+ exception.request_parameters = []
63
+ exception.url = 'http://example.com'
64
+ exception.user_id = '1'
65
+ exception.exception = options[:exception] || ZeroDivisionError.new
66
+ exception.remote_ip = '127.0.0.1'
67
+ exception
68
+ end
69
+ end
@@ -0,0 +1 @@
1
+ # Uninstall hook code here
metadata ADDED
@@ -0,0 +1,67 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: alexyoung-loom-exceptions-rails-plugin
3
+ version: !ruby/object:Gem::Version
4
+ version: "2.0"
5
+ platform: ruby
6
+ authors:
7
+ - Alex R. Young
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2009-07-18 00:00:00 -07:00
13
+ default_executable:
14
+ dependencies: []
15
+
16
+ description: Loom is a helpdesk web app which supports exception handling and notifications.
17
+ email: tom@mojombo.com
18
+ executables: []
19
+
20
+ extensions: []
21
+
22
+ extra_rdoc_files: []
23
+
24
+ files:
25
+ - init.rb
26
+ - install.rb
27
+ - lib
28
+ - lib/loom.rb
29
+ - lib/loom_exception.rb
30
+ - loom-exceptions-rails-plugin.gemspec
31
+ - MIT-LICENSE
32
+ - Rakefile
33
+ - README.textile
34
+ - tasks
35
+ - tasks/loom_tasks.rake
36
+ - test
37
+ - test/exception_test.rb
38
+ - test/loom_test.rb
39
+ - uninstall.rb
40
+ has_rdoc: false
41
+ homepage: http://loomapp.com
42
+ post_install_message:
43
+ rdoc_options: []
44
+
45
+ require_paths:
46
+ - lib
47
+ required_ruby_version: !ruby/object:Gem::Requirement
48
+ requirements:
49
+ - - ">="
50
+ - !ruby/object:Gem::Version
51
+ version: "0"
52
+ version:
53
+ required_rubygems_version: !ruby/object:Gem::Requirement
54
+ requirements:
55
+ - - ">="
56
+ - !ruby/object:Gem::Version
57
+ version: "0"
58
+ version:
59
+ requirements: []
60
+
61
+ rubyforge_project:
62
+ rubygems_version: 1.2.0
63
+ signing_key:
64
+ specification_version: 2
65
+ summary: This gem provides exception notification handling for your Rails applications.
66
+ test_files: []
67
+