hatless-hoptoad_notifier 2.2.6

Sign up to get free protection for your applications and to get access to all the features.
Files changed (45) hide show
  1. data/CHANGELOG +149 -0
  2. data/INSTALL +25 -0
  3. data/MIT-LICENSE +22 -0
  4. data/README.rdoc +382 -0
  5. data/Rakefile +217 -0
  6. data/SUPPORTED_RAILS_VERSIONS +9 -0
  7. data/TESTING.rdoc +8 -0
  8. data/generators/hoptoad/hoptoad_generator.rb +54 -0
  9. data/generators/hoptoad/lib/insert_commands.rb +34 -0
  10. data/generators/hoptoad/lib/rake_commands.rb +24 -0
  11. data/generators/hoptoad/templates/capistrano_hook.rb +6 -0
  12. data/generators/hoptoad/templates/hoptoad_notifier_tasks.rake +25 -0
  13. data/generators/hoptoad/templates/initializer.rb +6 -0
  14. data/lib/hoptoad_notifier/backtrace.rb +99 -0
  15. data/lib/hoptoad_notifier/capistrano.rb +20 -0
  16. data/lib/hoptoad_notifier/configuration.rb +232 -0
  17. data/lib/hoptoad_notifier/notice.rb +318 -0
  18. data/lib/hoptoad_notifier/rack.rb +40 -0
  19. data/lib/hoptoad_notifier/rails/action_controller_catcher.rb +29 -0
  20. data/lib/hoptoad_notifier/rails/controller_methods.rb +58 -0
  21. data/lib/hoptoad_notifier/rails/error_lookup.rb +33 -0
  22. data/lib/hoptoad_notifier/rails.rb +37 -0
  23. data/lib/hoptoad_notifier/rails3_tasks.rb +90 -0
  24. data/lib/hoptoad_notifier/railtie.rb +23 -0
  25. data/lib/hoptoad_notifier/sender.rb +63 -0
  26. data/lib/hoptoad_notifier/tasks.rb +97 -0
  27. data/lib/hoptoad_notifier/version.rb +3 -0
  28. data/lib/hoptoad_notifier.rb +148 -0
  29. data/lib/hoptoad_tasks.rb +40 -0
  30. data/lib/rails/generators/hoptoad/hoptoad_generator.rb +64 -0
  31. data/lib/templates/rescue.erb +91 -0
  32. data/rails/init.rb +1 -0
  33. data/script/integration_test.rb +38 -0
  34. data/test/backtrace_test.rb +118 -0
  35. data/test/catcher_test.rb +324 -0
  36. data/test/configuration_test.rb +208 -0
  37. data/test/helper.rb +239 -0
  38. data/test/hoptoad_tasks_test.rb +138 -0
  39. data/test/logger_test.rb +85 -0
  40. data/test/notice_test.rb +443 -0
  41. data/test/notifier_test.rb +222 -0
  42. data/test/rack_test.rb +58 -0
  43. data/test/rails_initializer_test.rb +36 -0
  44. data/test/sender_test.rb +123 -0
  45. metadata +204 -0
