sentry-raven 1.1.0 → 3.1.2
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.
- checksums.yaml +5 -5
- data/.craft.yml +19 -0
- data/.scripts/bump-version.rb +5 -0
- data/CHANGELOG.md +703 -0
- data/Gemfile +37 -0
- data/Makefile +3 -0
- data/README.md +116 -18
- data/Rakefile +30 -0
- data/exe/raven +32 -0
- data/lib/raven/backtrace.rb +17 -8
- data/lib/raven/base.rb +45 -194
- data/lib/raven/breadcrumbs/active_support_logger.rb +25 -0
- data/lib/raven/breadcrumbs/logger.rb +3 -0
- data/lib/raven/breadcrumbs/sentry_logger.rb +73 -0
- data/lib/raven/breadcrumbs.rb +76 -0
- data/lib/raven/cli.rb +31 -39
- data/lib/raven/client.rb +45 -32
- data/lib/raven/configuration.rb +427 -130
- data/lib/raven/context.rb +33 -6
- data/lib/raven/core_ext/object/deep_dup.rb +57 -0
- data/lib/raven/core_ext/object/duplicable.rb +153 -0
- data/lib/raven/event.rb +194 -206
- data/lib/raven/helpers/deprecation_helper.rb +17 -0
- data/lib/raven/instance.rb +249 -0
- data/lib/raven/integrations/delayed_job.rb +25 -23
- data/lib/raven/integrations/rack-timeout.rb +22 -0
- data/lib/raven/integrations/rack.rb +40 -24
- data/lib/raven/integrations/rails/active_job.rb +52 -20
- data/lib/raven/integrations/rails/backtrace_cleaner.rb +29 -0
- data/lib/raven/integrations/rails/controller_transaction.rb +13 -0
- data/lib/raven/integrations/rails/overrides/debug_exceptions_catcher.rb +2 -2
- data/lib/raven/integrations/rails.rb +39 -7
- data/lib/raven/integrations/rake.rb +7 -2
- data/lib/raven/integrations/sidekiq/cleanup_middleware.rb +13 -0
- data/lib/raven/integrations/sidekiq/error_handler.rb +38 -0
- data/lib/raven/integrations/sidekiq.rb +6 -48
- data/lib/raven/integrations/tasks.rb +1 -1
- data/lib/raven/interface.rb +25 -0
- data/lib/raven/interfaces/exception.rb +5 -8
- data/lib/raven/interfaces/http.rb +5 -12
- data/lib/raven/interfaces/message.rb +10 -6
- data/lib/raven/interfaces/single_exception.rb +1 -5
- data/lib/raven/interfaces/stack_trace.rb +23 -30
- data/lib/raven/linecache.rb +35 -23
- data/lib/raven/logger.rb +13 -16
- data/lib/raven/processor/cookies.rb +27 -7
- data/lib/raven/processor/http_headers.rb +55 -0
- data/lib/raven/processor/post_data.rb +16 -3
- data/lib/raven/processor/removecircularreferences.rb +12 -8
- data/lib/raven/processor/removestacktrace.rb +17 -6
- data/lib/raven/processor/sanitizedata.rb +92 -37
- data/lib/raven/processor/utf8conversion.rb +39 -14
- data/lib/raven/processor.rb +5 -1
- data/lib/raven/transports/http.rb +31 -22
- data/lib/raven/transports/stdout.rb +20 -0
- data/lib/raven/transports.rb +6 -10
- data/lib/raven/utils/context_filter.rb +42 -0
- data/lib/raven/utils/deep_merge.rb +6 -12
- data/lib/raven/utils/exception_cause_chain.rb +20 -0
- data/lib/raven/utils/real_ip.rb +62 -0
- data/lib/raven/utils/request_id.rb +16 -0
- data/lib/raven/version.rb +2 -1
- data/lib/sentry-raven-without-integrations.rb +6 -1
- data/lib/sentry_raven_without_integrations.rb +1 -0
- data/sentry-raven.gemspec +28 -0
- metadata +44 -127
- data/lib/raven/error.rb +0 -4
- data/lib/raven/interfaces.rb +0 -34
- data/lib/raven/okjson.rb +0 -614
data/Gemfile
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
source "https://rubygems.org/"
|
|
2
|
+
|
|
3
|
+
gemspec
|
|
4
|
+
|
|
5
|
+
rails_version = ENV["RAILS_VERSION"]
|
|
6
|
+
rails_version = "5.2" if rails_version.nil?
|
|
7
|
+
|
|
8
|
+
if rails_version.to_f != 0
|
|
9
|
+
gem "rails", "~> #{rails_version}"
|
|
10
|
+
gem "rspec-rails", "~> 4.0"
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
gem "delayed_job"
|
|
14
|
+
gem "sidekiq"
|
|
15
|
+
|
|
16
|
+
gem "rack"
|
|
17
|
+
gem "rack-timeout"
|
|
18
|
+
|
|
19
|
+
# TODO: Remove this if https://github.com/jruby/jruby/issues/6547 is addressed
|
|
20
|
+
gem "i18n", "<= 1.8.7"
|
|
21
|
+
|
|
22
|
+
gem "pry"
|
|
23
|
+
gem "benchmark-ips"
|
|
24
|
+
gem "benchmark_driver"
|
|
25
|
+
gem "benchmark-ipsa"
|
|
26
|
+
gem "benchmark-memory"
|
|
27
|
+
gem "ruby-prof", platform: :mri
|
|
28
|
+
gem "rake", "> 12"
|
|
29
|
+
gem "rubocop", "~> 0.81.0"
|
|
30
|
+
gem "rspec", "~> 3.9.0"
|
|
31
|
+
gem "capybara", "~> 3.15.0" # rspec system tests
|
|
32
|
+
gem "puma" # rspec system tests
|
|
33
|
+
|
|
34
|
+
gem "timecop"
|
|
35
|
+
gem "test-unit"
|
|
36
|
+
gem "simplecov"
|
|
37
|
+
gem "codecov", "<= 0.2.12"
|
data/Makefile
ADDED
data/README.md
CHANGED
|
@@ -1,13 +1,44 @@
|
|
|
1
|
-
|
|
1
|
+
<p align="center">
|
|
2
|
+
<a href="https://sentry.io" target="_blank" align="center">
|
|
3
|
+
<img src="https://sentry-brand.storage.googleapis.com/sentry-logo-black.png" width="280">
|
|
4
|
+
</a>
|
|
5
|
+
<br>
|
|
6
|
+
</p>
|
|
7
|
+
|
|
8
|
+
# Raven-Ruby, the Ruby Client for Sentry
|
|
9
|
+
|
|
10
|
+
### 🚧 Migrating To The New SDK 🚧
|
|
11
|
+
|
|
12
|
+
We've released our new Ruby SDK, [sentry-ruby](https://github.com/getsentry/sentry-ruby/tree/master/sentry-ruby). Here are the benefits of migrating to it:
|
|
13
|
+
|
|
14
|
+
- **Unified Interfaces With Other SDKs:** The design of `sentry-raven` is outdated compared with our modern Sentry SDKs. If you also use other Sentry SDKs, such as Sentry's JavaScript SDK for your frontend application, you'll notice that their interfaces are quite different from the one provided for `sentry-raven`. The new `sentry-ruby` SDK provides a more consistent user experience across all different platforms.
|
|
15
|
+
|
|
16
|
+
- **Performance Monitoring:** The Sentry Ruby SDK includes [performance monitoring](https://docs.sentry.io/product/performance/), which you can enable if you haven't already as ([discussed here](https://docs.sentry.io/platforms/ruby/performance/)).
|
|
17
|
+
|
|
18
|
+
- **Future Support:** `sentry-raven` has entered maintenance mode, which means it won't receive any new feature supports or aggressive bug fixes.
|
|
19
|
+
|
|
20
|
+
- **Better Extensibility:** Unlike `sentry-raven`, `sentry-ruby` is built with extensibility in mind and will allow the community to build extensions for different integrations/features.
|
|
21
|
+
|
|
22
|
+
If you're interested in the migration, please also read our [migration guide](https://docs.sentry.io/platforms/ruby/migration/) for more information.
|
|
23
|
+
|
|
24
|
+
---
|
|
25
|
+
|
|
2
26
|
|
|
3
27
|
[](https://rubygems.org/gems/sentry-raven)
|
|
4
|
-
|
|
28
|
+

|
|
29
|
+
[](https://codecov.io/gh/getsentry/sentry-ruby/branch/master)
|
|
30
|
+
[](https://rubygems.org/gems/sentry-raven/)
|
|
31
|
+
[](https://dependabot.com/compatibility-score.html?dependency-name=sentry-raven&package-manager=bundler&version-scheme=semver)
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
[Documentation](https://docs.sentry.io/clients/ruby/) | [Bug Tracker](https://github.com/getsentry/raven-ruby/issues) | [Forum](https://forum.sentry.io/) | IRC: irc.freenode.net, #sentry
|
|
35
|
+
|
|
36
|
+
The official Ruby-language client and integration layer for the [Sentry](https://github.com/getsentry/sentry) error reporting API.
|
|
5
37
|
|
|
6
|
-
A client and integration layer for the [Sentry](https://github.com/getsentry/sentry) error reporting API.
|
|
7
38
|
|
|
8
39
|
## Requirements
|
|
9
40
|
|
|
10
|
-
We test on Ruby
|
|
41
|
+
We test on Ruby 2.3, 2.4, 2.5, 2.6 and 2.7 at the latest patchlevel/teeny version. We also support JRuby 9.0. Our Rails integration works with Rails 4.2+, including Rails 5 and Rails 6.
|
|
11
42
|
|
|
12
43
|
## Getting Started
|
|
13
44
|
|
|
@@ -17,30 +48,30 @@ We test on Ruby 1.9, 2.2 and 2.3 at the latest patchlevel/teeny version. Our Rai
|
|
|
17
48
|
gem "sentry-raven"
|
|
18
49
|
```
|
|
19
50
|
|
|
20
|
-
### Raven only runs when
|
|
51
|
+
### Raven only runs when Sentry DSN is set
|
|
21
52
|
|
|
22
53
|
Raven will capture and send exceptions to the Sentry server whenever its DSN is set. This makes environment-based configuration easy - if you don't want to send errors in a certain environment, just don't set the DSN in that environment!
|
|
23
54
|
|
|
24
55
|
```bash
|
|
25
56
|
# Set your SENTRY_DSN environment variable.
|
|
26
|
-
export SENTRY_DSN=http://public
|
|
57
|
+
export SENTRY_DSN=http://public@example.com/project-id
|
|
27
58
|
```
|
|
28
59
|
```ruby
|
|
29
|
-
# Or you can configure the client in the code
|
|
60
|
+
# Or you can configure the client in the code.
|
|
30
61
|
Raven.configure do |config|
|
|
31
|
-
config.dsn = 'http://public
|
|
62
|
+
config.dsn = 'http://public@example.com/project-id'
|
|
32
63
|
end
|
|
33
64
|
```
|
|
34
65
|
|
|
35
|
-
### Raven doesn't report some kinds of data by default
|
|
66
|
+
### Raven doesn't report some kinds of data by default
|
|
36
67
|
|
|
37
|
-
Raven ignores some exceptions by default - most of these are related to 404s or controller actions not being found. [For a complete list, see the `IGNORE_DEFAULT` constant](https://github.com/getsentry/raven-ruby/blob/master/lib/raven/configuration.rb).
|
|
68
|
+
**Raven ignores some exceptions by default** - most of these are related to 404s or controller actions not being found. [For a complete list, see the `IGNORE_DEFAULT` constant](https://github.com/getsentry/raven-ruby/blob/master/lib/raven/configuration.rb).
|
|
38
69
|
|
|
39
|
-
Raven doesn't report POST data or cookies by default. In addition, it will attempt to remove any obviously sensitive data, such as credit card or Social Security numbers. For more information about how Sentry processes your data, [check out the documentation on the `processors` config setting.](https://docs.
|
|
70
|
+
Raven doesn't report POST data or cookies by default. In addition, it will attempt to remove any obviously sensitive data, such as credit card or Social Security numbers. For more information about how Sentry processes your data, [check out the documentation on the `processors` config setting.](https://docs.sentry.io/platforms/ruby/configuration/options/)
|
|
40
71
|
|
|
41
|
-
###
|
|
72
|
+
### Usage
|
|
42
73
|
|
|
43
|
-
If you use Rails, you're already done - no more configuration required
|
|
74
|
+
**If you use Rails, you're already done - no more configuration required!** Check [Integrations](https://docs.sentry.io/platforms/ruby/configuration/integrations/) for more details on other gems Sentry integrates with automatically.
|
|
44
75
|
|
|
45
76
|
Otherwise, Raven supports two methods of capturing exceptions:
|
|
46
77
|
|
|
@@ -57,10 +88,77 @@ rescue ZeroDivisionError => exception
|
|
|
57
88
|
end
|
|
58
89
|
```
|
|
59
90
|
|
|
91
|
+
### More configuration
|
|
92
|
+
|
|
93
|
+
You're all set - but there's a few more settings you may want to know about too!
|
|
94
|
+
|
|
95
|
+
#### async
|
|
96
|
+
|
|
97
|
+
When an error or message occurs, the notification is immediately sent to Sentry. Raven can be configured to send asynchronously:
|
|
98
|
+
|
|
99
|
+
```ruby
|
|
100
|
+
config.async = lambda { |event|
|
|
101
|
+
Thread.new { Raven.send_event(event) }
|
|
102
|
+
}
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
Using a thread to send events will be adequate for truly parallel Ruby platforms such as JRuby, though the benefit on MRI/CRuby will be limited. If the async callback raises an exception, Raven will attempt to send synchronously.
|
|
106
|
+
|
|
107
|
+
Note that the naive example implementation has a major drawback - it can create an infinite number of threads. We recommend creating a background job, using your background job processor, that will send Sentry notifications in the background.
|
|
108
|
+
|
|
109
|
+
```ruby
|
|
110
|
+
config.async = lambda { |event| SentryJob.perform_later(event) }
|
|
111
|
+
|
|
112
|
+
class SentryJob < ActiveJob::Base
|
|
113
|
+
queue_as :default
|
|
114
|
+
|
|
115
|
+
def perform(event)
|
|
116
|
+
Raven.send_event(event)
|
|
117
|
+
end
|
|
118
|
+
end
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
#### transport_failure_callback
|
|
122
|
+
|
|
123
|
+
If Raven fails to send an event to Sentry for any reason (either the Sentry server has returned a 4XX or 5XX response), this Proc or lambda will be called.
|
|
124
|
+
|
|
125
|
+
```ruby
|
|
126
|
+
config.transport_failure_callback = lambda { |event, error|
|
|
127
|
+
AdminMailer.email_admins("Oh god, it's on fire because #{error.message}!", event).deliver_later
|
|
128
|
+
}
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
#### Context
|
|
132
|
+
|
|
133
|
+
Much of the usefulness of Sentry comes from additional context data with the events. Raven makes this very convenient by providing methods to set thread local context data that is then submitted automatically with all events:
|
|
134
|
+
|
|
135
|
+
```ruby
|
|
136
|
+
Raven.user_context email: 'foo@example.com'
|
|
137
|
+
|
|
138
|
+
Raven.tags_context interesting: 'yes'
|
|
139
|
+
|
|
140
|
+
Raven.extra_context additional_info: 'foo'
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
You can also use `tags_context` and `extra_context` to provide scoped information:
|
|
144
|
+
|
|
145
|
+
```ruby
|
|
146
|
+
Raven.tags_context(interesting: 'yes') do
|
|
147
|
+
# the `interesting: 'yes'` tag will only present in the requests sent inside the block
|
|
148
|
+
Raven.capture_exception(exception)
|
|
149
|
+
end
|
|
150
|
+
|
|
151
|
+
Raven.extra_context(additional_info: 'foo') do
|
|
152
|
+
# same as above, the `additional_info` will only present in this request
|
|
153
|
+
Raven.capture_exception(exception)
|
|
154
|
+
end
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
For more information, see [Context](https://docs.sentry.io/platforms/ruby/enriching-events/context/).
|
|
158
|
+
|
|
60
159
|
## More Information
|
|
61
160
|
|
|
62
|
-
* [Documentation](https://docs.
|
|
63
|
-
* [Bug Tracker](https://github.com/getsentry/raven-ruby/issues
|
|
64
|
-
* [
|
|
65
|
-
|
|
66
|
-
* [IRC](irc://irc.freenode.net/sentry>) (irc.freenode.net, #sentry)
|
|
161
|
+
* [Documentation](https://docs.sentry.io/clients/ruby/)
|
|
162
|
+
* [Bug Tracker](https://github.com/getsentry/raven-ruby/issues)
|
|
163
|
+
* [Forum](https://forum.sentry.io/)
|
|
164
|
+
- [Discord](https://discord.gg/ez5KZN7)
|
data/Rakefile
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
require 'rake'
|
|
2
|
+
require 'raven'
|
|
3
|
+
require 'rubygems/package_task'
|
|
4
|
+
require 'bundler/gem_tasks'
|
|
5
|
+
|
|
6
|
+
gemspec = Gem::Specification.load(Dir['*.gemspec'].first)
|
|
7
|
+
|
|
8
|
+
Gem::PackageTask.new(gemspec).define
|
|
9
|
+
|
|
10
|
+
begin
|
|
11
|
+
require 'rubygems'
|
|
12
|
+
require 'rspec/core/rake_task'
|
|
13
|
+
|
|
14
|
+
require 'rubocop/rake_task'
|
|
15
|
+
RuboCop::RakeTask.new(:rubocop) do |task|
|
|
16
|
+
task.patterns = ['lib/**/*.rb','spec/**/*.rb',]
|
|
17
|
+
task.options << '--display-cop-names'
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
RSpec::Core::RakeTask.new(:spec) do |spec|
|
|
21
|
+
spec.pattern = 'spec/**/*_spec.rb'
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
rescue LoadError
|
|
25
|
+
task :spec do
|
|
26
|
+
abort "Rspec is not available. bundle install to run unit tests"
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
task :default => [:rubocop, :spec]
|
data/exe/raven
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
#!/usr/bin/env ruby
|
|
2
|
+
|
|
3
|
+
require "raven"
|
|
4
|
+
require "raven/cli"
|
|
5
|
+
require "optparse"
|
|
6
|
+
|
|
7
|
+
parser = OptionParser.new do |opt|
|
|
8
|
+
opt.banner = "Usage: raven COMMAND [OPTIONS]"
|
|
9
|
+
opt.separator ""
|
|
10
|
+
opt.separator "Commands"
|
|
11
|
+
opt.separator " test: send a test event"
|
|
12
|
+
opt.separator ""
|
|
13
|
+
opt.separator "Options"
|
|
14
|
+
|
|
15
|
+
opt.on("-h", "--help", "help") do
|
|
16
|
+
puts parser
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
parser.parse!
|
|
21
|
+
|
|
22
|
+
case ARGV[0]
|
|
23
|
+
when "test"
|
|
24
|
+
dsn = ARGV[1] if ARGV.length > 1
|
|
25
|
+
if !dsn
|
|
26
|
+
puts "Usage: raven test <dsn>"
|
|
27
|
+
else
|
|
28
|
+
Raven::CLI.test(dsn)
|
|
29
|
+
end
|
|
30
|
+
else
|
|
31
|
+
puts parser
|
|
32
|
+
end
|
data/lib/raven/backtrace.rb
CHANGED
|
@@ -1,16 +1,22 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
## Inspired by Rails' and Airbrake's backtrace parsers.
|
|
2
4
|
|
|
3
5
|
module Raven
|
|
4
|
-
|
|
5
6
|
# Front end to parsing the backtrace for each notice
|
|
6
7
|
class Backtrace
|
|
7
8
|
# Handles backtrace parsing line by line
|
|
8
9
|
class Line
|
|
9
|
-
|
|
10
|
-
|
|
10
|
+
RB_EXTENSION = ".rb"
|
|
11
|
+
# regexp (optional leading X: on windows, or JRuby9000 class-prefix)
|
|
12
|
+
RUBY_INPUT_FORMAT = /
|
|
13
|
+
^ \s* (?: [a-zA-Z]: | uri:classloader: )? ([^:]+ | <.*>):
|
|
14
|
+
(\d+)
|
|
15
|
+
(?: :in \s `([^']+)')?$
|
|
16
|
+
/x.freeze
|
|
11
17
|
|
|
12
18
|
# org.jruby.runtime.callsite.CachingCallSite.call(CachingCallSite.java:170)
|
|
13
|
-
JAVA_INPUT_FORMAT =
|
|
19
|
+
JAVA_INPUT_FORMAT = /^(.+)\.([^\.]+)\(([^\:]+)\:(\d+)\)$/.freeze
|
|
14
20
|
|
|
15
21
|
# The file portion of the line (such as app/models/user.rb)
|
|
16
22
|
attr_reader :file
|
|
@@ -31,6 +37,7 @@ module Raven
|
|
|
31
37
|
ruby_match = unparsed_line.match(RUBY_INPUT_FORMAT)
|
|
32
38
|
if ruby_match
|
|
33
39
|
_, file, number, method = ruby_match.to_a
|
|
40
|
+
file.sub!(/\.class$/, RB_EXTENSION)
|
|
34
41
|
module_name = nil
|
|
35
42
|
else
|
|
36
43
|
java_match = unparsed_line.match(JAVA_INPUT_FORMAT)
|
|
@@ -47,7 +54,7 @@ module Raven
|
|
|
47
54
|
end
|
|
48
55
|
|
|
49
56
|
def in_app
|
|
50
|
-
if
|
|
57
|
+
if file =~ self.class.in_app_pattern
|
|
51
58
|
true
|
|
52
59
|
else
|
|
53
60
|
false
|
|
@@ -69,7 +76,7 @@ module Raven
|
|
|
69
76
|
|
|
70
77
|
def self.in_app_pattern
|
|
71
78
|
@in_app_pattern ||= begin
|
|
72
|
-
project_root = Raven.configuration.project_root
|
|
79
|
+
project_root = Raven.configuration.project_root&.to_s
|
|
73
80
|
Regexp.new("^(#{project_root}/)?#{Raven.configuration.app_dirs_pattern || APP_DIRS_PATTERN}")
|
|
74
81
|
end
|
|
75
82
|
end
|
|
@@ -79,7 +86,7 @@ module Raven
|
|
|
79
86
|
attr_writer :file, :number, :method, :module_name
|
|
80
87
|
end
|
|
81
88
|
|
|
82
|
-
APP_DIRS_PATTERN = /(bin|exe|app|config|lib|test)
|
|
89
|
+
APP_DIRS_PATTERN = /(bin|exe|app|config|lib|test)/.freeze
|
|
83
90
|
|
|
84
91
|
# holder for an Array of Backtrace::Line instances
|
|
85
92
|
attr_reader :lines
|
|
@@ -87,6 +94,8 @@ module Raven
|
|
|
87
94
|
def self.parse(backtrace, opts = {})
|
|
88
95
|
ruby_lines = backtrace.is_a?(Array) ? backtrace : backtrace.split(/\n\s*/)
|
|
89
96
|
|
|
97
|
+
ruby_lines = opts[:configuration].backtrace_cleanup_callback.call(ruby_lines) if opts[:configuration]&.backtrace_cleanup_callback
|
|
98
|
+
|
|
90
99
|
filters = opts[:filters] || []
|
|
91
100
|
filtered_lines = ruby_lines.to_a.map do |line|
|
|
92
101
|
filters.reduce(line) do |nested_line, proc|
|
|
@@ -106,7 +115,7 @@ module Raven
|
|
|
106
115
|
end
|
|
107
116
|
|
|
108
117
|
def inspect
|
|
109
|
-
"<Backtrace: " + lines.map(
|
|
118
|
+
"<Backtrace: " + lines.map(&:inspect).join(", ") + ">"
|
|
110
119
|
end
|
|
111
120
|
|
|
112
121
|
def to_s
|
data/lib/raven/base.rb
CHANGED
|
@@ -1,203 +1,63 @@
|
|
|
1
1
|
require 'raven/version'
|
|
2
|
+
require "raven/helpers/deprecation_helper"
|
|
3
|
+
require 'raven/core_ext/object/deep_dup'
|
|
2
4
|
require 'raven/backtrace'
|
|
5
|
+
require 'raven/breadcrumbs'
|
|
3
6
|
require 'raven/processor'
|
|
4
7
|
require 'raven/processor/sanitizedata'
|
|
5
8
|
require 'raven/processor/removecircularreferences'
|
|
6
9
|
require 'raven/processor/utf8conversion'
|
|
7
10
|
require 'raven/processor/cookies'
|
|
8
11
|
require 'raven/processor/post_data'
|
|
12
|
+
require 'raven/processor/http_headers'
|
|
9
13
|
require 'raven/configuration'
|
|
10
14
|
require 'raven/context'
|
|
11
15
|
require 'raven/client'
|
|
12
16
|
require 'raven/event'
|
|
17
|
+
require 'raven/linecache'
|
|
13
18
|
require 'raven/logger'
|
|
14
19
|
require 'raven/interfaces/message'
|
|
15
20
|
require 'raven/interfaces/exception'
|
|
16
21
|
require 'raven/interfaces/single_exception'
|
|
17
22
|
require 'raven/interfaces/stack_trace'
|
|
18
23
|
require 'raven/interfaces/http'
|
|
24
|
+
require 'raven/transports'
|
|
25
|
+
require 'raven/transports/http'
|
|
19
26
|
require 'raven/utils/deep_merge'
|
|
27
|
+
require 'raven/utils/real_ip'
|
|
28
|
+
require 'raven/utils/request_id'
|
|
29
|
+
require 'raven/utils/exception_cause_chain'
|
|
30
|
+
require 'raven/instance'
|
|
20
31
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
class << self
|
|
25
|
-
# The client object is responsible for delivering formatted data to the Sentry server.
|
|
26
|
-
# Must respond to #send. See Raven::Client.
|
|
27
|
-
attr_writer :client
|
|
28
|
-
|
|
29
|
-
# A Raven configuration object. Must act like a hash and return sensible
|
|
30
|
-
# values for all Raven configuration options. See Raven::Configuration.
|
|
31
|
-
attr_writer :configuration
|
|
32
|
-
|
|
33
|
-
def context
|
|
34
|
-
Context.current
|
|
35
|
-
end
|
|
36
|
-
|
|
37
|
-
def logger
|
|
38
|
-
@logger ||= Logger.new
|
|
39
|
-
end
|
|
40
|
-
|
|
41
|
-
# The configuration object.
|
|
42
|
-
# @see Raven.configure
|
|
43
|
-
def configuration
|
|
44
|
-
@configuration ||= Configuration.new
|
|
45
|
-
end
|
|
46
|
-
|
|
47
|
-
# The client object is responsible for delivering formatted data to the Sentry server.
|
|
48
|
-
def client
|
|
49
|
-
@client ||= Client.new(configuration)
|
|
50
|
-
end
|
|
51
|
-
|
|
52
|
-
# Tell the log that the client is good to go
|
|
53
|
-
def report_status
|
|
54
|
-
return if client.configuration.silence_ready
|
|
55
|
-
if client.configuration.send_in_current_environment?
|
|
56
|
-
logger.info "Raven #{VERSION} ready to catch errors"
|
|
57
|
-
else
|
|
58
|
-
logger.info "Raven #{VERSION} configured not to send errors."
|
|
59
|
-
end
|
|
60
|
-
end
|
|
61
|
-
alias_method :report_ready, :report_status
|
|
62
|
-
|
|
63
|
-
# Call this method to modify defaults in your initializers.
|
|
64
|
-
#
|
|
65
|
-
# @example
|
|
66
|
-
# Raven.configure do |config|
|
|
67
|
-
# config.server = 'http://...'
|
|
68
|
-
# end
|
|
69
|
-
def configure
|
|
70
|
-
yield(configuration) if block_given?
|
|
71
|
-
|
|
72
|
-
self.client = Client.new(configuration)
|
|
73
|
-
report_status
|
|
74
|
-
self.client
|
|
75
|
-
end
|
|
76
|
-
|
|
77
|
-
# Send an event to the configured Sentry server
|
|
78
|
-
#
|
|
79
|
-
# @example
|
|
80
|
-
# evt = Raven::Event.new(:message => "An error")
|
|
81
|
-
# Raven.send_event(evt)
|
|
82
|
-
def send_event(event)
|
|
83
|
-
client.send_event(event)
|
|
84
|
-
end
|
|
85
|
-
|
|
86
|
-
# Capture and process any exceptions from the given block, or globally if
|
|
87
|
-
# no block is given
|
|
88
|
-
#
|
|
89
|
-
# @example
|
|
90
|
-
# Raven.capture do
|
|
91
|
-
# MyApp.run
|
|
92
|
-
# end
|
|
93
|
-
def capture(options = {})
|
|
94
|
-
if block_given?
|
|
95
|
-
begin
|
|
96
|
-
yield
|
|
97
|
-
rescue Error
|
|
98
|
-
raise # Don't capture Raven errors
|
|
99
|
-
rescue Exception => e
|
|
100
|
-
capture_exception(e, options)
|
|
101
|
-
raise
|
|
102
|
-
end
|
|
103
|
-
else
|
|
104
|
-
install_at_exit_hook(options)
|
|
105
|
-
end
|
|
106
|
-
end
|
|
107
|
-
|
|
108
|
-
def capture_type(obj, options = {})
|
|
109
|
-
return false unless should_capture?(obj)
|
|
110
|
-
message_or_exc = obj.is_a?(String) ? "message" : "exception"
|
|
111
|
-
if (evt = Event.send("from_" + message_or_exc, obj, options))
|
|
112
|
-
yield evt if block_given?
|
|
113
|
-
if configuration.async?
|
|
114
|
-
configuration.async.call(evt)
|
|
115
|
-
else
|
|
116
|
-
send_event(evt)
|
|
117
|
-
end
|
|
118
|
-
Thread.current[:sentry_last_event_id] = evt.id
|
|
119
|
-
evt
|
|
120
|
-
end
|
|
121
|
-
end
|
|
122
|
-
alias_method :capture_message, :capture_type
|
|
123
|
-
alias_method :capture_exception, :capture_type
|
|
32
|
+
require 'forwardable'
|
|
33
|
+
require 'English'
|
|
124
34
|
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
end
|
|
128
|
-
|
|
129
|
-
def should_capture?(message_or_exc)
|
|
130
|
-
if configuration.should_capture
|
|
131
|
-
configuration.should_capture.call(*[message_or_exc])
|
|
132
|
-
else
|
|
133
|
-
true
|
|
134
|
-
end
|
|
135
|
-
end
|
|
35
|
+
module Raven
|
|
36
|
+
AVAILABLE_INTEGRATIONS = %w(delayed_job railties sidekiq rack rack-timeout rake).freeze
|
|
136
37
|
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
# together.
|
|
140
|
-
#
|
|
141
|
-
# The options (annotation) is treated the same as the ``options``
|
|
142
|
-
# parameter to ``capture_exception`` or ``Event.from_exception``, and
|
|
143
|
-
# can contain the same ``:user``, ``:tags``, etc. options as these
|
|
144
|
-
# methods.
|
|
145
|
-
#
|
|
146
|
-
# These will be merged with the ``options`` parameter to
|
|
147
|
-
# ``Event.from_exception`` at the top of execution.
|
|
148
|
-
#
|
|
149
|
-
# @example
|
|
150
|
-
# begin
|
|
151
|
-
# raise "Hello"
|
|
152
|
-
# rescue => exc
|
|
153
|
-
# Raven.annotate_exception(exc, :user => { 'id' => 1,
|
|
154
|
-
# 'email' => 'foo@example.com' })
|
|
155
|
-
# end
|
|
156
|
-
def annotate_exception(exc, options = {})
|
|
157
|
-
notes = (exc.instance_variable_defined?(:@__raven_context) && exc.instance_variable_get(:@__raven_context)) || {}
|
|
158
|
-
notes.merge!(options)
|
|
159
|
-
exc.instance_variable_set(:@__raven_context, notes)
|
|
160
|
-
exc
|
|
161
|
-
end
|
|
38
|
+
class Error < StandardError
|
|
39
|
+
end
|
|
162
40
|
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
# It is recommending that you send at least the ``id`` and ``email``
|
|
166
|
-
# values. All other values are arbitrary.
|
|
167
|
-
#
|
|
168
|
-
# @example
|
|
169
|
-
# Raven.user_context('id' => 1, 'email' => 'foo@example.com')
|
|
170
|
-
def user_context(options = nil)
|
|
171
|
-
self.context.user = options || {}
|
|
172
|
-
end
|
|
41
|
+
class << self
|
|
42
|
+
extend Forwardable
|
|
173
43
|
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
# Tags are key / value pairs which generally represent things like application version,
|
|
177
|
-
# environment, role, and server names.
|
|
178
|
-
#
|
|
179
|
-
# @example
|
|
180
|
-
# Raven.tags_context('my_custom_tag' => 'tag_value')
|
|
181
|
-
def tags_context(options = nil)
|
|
182
|
-
self.context.tags.merge!(options || {})
|
|
44
|
+
def instance
|
|
45
|
+
@instance ||= Raven::Instance.new
|
|
183
46
|
end
|
|
184
47
|
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
# @example
|
|
190
|
-
# Raven.extra_context('my_custom_data' => 'value')
|
|
191
|
-
def extra_context(options = nil)
|
|
192
|
-
self.context.extra.merge!(options || {})
|
|
193
|
-
end
|
|
48
|
+
def_delegators :instance, :client=, :configuration=, :context, :logger, :configuration,
|
|
49
|
+
:client, :report_status, :configure, :send_event, :capture, :capture_type,
|
|
50
|
+
:last_event_id, :annotate_exception, :user_context,
|
|
51
|
+
:tags_context, :extra_context, :rack_context, :breadcrumbs
|
|
194
52
|
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
53
|
+
def_delegator :instance, :report_status, :report_ready
|
|
54
|
+
def_delegator :instance, :capture_type, :capture_message
|
|
55
|
+
def_delegator :instance, :capture_type, :capture_exception
|
|
56
|
+
# For cross-language compatibility
|
|
57
|
+
def_delegator :instance, :capture_type, :captureException
|
|
58
|
+
def_delegator :instance, :capture_type, :captureMessage
|
|
59
|
+
def_delegator :instance, :annotate_exception, :annotateException
|
|
60
|
+
def_delegator :instance, :annotate_exception, :annotate
|
|
201
61
|
|
|
202
62
|
# Injects various integrations. Default behavior: inject all available integrations
|
|
203
63
|
def inject
|
|
@@ -214,7 +74,7 @@ module Raven
|
|
|
214
74
|
integrations_to_load = Raven::AVAILABLE_INTEGRATIONS & only_integrations
|
|
215
75
|
not_found_integrations = only_integrations - integrations_to_load
|
|
216
76
|
if not_found_integrations.any?
|
|
217
|
-
|
|
77
|
+
logger.warn "Integrations do not exist: #{not_found_integrations.join ', '}"
|
|
218
78
|
end
|
|
219
79
|
integrations_to_load &= Gem.loaded_specs.keys
|
|
220
80
|
# TODO(dcramer): integrations should have some additional checks baked-in
|
|
@@ -228,34 +88,25 @@ module Raven
|
|
|
228
88
|
|
|
229
89
|
def load_integration(integration)
|
|
230
90
|
require "raven/integrations/#{integration}"
|
|
231
|
-
rescue Exception =>
|
|
232
|
-
|
|
91
|
+
rescue Exception => e
|
|
92
|
+
logger.warn "Unable to load raven/integrations/#{integration}: #{e}"
|
|
233
93
|
end
|
|
234
94
|
|
|
235
|
-
def
|
|
236
|
-
return if opts[:to].nil?
|
|
95
|
+
def safely_prepend(module_name, opts = {})
|
|
96
|
+
return if opts[:to].nil? || opts[:from].nil?
|
|
97
|
+
|
|
237
98
|
if opts[:to].respond_to?(:prepend, true)
|
|
238
|
-
opts[:to].send(:prepend,
|
|
99
|
+
opts[:to].send(:prepend, opts[:from].const_get(module_name))
|
|
239
100
|
else
|
|
240
|
-
opts[:to].send(:include,
|
|
101
|
+
opts[:to].send(:include, opts[:from].const_get("Old" + module_name))
|
|
241
102
|
end
|
|
242
103
|
end
|
|
243
104
|
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
alias :annotateException :annotate_exception
|
|
248
|
-
alias :annotate :annotate_exception
|
|
105
|
+
def sys_command(command)
|
|
106
|
+
result = `#{command} 2>&1` rescue nil
|
|
107
|
+
return if result.nil? || result.empty? || ($CHILD_STATUS && $CHILD_STATUS.exitstatus != 0)
|
|
249
108
|
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
def install_at_exit_hook(options)
|
|
253
|
-
at_exit do
|
|
254
|
-
if $!
|
|
255
|
-
logger.debug "Caught a post-mortem exception: #{$!.inspect}"
|
|
256
|
-
capture_exception($!, options)
|
|
257
|
-
end
|
|
258
|
-
end
|
|
109
|
+
result.strip
|
|
259
110
|
end
|
|
260
111
|
end
|
|
261
112
|
end
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
module Raven
|
|
2
|
+
module Breadcrumbs
|
|
3
|
+
module ActiveSupportLogger
|
|
4
|
+
class << self
|
|
5
|
+
def add(name, started, _finished, _unique_id, data)
|
|
6
|
+
Raven.breadcrumbs.record do |crumb|
|
|
7
|
+
crumb.data = data
|
|
8
|
+
crumb.category = name
|
|
9
|
+
crumb.timestamp = started.to_i
|
|
10
|
+
end
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def inject
|
|
14
|
+
@subscriber = ::ActiveSupport::Notifications.subscribe(/.*/) do |name, started, finished, unique_id, data|
|
|
15
|
+
add(name, started, finished, unique_id, data)
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def detach
|
|
20
|
+
::ActiveSupport::Notifications.unsubscribe(@subscriber)
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|