projectlocker_pulse 0.2.1
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG +26 -0
- data/Gemfile +3 -0
- data/Guardfile +6 -0
- data/INSTALL +20 -0
- data/MIT-LICENSE +23 -0
- data/README.md +439 -0
- data/README_FOR_HEROKU_ADDON.md +89 -0
- data/Rakefile +223 -0
- data/SUPPORTED_RAILS_VERSIONS +38 -0
- data/TESTING.md +41 -0
- data/features/metal.feature +18 -0
- data/features/rack.feature +60 -0
- data/features/rails.feature +272 -0
- data/features/rails_with_js_notifier.feature +97 -0
- data/features/rake.feature +27 -0
- data/features/sinatra.feature +29 -0
- data/features/step_definitions/file_steps.rb +10 -0
- data/features/step_definitions/metal_steps.rb +23 -0
- data/features/step_definitions/rack_steps.rb +23 -0
- data/features/step_definitions/rails_application_steps.rb +478 -0
- data/features/step_definitions/rake_steps.rb +17 -0
- data/features/support/env.rb +18 -0
- data/features/support/matchers.rb +35 -0
- data/features/support/projectlocker_pulse_shim.rb.template +16 -0
- data/features/support/rails.rb +201 -0
- data/features/support/rake/Rakefile +68 -0
- data/features/support/terminal.rb +107 -0
- data/features/user_informer.feature +63 -0
- data/generators/pulse/lib/insert_commands.rb +34 -0
- data/generators/pulse/lib/rake_commands.rb +24 -0
- data/generators/pulse/pulse_generator.rb +94 -0
- data/generators/pulse/templates/capistrano_hook.rb +6 -0
- data/generators/pulse/templates/initializer.rb +6 -0
- data/generators/pulse/templates/pulse_tasks.rake +25 -0
- data/install.rb +1 -0
- data/lib/projectlocker_pulse.rb +159 -0
- data/lib/pulse/backtrace.rb +108 -0
- data/lib/pulse/capistrano.rb +43 -0
- data/lib/pulse/configuration.rb +305 -0
- data/lib/pulse/notice.rb +390 -0
- data/lib/pulse/rack.rb +54 -0
- data/lib/pulse/rails/action_controller_catcher.rb +30 -0
- data/lib/pulse/rails/controller_methods.rb +85 -0
- data/lib/pulse/rails/error_lookup.rb +33 -0
- data/lib/pulse/rails/javascript_notifier.rb +47 -0
- data/lib/pulse/rails/middleware/exceptions_catcher.rb +33 -0
- data/lib/pulse/rails.rb +40 -0
- data/lib/pulse/rails3_tasks.rb +99 -0
- data/lib/pulse/railtie.rb +49 -0
- data/lib/pulse/rake_handler.rb +65 -0
- data/lib/pulse/sender.rb +128 -0
- data/lib/pulse/shared_tasks.rb +47 -0
- data/lib/pulse/tasks.rb +83 -0
- data/lib/pulse/user_informer.rb +27 -0
- data/lib/pulse/utils/blank.rb +53 -0
- data/lib/pulse/version.rb +3 -0
- data/lib/pulse_tasks.rb +64 -0
- data/lib/rails/generators/pulse/pulse_generator.rb +100 -0
- data/lib/templates/javascript_notifier.erb +15 -0
- data/lib/templates/rescue.erb +91 -0
- data/pulse.gemspec +39 -0
- data/rails/init.rb +1 -0
- data/resources/README.md +34 -0
- data/resources/ca-bundle.crt +3376 -0
- data/script/integration_test.rb +38 -0
- data/test/backtrace_test.rb +162 -0
- data/test/capistrano_test.rb +34 -0
- data/test/catcher_test.rb +333 -0
- data/test/configuration_test.rb +236 -0
- data/test/helper.rb +263 -0
- data/test/javascript_notifier_test.rb +51 -0
- data/test/logger_test.rb +79 -0
- data/test/notice_test.rb +490 -0
- data/test/notifier_test.rb +276 -0
- data/test/projectlocker_pulse_tasks_test.rb +170 -0
- data/test/pulse.xsd +88 -0
- data/test/rack_test.rb +58 -0
- data/test/rails_initializer_test.rb +36 -0
- data/test/recursion_test.rb +10 -0
- data/test/sender_test.rb +288 -0
- data/test/user_informer_test.rb +29 -0
- metadata +432 -0
@@ -0,0 +1,100 @@
|
|
1
|
+
require 'rails/generators'
|
2
|
+
|
3
|
+
class PulseGenerator < Rails::Generators::Base
|
4
|
+
|
5
|
+
class_option :api_key, :aliases => "-k", :type => :string, :desc => "Your Pulse API key"
|
6
|
+
class_option :heroku, :type => :boolean, :desc => "Use the Heroku addon to provide your Pulse API key"
|
7
|
+
class_option :app, :aliases => "-a", :type => :string, :desc => "Your Heroku app name (only required if deploying to >1 Heroku app)"
|
8
|
+
|
9
|
+
def self.source_root
|
10
|
+
@_pulse_source_root ||= File.expand_path("../../../../../generators/pulse/templates", __FILE__)
|
11
|
+
end
|
12
|
+
|
13
|
+
def install
|
14
|
+
ensure_api_key_was_configured
|
15
|
+
ensure_plugin_is_not_present
|
16
|
+
append_capistrano_hook
|
17
|
+
generate_initializer unless api_key_configured?
|
18
|
+
determine_api_key if heroku?
|
19
|
+
test_pulse
|
20
|
+
end
|
21
|
+
|
22
|
+
private
|
23
|
+
|
24
|
+
def ensure_api_key_was_configured
|
25
|
+
if !options[:api_key] && !options[:heroku] && !api_key_configured?
|
26
|
+
puts "Must pass --api-key or --heroku or create config/initializers/pulse.rb"
|
27
|
+
exit
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def ensure_plugin_is_not_present
|
32
|
+
if plugin_is_present?
|
33
|
+
puts "You must first remove the pulse plugin. Please run: script/plugin remove pulse"
|
34
|
+
exit
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
def append_capistrano_hook
|
39
|
+
if File.exists?('config/deploy.rb') && File.exists?('Capfile')
|
40
|
+
append_file('config/deploy.rb', <<-HOOK)
|
41
|
+
|
42
|
+
require './config/boot'
|
43
|
+
require 'pulse/capistrano'
|
44
|
+
HOOK
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
def api_key_expression
|
49
|
+
s = if options[:api_key]
|
50
|
+
"'#{options[:api_key]}'"
|
51
|
+
elsif options[:heroku]
|
52
|
+
"ENV['PULSE_API_KEY']"
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
def generate_initializer
|
57
|
+
template 'initializer.rb', 'config/initializers/pulse.rb'
|
58
|
+
end
|
59
|
+
|
60
|
+
def determine_api_key
|
61
|
+
puts "Attempting to determine your API Key from Heroku..."
|
62
|
+
ENV['PULSE_API_KEY'] = heroku_api_key
|
63
|
+
if ENV['PULSE_API_KEY'].blank?
|
64
|
+
puts "... Failed."
|
65
|
+
puts "WARNING: We were unable to detect the Pulse API Key from your Heroku environment."
|
66
|
+
puts "Your Heroku application environment may not be configured correctly."
|
67
|
+
exit 1
|
68
|
+
else
|
69
|
+
puts "... Done."
|
70
|
+
puts "Heroku's Pulse API Key is '#{ENV['PULSE_API_KEY']}'"
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
def heroku_var(var,app_name = nil)
|
75
|
+
app = app_name ? "--app #{app_name}" : ''
|
76
|
+
`heroku config #{app} | grep -E "#{var.upcase}" | awk '{ print $3; }'`.strip
|
77
|
+
end
|
78
|
+
|
79
|
+
def heroku_api_key
|
80
|
+
heroku_var("pulse_api_key",options[:app]).split.find {|x| x unless x.blank?}
|
81
|
+
end
|
82
|
+
|
83
|
+
def heroku?
|
84
|
+
options[:heroku] ||
|
85
|
+
system("grep PULSE_API_KEY config/initializers/pulse.rb") ||
|
86
|
+
system("grep PULSE_API_KEY config/environment.rb")
|
87
|
+
end
|
88
|
+
|
89
|
+
def api_key_configured?
|
90
|
+
File.exists?('config/initializers/pulse.rb')
|
91
|
+
end
|
92
|
+
|
93
|
+
def test_pulse
|
94
|
+
puts run("rake pulse:test --trace")
|
95
|
+
end
|
96
|
+
|
97
|
+
def plugin_is_present?
|
98
|
+
File.exists?('vendor/plugins/pulse')
|
99
|
+
end
|
100
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
<%= javascript_tag %Q{
|
2
|
+
(function(){
|
3
|
+
var notifierJsScheme = (("https:" == document.location.protocol) ? "https://" : "http://");
|
4
|
+
document.write(unescape("%3Cscript src='" + notifierJsScheme + "#{host}/javascripts/notifier.js' type='text/javascript'%3E%3C/script%3E"));
|
5
|
+
})();
|
6
|
+
}%>
|
7
|
+
|
8
|
+
<%= javascript_tag %Q{
|
9
|
+
window.Pulse = Pulse
|
10
|
+
Pulse.setKey('#{api_key}');
|
11
|
+
Pulse.setHost('#{host}');
|
12
|
+
Pulse.setEnvironment('#{environment}');
|
13
|
+
Pulse.setErrorDefaults({ url: "#{escape_javascript url}", component: "#{controller_name}", action: "#{action_name}" });
|
14
|
+
}
|
15
|
+
%>
|
@@ -0,0 +1,91 @@
|
|
1
|
+
<script type="text/javascript">
|
2
|
+
var Pulse = {
|
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=Pulse.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 = 'pulse';
|
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
|
+
Pulse.initialize.apply(Pulse);
|
74
|
+
};
|
75
|
+
</script>
|
76
|
+
|
77
|
+
<style type="text/css">
|
78
|
+
#pulse {
|
79
|
+
background: #FFF url(http://www.projectlocker.com/images/projectlocker_logo_244x30.png) 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>
|
data/pulse.gemspec
ADDED
@@ -0,0 +1,39 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
$:.push File.expand_path("../lib", __FILE__)
|
3
|
+
require "pulse/version"
|
4
|
+
|
5
|
+
Gem::Specification.new do |s|
|
6
|
+
s.name = %q{projectlocker_pulse}
|
7
|
+
s.version = Pulse::VERSION.dup
|
8
|
+
s.summary = %q{Exception reporting service for ProjectLocker}
|
9
|
+
|
10
|
+
s.require_paths = ["lib"]
|
11
|
+
s.files = Dir["{generators/**/*,lib/**/*,rails/**/*,resources/*,script/*}"] +
|
12
|
+
%w(pulse.gemspec CHANGELOG Gemfile Guardfile INSTALL MIT-LICENSE Rakefile README_FOR_HEROKU_ADDON.md README.md TESTING.md SUPPORTED_RAILS_VERSIONS install.rb)
|
13
|
+
s.test_files = Dir.glob("{test,spec,features}/**/*")
|
14
|
+
|
15
|
+
s.add_runtime_dependency("builder")
|
16
|
+
s.add_runtime_dependency("girl_friday")
|
17
|
+
|
18
|
+
s.add_development_dependency("actionpack", "~> 2.3.8")
|
19
|
+
s.add_development_dependency("activerecord", "~> 2.3.8")
|
20
|
+
s.add_development_dependency("activesupport", "~> 2.3.8")
|
21
|
+
s.add_development_dependency("mocha", "0.10.5")
|
22
|
+
s.add_development_dependency("bourne", ">= 1.0")
|
23
|
+
s.add_development_dependency("cucumber", "~> 0.10.6")
|
24
|
+
s.add_development_dependency("fakeweb", "~> 1.3.0")
|
25
|
+
s.add_development_dependency("nokogiri", "~> 1.4.3.1")
|
26
|
+
s.add_development_dependency("rspec", "~> 2.6.0")
|
27
|
+
s.add_development_dependency("sham_rack", "~> 1.3.0")
|
28
|
+
s.add_development_dependency("shoulda", "~> 2.11.3")
|
29
|
+
s.add_development_dependency("capistrano", "~> 2.8.0")
|
30
|
+
s.add_development_dependency("guard" )
|
31
|
+
s.add_development_dependency("guard-test" )
|
32
|
+
s.add_development_dependency("simplecov" )
|
33
|
+
|
34
|
+
s.authors = ["Airbrake", "C. G. Brown"]
|
35
|
+
s.email = %q{support@projectlocker.com}
|
36
|
+
s.homepage = "http://www.projectlocker.com"
|
37
|
+
|
38
|
+
s.platform = Gem::Platform::RUBY
|
39
|
+
end
|
data/rails/init.rb
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require 'pulse/rails'
|
data/resources/README.md
ADDED
@@ -0,0 +1,34 @@
|
|
1
|
+
Pulse Resources
|
2
|
+
==================
|
3
|
+
|
4
|
+
Pulse can be run over SSL. SSL Certificate Authority (CA) certificates are not kept current by default on many environments. When CA certs are stale, Pulse cannot verify Pulse's production SSL cert and error reports fail. To avoid this, we now package local CA certs. The production of these certs is detailed here.
|
5
|
+
|
6
|
+
Building ca-bundle.crt
|
7
|
+
----------------------
|
8
|
+
|
9
|
+
From https://gist.github.com/996292.
|
10
|
+
|
11
|
+
If you want to use curl or net-http/open-uri to access https resources, you will often (always?) get an error, because they don't have the large number of root certificates installed that web browsers have.
|
12
|
+
|
13
|
+
You can manually install the root certs, but first you have to get them from somewhere. [This article](http://notetoself.vrensk.com/2008/09/verified-https-in-ruby/) gives a nice description of how to do that. The [source of the cert files](http://curl.haxx.se/ca/cacert.pem) it points to is hosted by the curl project, who kindly provide it in the .pem format.
|
14
|
+
|
15
|
+
**problem:** Sadly, ironically, and comically, it's not possible to access that file via https! Luckily, the awesome curl project does provide us with the script that they use to produce the file, so we can do it securely ourselves. Here's how.
|
16
|
+
|
17
|
+
1. `git clone https://github.com/bagder/curl.git`
|
18
|
+
2. `cd curl/lib`
|
19
|
+
3. edit `mk-ca-bundle.pl` and change:
|
20
|
+
|
21
|
+
```perl
|
22
|
+
my $url = 'http://mxr.mozilla.org/mozilla/source/security/nss/lib/ckfw/builtins/certdata.txt?raw=1';
|
23
|
+
```
|
24
|
+
|
25
|
+
to
|
26
|
+
|
27
|
+
```perl
|
28
|
+
my $url = 'https://mxr.mozilla.org/mozilla/source/security/nss/lib/ckfw/builtins/certdata.txt?raw=1';
|
29
|
+
```
|
30
|
+
|
31
|
+
(change `http` to `https`)
|
32
|
+
4. `./mk-ca-bundle.pl`
|
33
|
+
|
34
|
+
Ta da!
|