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.
Files changed (69) hide show
  1. checksums.yaml +5 -5
  2. data/.craft.yml +19 -0
  3. data/.scripts/bump-version.rb +5 -0
  4. data/CHANGELOG.md +703 -0
  5. data/Gemfile +37 -0
  6. data/Makefile +3 -0
  7. data/README.md +116 -18
  8. data/Rakefile +30 -0
  9. data/exe/raven +32 -0
  10. data/lib/raven/backtrace.rb +17 -8
  11. data/lib/raven/base.rb +45 -194
  12. data/lib/raven/breadcrumbs/active_support_logger.rb +25 -0
  13. data/lib/raven/breadcrumbs/logger.rb +3 -0
  14. data/lib/raven/breadcrumbs/sentry_logger.rb +73 -0
  15. data/lib/raven/breadcrumbs.rb +76 -0
  16. data/lib/raven/cli.rb +31 -39
  17. data/lib/raven/client.rb +45 -32
  18. data/lib/raven/configuration.rb +427 -130
  19. data/lib/raven/context.rb +33 -6
  20. data/lib/raven/core_ext/object/deep_dup.rb +57 -0
  21. data/lib/raven/core_ext/object/duplicable.rb +153 -0
  22. data/lib/raven/event.rb +194 -206
  23. data/lib/raven/helpers/deprecation_helper.rb +17 -0
  24. data/lib/raven/instance.rb +249 -0
  25. data/lib/raven/integrations/delayed_job.rb +25 -23
  26. data/lib/raven/integrations/rack-timeout.rb +22 -0
  27. data/lib/raven/integrations/rack.rb +40 -24
  28. data/lib/raven/integrations/rails/active_job.rb +52 -20
  29. data/lib/raven/integrations/rails/backtrace_cleaner.rb +29 -0
  30. data/lib/raven/integrations/rails/controller_transaction.rb +13 -0
  31. data/lib/raven/integrations/rails/overrides/debug_exceptions_catcher.rb +2 -2
  32. data/lib/raven/integrations/rails.rb +39 -7
  33. data/lib/raven/integrations/rake.rb +7 -2
  34. data/lib/raven/integrations/sidekiq/cleanup_middleware.rb +13 -0
  35. data/lib/raven/integrations/sidekiq/error_handler.rb +38 -0
  36. data/lib/raven/integrations/sidekiq.rb +6 -48
  37. data/lib/raven/integrations/tasks.rb +1 -1
  38. data/lib/raven/interface.rb +25 -0
  39. data/lib/raven/interfaces/exception.rb +5 -8
  40. data/lib/raven/interfaces/http.rb +5 -12
  41. data/lib/raven/interfaces/message.rb +10 -6
  42. data/lib/raven/interfaces/single_exception.rb +1 -5
  43. data/lib/raven/interfaces/stack_trace.rb +23 -30
  44. data/lib/raven/linecache.rb +35 -23
  45. data/lib/raven/logger.rb +13 -16
  46. data/lib/raven/processor/cookies.rb +27 -7
  47. data/lib/raven/processor/http_headers.rb +55 -0
  48. data/lib/raven/processor/post_data.rb +16 -3
  49. data/lib/raven/processor/removecircularreferences.rb +12 -8
  50. data/lib/raven/processor/removestacktrace.rb +17 -6
  51. data/lib/raven/processor/sanitizedata.rb +92 -37
  52. data/lib/raven/processor/utf8conversion.rb +39 -14
  53. data/lib/raven/processor.rb +5 -1
  54. data/lib/raven/transports/http.rb +31 -22
  55. data/lib/raven/transports/stdout.rb +20 -0
  56. data/lib/raven/transports.rb +6 -10
  57. data/lib/raven/utils/context_filter.rb +42 -0
  58. data/lib/raven/utils/deep_merge.rb +6 -12
  59. data/lib/raven/utils/exception_cause_chain.rb +20 -0
  60. data/lib/raven/utils/real_ip.rb +62 -0
  61. data/lib/raven/utils/request_id.rb +16 -0
  62. data/lib/raven/version.rb +2 -1
  63. data/lib/sentry-raven-without-integrations.rb +6 -1
  64. data/lib/sentry_raven_without_integrations.rb +1 -0
  65. data/sentry-raven.gemspec +28 -0
  66. metadata +44 -127
  67. data/lib/raven/error.rb +0 -4
  68. data/lib/raven/interfaces.rb +0 -34
  69. 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
