alexyoung-loom-exceptions-rails-plugin 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.
@@ -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
+