@@ -0,0 +1,33 @@
1
+ module HoptoadNotifier
2
+ module Rails
3
+ module ErrorLookup
4
+
5
+ # Sets up an alias chain to catch exceptions when Rails does
6
+ def self.included(base) #:nodoc:
7
+ base.send(:alias_method, :rescue_action_locally_without_hoptoad, :rescue_action_locally)
8
+ base.send(:alias_method, :rescue_action_locally, :rescue_action_locally_with_hoptoad)
9
+ end
10
+
11
+ private
12
+
13
+ def rescue_action_locally_with_hoptoad(exception)
14
+ result = rescue_action_locally_without_hoptoad(exception)
15
+
16
+ if HoptoadNotifier.configuration.development_lookup
17
+ path = File.join(File.dirname(__FILE__), '..', '..', 'templates', 'rescue.erb')
18
+ notice = HoptoadNotifier.build_lookup_hash_for(exception, hoptoad_request_data)
19
+
20
+ result << @template.render(
21
+ :file => path,
22
+ :use_full_path => false,
23
+ :locals => { :host => HoptoadNotifier.configuration.host,
24
+ :api_key => HoptoadNotifier.configuration.api_key,
25
+ :notice => notice })
26
+ end
27
+
28
+ result
29
+ end
30
+ end
31
+ end
32
+ end
33
+
@@ -0,0 +1,37 @@
1
+ require 'hoptoad_notifier'
2
+ require 'hoptoad_notifier/rails/controller_methods'
3
+ require 'hoptoad_notifier/rails/action_controller_catcher'
4
+ require 'hoptoad_notifier/rails/error_lookup'
5
+
6
+ module HoptoadNotifier
7
+ module Rails
8
+ def self.initialize
9
+ if defined?(ActionController::Base)
10
+ ActionController::Base.send(:include, HoptoadNotifier::Rails::ActionControllerCatcher)
11
+ ActionController::Base.send(:include, HoptoadNotifier::Rails::ErrorLookup)
12
+ ActionController::Base.send(:include, HoptoadNotifier::Rails::ControllerMethods)
13
+ end
14
+
15
+ rails_logger = if defined?(::Rails.logger)
16
+ ::Rails.logger
17
+ elsif defined?(RAILS_DEFAULT_LOGGER)
18
+ RAILS_DEFAULT_LOGGER
19
+ end
20
+
21
+ if defined?(::Rails.configuration) && ::Rails.configuration.respond_to?(:middleware)
22
+ ::Rails.configuration.middleware.insert_after 'ActionController::Failsafe',
23
+ HoptoadNotifier::Rack
24
+ end
25
+
26
+ HoptoadNotifier.configure(true) do |config|
27
+ config.logger = rails_logger
28
+ config.environment_name = RAILS_ENV if defined?(RAILS_ENV)
29
+ config.project_root = RAILS_ROOT if defined?(RAILS_ROOT)
30
+ config.framework = "Rails: #{::Rails::VERSION::STRING}" if defined?(::Rails::VERSION)
31
+ end
32
+ end
33
+ end
34
+ end
35
+
36
+ HoptoadNotifier::Rails.initialize
37
+
@@ -0,0 +1,90 @@
1
+ require 'hoptoad_notifier'
2
+
3
+ namespace :hoptoad do
4
+ desc "Notify Hoptoad of a new deploy."
5
+ task :deploy => :environment do
6
+ require 'hoptoad_tasks'
7
+ HoptoadTasks.deploy(:rails_env => ENV['TO'],
8
+ :scm_revision => ENV['REVISION'],
9
+ :scm_repository => ENV['REPO'],
10
+ :local_username => ENV['USER'],
11
+ :api_key => ENV['API_KEY'])
12
+ end
13
+
14
+ desc "Verify your gem installation by sending a test exception to the hoptoad service"
15
+ task :test => [:environment] do
16
+ Rails.logger = Logger.new(STDOUT)
17
+ Rails.logger.level = Logger::DEBUG
18
+ HoptoadNotifier.configure(true) do |config|
19
+ config.logger = Rails.logger
20
+ end
21
+
22
+ require 'app/controllers/application_controller'
23
+
24
+ class HoptoadTestingException < RuntimeError; end
25
+
26
+ unless HoptoadNotifier.configuration.api_key
27
+ puts "Hoptoad needs an API key configured! Check the README to see how to add it."
28
+ exit
29
+ end
30
+
31
+ HoptoadNotifier.configuration.development_environments = []
32
+
33
+ puts "Configuration:"
34
+ HoptoadNotifier.configuration.to_hash.each do |key, value|
35
+ puts sprintf("%25s: %s", key.to_s, value.inspect.slice(0, 55))
36
+ end
37
+
38
+ unless defined?(ApplicationController)
39
+ puts "No ApplicationController found"
40
+ exit
41
+ end
42
+
43
+ puts 'Setting up the Controller.'
44
+ class ApplicationController
45
+ # This is to bypass any filters that may prevent access to the action.
46
+ prepend_before_filter :test_hoptoad
47
+ def test_hoptoad
48
+ puts "Raising '#{exception_class.name}' to simulate application failure."
49
+ raise exception_class.new, 'Testing hoptoad via "rake hoptoad:test". If you can see this, it works.'
50
+ end
51
+
52
+ # def rescue_action(exception)
53
+ # rescue_action_in_public exception
54
+ # end
55
+
56
+ # Ensure we actually have an action to go to.
57
+ def verify; end
58
+
59
+ # def consider_all_requests_local
60
+ # false
61
+ # end
62
+
63
+ # def local_request?
64
+ # false
65
+ # end
66
+
67
+ def exception_class
68
+ exception_name = ENV['EXCEPTION'] || "HoptoadTestingException"
69
+ Object.const_get(exception_name)
70
+ rescue
71
+ Object.const_set(exception_name, Class.new(Exception))
72
+ end
73
+
74
+ def logger
75
+ nil
76
+ end
77
+ end
78
+ class HoptoadVerificationController < ApplicationController; end
79
+
80
+ Rails::Application.routes_reloader.reload_if_changed
81
+ Rails::Application.routes.draw do |map|
82
+ match 'verify' => 'application#verify', :as => 'verify'
83
+ end
84
+
85
+ puts 'Processing request.'
86
+ env = Rack::MockRequest.env_for("/verify")
87
+ Rails::Application.call(env)
88
+ end
89
+ end
90
+
@@ -0,0 +1,23 @@
1
+ require 'hoptoad_notifier'
2
+ require 'rails'
3
+
4
+ module HoptoadNotifier
5
+ class Railtie < Rails::Railtie
6
+ rake_tasks do
7
+ require "hoptoad_notifier/rails3_tasks"
8
+ end
9
+
10
+ initializer "hoptoad.use_rack_middleware" do |app|
11
+ app.config.middleware.use "HoptoadNotifier::Rack"
12
+ end
13
+
14
+ config.after_initialize do
15
+ HoptoadNotifier.configure(true) do |config|
16
+ config.logger = Rails.logger
17
+ config.environment_name = Rails.env
18
+ config.project_root = Rails.root
19
+ config.framework = "Rails: #{::Rails::VERSION::STRING}"
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,63 @@
1
+ module HoptoadNotifier
2
+ # Sends out the notice to Hoptoad
3
+ class Sender
4
+
5
+ NOTICES_URI = '/notifier_api/v2/notices/'.freeze
6
+
7
+ def initialize(options = {})
8
+ [:proxy_host, :proxy_port, :proxy_user, :proxy_pass, :protocol,
9
+ :host, :port, :secure, :http_open_timeout, :http_read_timeout].each do |option|
10
+ instance_variable_set("@#{option}", options[option])
11
+ end
12
+ end
13
+
14
+ # Sends the notice data off to Hoptoad for processing.
15
+ #
16
+ # @param [String] data The XML notice to be sent off
17
+ def send_to_hoptoad(data)
18
+ logger.debug { "Sending request to #{url.to_s}:\n#{data}" } if logger
19
+
20
+ http =
21
+ Net::HTTP::Proxy(proxy_host, proxy_port, proxy_user, proxy_pass).
22
+ new(url.host, url.port)
23
+
24
+ http.read_timeout = http_read_timeout
25
+ http.open_timeout = http_open_timeout
26
+ http.use_ssl = secure
27
+
28
+ response = begin
29
+ http.post(url.path, data, HEADERS)
30
+ rescue TimeoutError => e
31
+ log :error, "Timeout while contacting the Hoptoad server."
32
+ nil
33
+ end
34
+
35
+ case response
36
+ when Net::HTTPSuccess then
37
+ log :info, "Success: #{response.class}", response
38
+ else
39
+ log :error, "Failure: #{response.class}", response
40
+ end
41
+ end
42
+
43
+ private
44
+
45
+ attr_reader :proxy_host, :proxy_port, :proxy_user, :proxy_pass, :protocol,
46
+ :host, :port, :secure, :http_open_timeout, :http_read_timeout
47
+
48
+ def url
49
+ URI.parse("#{protocol}://#{host}:#{port}").merge(NOTICES_URI)
50
+ end
51
+
52
+ def log(level, message, response = nil)
53
+ logger.send level, LOG_PREFIX + message if logger
54
+ HoptoadNotifier.report_environment_info
55
+ HoptoadNotifier.report_response_body(response.body) if response && response.respond_to?(:body)
56
+ end
57
+
58
+ def logger
59
+ HoptoadNotifier.logger
60
+ end
61
+
62
+ end
63
+ end
@@ -0,0 +1,97 @@
1
+ require 'hoptoad_notifier'
2
+
3
+ namespace :hoptoad do
4
+ desc "Notify Hoptoad of a new deploy."
5
+ task :deploy => :environment do
6
+ require 'hoptoad_tasks'
7
+ HoptoadTasks.deploy(:rails_env => ENV['TO'],
8
+ :scm_revision => ENV['REVISION'],
9
+ :scm_repository => ENV['REPO'],
10
+ :local_username => ENV['USER'],
11
+ :api_key => ENV['API_KEY'])
12
+ end
13
+
14
+ task :log_stdout do
15
+ require 'logger'
16
+ RAILS_DEFAULT_LOGGER = Logger.new(STDOUT)
17
+ end
18
+
19
+ desc "Verify your gem installation by sending a test exception to the hoptoad service"
20
+ task :test => ['hoptoad:log_stdout', :environment] do
21
+ RAILS_DEFAULT_LOGGER.level = Logger::DEBUG
22
+
23
+ require 'action_controller/test_process'
24
+
25
+ Dir["app/controllers/application*.rb"].each { |file| require(file) }
26
+
27
+ class HoptoadTestingException < RuntimeError; end
28
+
29
+ unless HoptoadNotifier.configuration.api_key
30
+ puts "Hoptoad needs an API key configured! Check the README to see how to add it."
31
+ exit
32
+ end
33
+
34
+ HoptoadNotifier.configuration.development_environments = []
35
+
36
+ catcher = HoptoadNotifier::Rails::ActionControllerCatcher
37
+ in_controller = ApplicationController.included_modules.include?(catcher)
38
+ in_base = ActionController::Base.included_modules.include?(catcher)
39
+ if !in_controller || !in_base
40
+ puts "Rails initialization did not occur"
41
+ exit
42
+ end
43
+
44
+ puts "Configuration:"
45
+ HoptoadNotifier.configuration.to_hash.each do |key, value|
46
+ puts sprintf("%25s: %s", key.to_s, value.inspect.slice(0, 55))
47
+ end
48
+
49
+ unless defined?(ApplicationController)
50
+ puts "No ApplicationController found"
51
+ exit
52
+ end
53
+
54
+ puts 'Setting up the Controller.'
55
+ class ApplicationController
56
+ # This is to bypass any filters that may prevent access to the action.
57
+ prepend_before_filter :test_hoptoad
58
+ def test_hoptoad
59
+ puts "Raising '#{exception_class.name}' to simulate application failure."
60
+ raise exception_class.new, 'Testing hoptoad via "rake hoptoad:test". If you can see this, it works.'
61
+ end
62
+
63
+ def rescue_action(exception)
64
+ rescue_action_in_public exception
65
+ end
66
+
67
+ # Ensure we actually have an action to go to.
68
+ def verify; end
69
+
70
+ def consider_all_requests_local
71
+ false
72
+ end
73
+
74
+ def local_request?
75
+ false
76
+ end
77
+
78
+ def exception_class
79
+ exception_name = ENV['EXCEPTION'] || "HoptoadTestingException"
80
+ Object.const_get(exception_name)
81
+ rescue
82
+ Object.const_set(exception_name, Class.new(Exception))
83
+ end
84
+
85
+ def logger
86
+ nil
87
+ end
88
+ end
89
+ class HoptoadVerificationController < ApplicationController; end
90
+
91
+ puts 'Processing request.'
92
+ request = ActionController::TestRequest.new
93
+ response = ActionController::TestResponse.new
94
+ HoptoadVerificationController.new.process(request, response)
95
+ end
96
+ end
97
+
@@ -0,0 +1,3 @@
1
+ module HoptoadNotifier
2
+ VERSION = "2.2.6".freeze
3
+ end
@@ -0,0 +1,148 @@
1
+ require 'net/http'
2
+ require 'net/https'
3
+ require 'rubygems'
4
+ require 'active_support'
5
+ require 'hoptoad_notifier/version'
6
+ require 'hoptoad_notifier/configuration'
7
+ require 'hoptoad_notifier/notice'
8
+ require 'hoptoad_notifier/sender'
9
+ require 'hoptoad_notifier/backtrace'
10
+ require 'hoptoad_notifier/rack'
11
+
12
+ require 'hoptoad_notifier/railtie' if defined?(Rails::Railtie)
13
+
14
+ # Gem for applications to automatically post errors to the Hoptoad of their choice.
15
+ module HoptoadNotifier
16
+
17
+ API_VERSION = "2.0"
18
+ LOG_PREFIX = "** [Hoptoad] "
19
+
20
+ HEADERS = {
21
+ 'Content-type' => 'text/xml',
22
+ 'Accept' => 'text/xml, application/xml'
23
+ }
24
+
25
+ class << self
26
+ # The sender object is responsible for delivering formatted data to the Hoptoad server.
27
+ # Must respond to #send_to_hoptoad. See HoptoadNotifier::Sender.
28
+ attr_accessor :sender
29
+
30
+ # A Hoptoad configuration object. Must act like a hash and return sensible
31
+ # values for all Hoptoad configuration options. See HoptoadNotifier::Configuration.
32
+ attr_accessor :configuration
33
+
34
+ # Tell the log that the Notifier is good to go
35
+ def report_ready
36
+ write_verbose_log("Notifier #{VERSION} ready to catch errors")
37
+ end
38
+
39
+ # Prints out the environment info to the log for debugging help
40
+ def report_environment_info
41
+ write_verbose_log("Environment Info: #{environment_info}")
42
+ end
43
+
44
+ # Prints out the response body from Hoptoad for debugging help
45
+ def report_response_body(response)
46
+ write_verbose_log("Response from Hoptoad: \n#{response}")
47
+ end
48
+
49
+ # Returns the Ruby version, Rails version, and current Rails environment
50
+ def environment_info
51
+ info = "[Ruby: #{RUBY_VERSION}]"
52
+ info << " [#{configuration.framework}]"
53
+ info << " [Env: #{configuration.environment_name}]"
54
+ end
55
+
56
+ # Writes out the given message to the #logger
57
+ def write_verbose_log(message)
58
+ logger.info LOG_PREFIX + message if logger
59
+ end
60
+
61
+ # Look for the Rails logger currently defined
62
+ def logger
63
+ self.configuration.logger
64
+ end
65
+
66
+ # Call this method to modify defaults in your initializers.
67
+ #
68
+ # @example
69
+ # HoptoadNotifier.configure do |config|
70
+ # config.api_key = '1234567890abcdef'
71
+ # config.secure = false
72
+ # end
73
+ def configure(silent = false)
74
+ self.configuration ||= Configuration.new
75
+ yield(configuration)
76
+ self.sender = Sender.new(configuration)
77
+ report_ready unless silent
78
+ end
79
+
80
+ # Sends an exception manually using this method, even when you are not in a controller.
81
+ #
82
+ # @param [Exception] exception The exception you want to notify Hoptoad about.
83
+ # @param [Hash] opts Data that will be sent to Hoptoad.
84
+ #
85
+ # @option opts [String] :api_key The API key for this project. The API key is a unique identifier that Hoptoad uses for identification.
86
+ # @option opts [String] :error_message The error returned by the exception (or the message you want to log).
87
+ # @option opts [String] :backtrace A backtrace, usually obtained with +caller+.
88
+ # @option opts [String] :request The controller's request object.
89
+ # @option opts [String] :session The contents of the user's session.
90
+ # @option opts [String] :environment ENV merged with the contents of the request's environment.
91
+ def notify(exception, opts = {})
92
+ send_notice(build_notice_for(exception, opts))
93
+ end
94
+
95
+ # Sends the notice unless it is one of the default ignored exceptions
96
+ # @see HoptoadNotifier.notify
97
+ def notify_or_ignore(exception, opts = {})
98
+ notice = build_notice_for(exception, opts)
99
+ send_notice(notice) unless notice.ignore?
100
+ end
101
+
102
+ def build_lookup_hash_for(exception, options = {})
103
+ notice = build_notice_for(exception, options)
104
+
105
+ result = {}
106
+ result[:action] = notice.action rescue nil
107
+ result[:component] = notice.component rescue nil
108
+ result[:error_class] = notice.error_class if notice.error_class
109
+ result[:environment_name] = 'production'
110
+
111
+ unless notice.backtrace.lines.empty?
112
+ result[:file] = notice.backtrace.lines.first.file
113
+ result[:line_number] = notice.backtrace.lines.first.number
114
+ end
115
+
116
+ result
117
+ end
118
+
119
+ private
120
+
121
+ def send_notice(notice)
122
+ if configuration.public?
123
+ sender.send_to_hoptoad(notice.to_xml)
124
+ end
125
+ end
126
+
127
+ def build_notice_for(exception, opts = {})
128
+ exception = unwrap_exception(exception)
129
+ if exception.respond_to?(:to_hash)
130
+ opts = opts.merge(exception)
131
+ else
132
+ opts = opts.merge(:exception => exception)
133
+ end
134
+ Notice.new(configuration.merge(opts))
135
+ end
136
+
137
+ def unwrap_exception(exception)
138
+ if exception.respond_to?(:original_exception)
139
+ exception.original_exception
140
+ elsif exception.respond_to?(:continued_exception)
141
+ exception.continued_exception
142
+ else
143
+ exception
144
+ end
145
+ end
146
+ end
147
+ end
148
+
@@ -0,0 +1,40 @@
1
+ require 'net/http'
2
+ require 'uri'
3
+ require 'active_support'
4
+
5
+ # Capistrano tasks for notifying Hoptoad of deploys
6
+ module HoptoadTasks
7
+
8
+ # Alerts Hoptoad of a deploy.
9
+ #
10
+ # @param [Hash] opts Data about the deploy that is set to Hoptoad
11
+ #
12
+ # @option opts [String] :rails_env Environment of the deploy (production, staging)
13
+ # @option opts [String] :scm_revision The given revision/sha that is being deployed
14
+ # @option opts [String] :scm_repository Address of your repository to help with code lookups
15
+ # @option opts [String] :local_username Who is deploying
16
+ def self.deploy(opts = {})
17
+ if HoptoadNotifier.configuration.api_key.blank?
18
+ puts "I don't seem to be configured with an API key. Please check your configuration."
19
+ return false
20
+ end
21
+
22
+ if opts[:rails_env].blank?
23
+ puts "I don't know to which Rails environment you are deploying (use the TO=production option)."
24
+ return false
25
+ end
26
+
27
+ params = {'api_key' => opts.delete(:api_key) ||
28
+ HoptoadNotifier.configuration.api_key}
29
+ opts.each {|k,v| params["deploy[#{k}]"] = v }
30
+
31
+ url = URI.parse("http://#{HoptoadNotifier.configuration.host || 'hoptoadapp.com'}/deploys.txt")
32
+ response = Net::HTTP::Proxy(HoptoadNotifier.configuration.proxy_host,
33
+ HoptoadNotifier.configuration.proxy_port,
34
+ HoptoadNotifier.configuration.proxy_user,
35
+ HoptoadNotifier.configuration.proxy_pass).post_form(url, params)
36
+ puts response.body
37
+ return Net::HTTPSuccess === response
38
+ end
39
+ end
40
+
@@ -0,0 +1,64 @@
1
+ require 'rails/generators'
2
+
3
+ class HoptoadGenerator < Rails::Generators::Base
4
+
5
+ class_option :api_key, :aliases => "-k", :type => :string, :desc => "Your Hoptoad API key"
6
+
7
+ def self.source_root
8
+ @_hoptoad_source_root ||= File.expand_path("../../../../../generators/hoptoad/templates", __FILE__)
9
+ end
10
+
11
+ def install
12
+ ensure_api_key_was_configured
13
+ ensure_plugin_is_not_present
14
+ append_capistrano_hook
15
+ generate_initializer unless api_key_configured?
16
+ test_hoptoad
17
+ end
18
+
19
+ private
20
+
21
+ def ensure_api_key_was_configured
22
+ if !options[:api_key] && !api_key_configured?
23
+ puts "Must pass --api-key or create config/initializers/hoptoad.rb"
24
+ exit
25
+ end
26
+ end
27
+
28
+ def ensure_plugin_is_not_present
29
+ if plugin_is_present?
30
+ puts "You must first remove the hoptoad_notifier plugin. Please run: script/plugin remove hoptoad_notifier"
31
+ exit
32
+ end
33
+ end
34
+
35
+ def append_capistrano_hook
36
+ if File.exists?('config/deploy.rb') && File.exists?('Capfile')
37
+ append_file('config/deploy.rb', <<-HOOK)
38
+
39
+ require 'config/boot'
40
+ require 'hoptoad_notifier/capistrano'
41
+ HOOK
42
+ end
43
+ end
44
+
45
+ def api_key
46
+ options[:api_key]
47
+ end
48
+
49
+ def generate_initializer
50
+ template 'initializer.rb', 'config/initializers/hoptoad.rb'
51
+ end
52
+
53
+ def api_key_configured?
54
+ File.exists?('config/initializers/hoptoad.rb')
55
+ end
56
+
57
+ def test_hoptoad
58
+ puts run("rake hoptoad:test --trace")
59
+ end
60
+
61
+ def plugin_is_present?
62
+ File.exists?('vendor/plugins/hoptoad_notifier')
63
+ end
64
+ end
@@ -0,0 +1,91 @@
1
+ <script type="text/javascript">
2
+ var Hoptoad = {
3
+ host : <%= host.to_json %>,
4
+ api_key : <%= api_key.to_json %>,
5
+ notice : <%= notice.to_json %>,
6
+ message : 'This error exists in production!',
7
+
8
+ initialize: function() {
9
+ if (this.initialized) {
10
+ return;
11
+ } else {
12
+ this.initialized = true;
13
+ }
14
+
15
+ var data = [];
16
+
17
+ for (var key in this.notice) {
18
+ data[data.length] = 'notice[' + key + ']=' + this.notice[key];
19
+ }
20
+
21
+ data[data.length] = 'notice[api_key]=' + this.api_key;
22
+ data[data.length] = 'callback=Hoptoad.onSuccess';
23
+ data[data.length] = '_=' + (new Date()).getTime();
24
+
25
+ var head = document.getElementsByTagName('head')[0];
26
+ var done = false;
27
+
28
+ var
29
+ script = document.createElement('script');
30
+ script.src = 'http://' + this.host + '/notices_api/v1/notices/exist?' +
31
+ data.join('&');
32
+ script.type = 'text/javascript';
33
+ script.onload = script.onreadystatechange = function(){
34
+ if (!done && (!this.readyState ||
35
+ this.readyState == 'loaded' || this.readyState == 'complete')) {
36
+
37
+ done = true;
38
+
39
+ // Handle memory leak in IE. (via jQuery)
40
+ script.onload = script.onreadystatechange = null;
41
+ head.removeChild(script);
42
+ }
43
+ };
44
+
45
+ head.appendChild(script);
46
+ },
47
+
48
+ onSuccess: function(error) {
49
+ var body = document.getElementsByTagName('body')[0];
50
+ var text = document.createTextNode(this.message);
51
+ var element = document.createElement('a');
52
+
53
+ element.id = 'hoptoad';
54
+ element.href = 'http://' + error.subdomain + '.' + this.host +
55
+ '/projects/' + error.project_id + '/errors/' + error.id;
56
+ element.appendChild(text);
57
+
58
+ body.insertBefore(element, body.firstChild);
59
+
60
+ var h1 = document.getElementsByTagName('h1')[0];
61
+ var pre = document.getElementsByTagName('pre')[0];
62
+ var wrapper = document.createElement('div');
63
+
64
+ wrapper.id = 'wrapper';
65
+ wrapper.appendChild(h1);
66
+ wrapper.appendChild(pre);
67
+
68
+ body.insertBefore(wrapper, body.children[1]);
69
+ }
70
+ };
71
+
72
+ window.onload = function() {
73
+ Hoptoad.initialize.apply(Hoptoad);
74
+ };
75
+ </script>
76
+
77
+ <style type="text/css">
78
+ #hoptoad {
79
+ background: #FFF url(http://hoptoadapp.com/images/fell-off-the-toad.gif) no-repeat top right;
80
+ color: #F00;
81
+ padding: 45px 101px 45px 12px;
82
+ font-size: 14px;
83
+ font-weight: bold;
84
+ display: block;
85
+ float: right;
86
+ }
87
+
88
+ #wrapper {
89
+ padding-right: 360px;
90
+ }
91
+ </style>