@@ -0,0 +1,3 @@
1
+ build:
2
+ bundle install
3
+ gem build sentry-raven.gemspec
data/README.md CHANGED
@@ -1,13 +1,44 @@
1
- # Raven-Ruby
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
  [![Gem Version](https://img.shields.io/gem/v/sentry-raven.svg)](https://rubygems.org/gems/sentry-raven)
4
- [![Build Status](https://img.shields.io/travis/getsentry/raven-ruby/master.svg)](https://travis-ci.org/getsentry/raven-ruby)
28
+ ![Build Status](https://github.com/getsentry/raven-ruby/workflows/Test/badge.svg)
29
+ [![Coverage Status](https://img.shields.io/codecov/c/github/getsentry/sentry-ruby/master?logo=codecov)](https://codecov.io/gh/getsentry/sentry-ruby/branch/master)
30
+ [![Gem](https://img.shields.io/gem/dt/sentry-raven.svg)](https://rubygems.org/gems/sentry-raven/)
31
+ [![SemVer](https://api.dependabot.com/badges/compatibility_score?dependency-name=sentry-raven&package-manager=bundler&version-scheme=semver)](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 1.9, 2.2 and 2.3 at the latest patchlevel/teeny version. Our Rails integration works with Rails 4.2+. JRuby support is experimental - check TravisCI to see if the build is passing or failing.
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 SENTRY_DSN is set
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:secret@example.com/project-id
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 (not recommended - keep your DSN secret!)
60
+ # Or you can configure the client in the code.
30
61
  Raven.configure do |config|
31
- config.dsn = 'http://public:secret@example.com/project-id'
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.getsentry.com/hosted/clients/ruby/config/)
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
- ### Call
72
+ ### Usage
42
73
 
43
- If you use Rails, you're already done - no more configuration required! Check [Integrations](https://docs.getsentry.com/hosted/clients/ruby/integrations/) for more details on other gems Sentry integrates with automatically.
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.getsentry.com/hosted/clients/ruby/)
63
- * [Bug Tracker](https://github.com/getsentry/raven-ruby/issues>)
64
- * [Code](https://github.com/getsentry/raven-ruby>)
65
- * [Mailing List](https://groups.google.com/group/getsentry>)
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
@@ -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
- # regexp (optionnally allowing leading X: for windows support)
10
- RUBY_INPUT_FORMAT = %r{^((?:[a-zA-Z]:)?[^:]+|<.*>):(\d+)(?::in `([^']+)')?$}
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 = %r{^(.+)\.([^\.]+)\(([^\:]+)\:(\d+)\)$}
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 self.file =~ self.class.in_app_pattern
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 && Raven.configuration.project_root.to_s
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(&inspect).join(", ") + ">"
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
- module Raven
22
- AVAILABLE_INTEGRATIONS = %w[delayed_job railties sidekiq rack rake].freeze
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
- def last_event_id
126
- Thread.current[:sentry_last_event_id]
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
- # Provides extra context to the exception prior to it being handled by
138
- # Raven. An exception can have multiple annotations, which are merged
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
- # Bind user context. Merges with existing context (if any).
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
- # Bind tags context. Merges with existing context (if any).
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
- # Bind extra context. Merges with existing context (if any).
186
- #
187
- # Extra context shows up as Additional Data within Sentry, and is completely arbitrary.
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
- def rack_context(env)
196
- if env.empty?
197
- env = nil
198
- end
199
- self.context.rack_env = env
200
- end
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
- self.logger.warn "Integrations do not exist: #{not_found_integrations.join ', '}"
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 => error
232
- self.logger.warn "Unable to load raven/integrations/#{integration}: #{error}"
91
+ rescue Exception => e
92
+ logger.warn "Unable to load raven/integrations/#{integration}: #{e}"
233
93
  end
234
94
 
235
- def rails_safely_prepend(module_name, opts = {})
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, Raven::Rails::Overrides.const_get(module_name))
99
+ opts[:to].send(:prepend, opts[:from].const_get(module_name))
239
100
  else
240
- opts[:to].send(:include, Raven::Rails::Overrides.const_get("Old" + module_name))
101
+ opts[:to].send(:include, opts[:from].const_get("Old" + module_name))
241
102
  end
242
103
  end
243
104
 
244
- # For cross-language compat
245
- alias :captureException :capture_exception
246
- alias :captureMessage :capture_message
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
- private
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
@@ -0,0 +1,3 @@
1
+ DeprecationHelper.deprecate_old_breadcrumbs_configuration(:sentry_logger)
2
+
3
+ require "raven/breadcrumbs/sentry_logger"