sentry-raven 3.1.1 → 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 (163) hide show
  1. checksums.yaml +4 -4
  2. data/.craft.yml +9 -5
  3. data/.scripts/bump-version.rb +5 -0
  4. data/CHANGELOG.md +11 -0
  5. data/Gemfile +5 -1
  6. data/Makefile +3 -0
  7. data/README.md +19 -7
  8. data/lib/raven/base.rb +1 -0
  9. data/lib/raven/configuration.rb +0 -1
  10. data/lib/raven/event.rb +5 -1
  11. data/lib/raven/instance.rb +7 -1
  12. data/lib/raven/integrations/delayed_job.rb +1 -1
  13. data/lib/raven/integrations/rack.rb +2 -14
  14. data/lib/raven/transports/http.rb +2 -1
  15. data/lib/raven/utils/request_id.rb +16 -0
  16. data/lib/raven/version.rb +1 -1
  17. data/sentry-raven.gemspec +7 -0
  18. metadata +10 -148
  19. data/.github/ISSUE_TEMPLATE/bug_report.md +0 -32
  20. data/.github/pull_request_template.md +0 -16
  21. data/.github/workflows/test.yml +0 -92
  22. data/.github/workflows/zeus_upload.yml +0 -32
  23. data/.gitignore +0 -16
  24. data/.gitmodules +0 -0
  25. data/.rspec +0 -1
  26. data/.rubocop.yml +0 -112
  27. data/.scripts/bump-version.sh +0 -9
  28. data/CONTRIBUTING.md +0 -71
  29. data/sentry-ruby/.gitignore +0 -11
  30. data/sentry-ruby/.rspec +0 -3
  31. data/sentry-ruby/.travis.yml +0 -6
  32. data/sentry-ruby/CODE_OF_CONDUCT.md +0 -74
  33. data/sentry-ruby/Gemfile +0 -9
  34. data/sentry-ruby/LICENSE.txt +0 -21
  35. data/sentry-ruby/README.md +0 -44
  36. data/sentry-ruby/Rakefile +0 -6
  37. data/sentry-ruby/bin/console +0 -14
  38. data/sentry-ruby/bin/setup +0 -8
  39. data/sentry-ruby/examples/rails-6.0/.browserslistrc +0 -1
  40. data/sentry-ruby/examples/rails-6.0/.gitignore +0 -35
  41. data/sentry-ruby/examples/rails-6.0/Gemfile +0 -58
  42. data/sentry-ruby/examples/rails-6.0/README.md +0 -23
  43. data/sentry-ruby/examples/rails-6.0/Rakefile +0 -6
  44. data/sentry-ruby/examples/rails-6.0/app/assets/config/manifest.js +0 -2
  45. data/sentry-ruby/examples/rails-6.0/app/assets/images/.keep +0 -0
  46. data/sentry-ruby/examples/rails-6.0/app/assets/stylesheets/application.css +0 -15
  47. data/sentry-ruby/examples/rails-6.0/app/channels/application_cable/channel.rb +0 -4
  48. data/sentry-ruby/examples/rails-6.0/app/channels/application_cable/connection.rb +0 -4
  49. data/sentry-ruby/examples/rails-6.0/app/controllers/application_controller.rb +0 -2
  50. data/sentry-ruby/examples/rails-6.0/app/controllers/concerns/.keep +0 -0
  51. data/sentry-ruby/examples/rails-6.0/app/controllers/welcome_controller.rb +0 -23
  52. data/sentry-ruby/examples/rails-6.0/app/helpers/application_helper.rb +0 -2
  53. data/sentry-ruby/examples/rails-6.0/app/javascript/channels/consumer.js +0 -6
  54. data/sentry-ruby/examples/rails-6.0/app/javascript/channels/index.js +0 -5
  55. data/sentry-ruby/examples/rails-6.0/app/javascript/packs/application.js +0 -17
  56. data/sentry-ruby/examples/rails-6.0/app/jobs/application_job.rb +0 -7
  57. data/sentry-ruby/examples/rails-6.0/app/mailers/application_mailer.rb +0 -4
  58. data/sentry-ruby/examples/rails-6.0/app/models/application_record.rb +0 -3
  59. data/sentry-ruby/examples/rails-6.0/app/models/concerns/.keep +0 -0
  60. data/sentry-ruby/examples/rails-6.0/app/views/layouts/application.html.erb +0 -15
  61. data/sentry-ruby/examples/rails-6.0/app/views/layouts/mailer.html.erb +0 -13
  62. data/sentry-ruby/examples/rails-6.0/app/views/layouts/mailer.text.erb +0 -1
  63. data/sentry-ruby/examples/rails-6.0/app/views/welcome/report_demo.html.erb +0 -22
  64. data/sentry-ruby/examples/rails-6.0/app/views/welcome/view_error.html.erb +0 -1
  65. data/sentry-ruby/examples/rails-6.0/app/workers/error_worker.rb +0 -7
  66. data/sentry-ruby/examples/rails-6.0/babel.config.js +0 -72
  67. data/sentry-ruby/examples/rails-6.0/bin/bundle +0 -114
  68. data/sentry-ruby/examples/rails-6.0/bin/rails +0 -9
  69. data/sentry-ruby/examples/rails-6.0/bin/rake +0 -9
  70. data/sentry-ruby/examples/rails-6.0/bin/setup +0 -36
  71. data/sentry-ruby/examples/rails-6.0/bin/spring +0 -17
  72. data/sentry-ruby/examples/rails-6.0/bin/webpack +0 -18
  73. data/sentry-ruby/examples/rails-6.0/bin/webpack-dev-server +0 -18
  74. data/sentry-ruby/examples/rails-6.0/bin/yarn +0 -11
  75. data/sentry-ruby/examples/rails-6.0/config.ru +0 -5
  76. data/sentry-ruby/examples/rails-6.0/config/application.rb +0 -28
  77. data/sentry-ruby/examples/rails-6.0/config/boot.rb +0 -4
  78. data/sentry-ruby/examples/rails-6.0/config/cable.yml +0 -10
  79. data/sentry-ruby/examples/rails-6.0/config/credentials.yml.enc +0 -1
  80. data/sentry-ruby/examples/rails-6.0/config/database.yml +0 -25
  81. data/sentry-ruby/examples/rails-6.0/config/environment.rb +0 -5
  82. data/sentry-ruby/examples/rails-6.0/config/environments/development.rb +0 -62
  83. data/sentry-ruby/examples/rails-6.0/config/environments/production.rb +0 -112
  84. data/sentry-ruby/examples/rails-6.0/config/environments/test.rb +0 -48
  85. data/sentry-ruby/examples/rails-6.0/config/initializers/application_controller_renderer.rb +0 -8
  86. data/sentry-ruby/examples/rails-6.0/config/initializers/assets.rb +0 -14
  87. data/sentry-ruby/examples/rails-6.0/config/initializers/backtrace_silencers.rb +0 -7
  88. data/sentry-ruby/examples/rails-6.0/config/initializers/content_security_policy.rb +0 -30
  89. data/sentry-ruby/examples/rails-6.0/config/initializers/cookies_serializer.rb +0 -5
  90. data/sentry-ruby/examples/rails-6.0/config/initializers/filter_parameter_logging.rb +0 -4
  91. data/sentry-ruby/examples/rails-6.0/config/initializers/inflections.rb +0 -16
  92. data/sentry-ruby/examples/rails-6.0/config/initializers/mime_types.rb +0 -4
  93. data/sentry-ruby/examples/rails-6.0/config/initializers/wrap_parameters.rb +0 -14
  94. data/sentry-ruby/examples/rails-6.0/config/locales/en.yml +0 -33
  95. data/sentry-ruby/examples/rails-6.0/config/puma.rb +0 -38
  96. data/sentry-ruby/examples/rails-6.0/config/routes.rb +0 -10
  97. data/sentry-ruby/examples/rails-6.0/config/spring.rb +0 -6
  98. data/sentry-ruby/examples/rails-6.0/config/storage.yml +0 -34
  99. data/sentry-ruby/examples/rails-6.0/config/webpack/development.js +0 -5
  100. data/sentry-ruby/examples/rails-6.0/config/webpack/environment.js +0 -3
  101. data/sentry-ruby/examples/rails-6.0/config/webpack/production.js +0 -5
  102. data/sentry-ruby/examples/rails-6.0/config/webpack/test.js +0 -5
  103. data/sentry-ruby/examples/rails-6.0/config/webpacker.yml +0 -96
  104. data/sentry-ruby/examples/rails-6.0/db/seeds.rb +0 -7
  105. data/sentry-ruby/examples/rails-6.0/lib/assets/.keep +0 -0
  106. data/sentry-ruby/examples/rails-6.0/lib/tasks/.keep +0 -0
  107. data/sentry-ruby/examples/rails-6.0/package.json +0 -15
  108. data/sentry-ruby/examples/rails-6.0/postcss.config.js +0 -12
  109. data/sentry-ruby/examples/rails-6.0/public/404.html +0 -67
  110. data/sentry-ruby/examples/rails-6.0/public/422.html +0 -67
  111. data/sentry-ruby/examples/rails-6.0/public/500.html +0 -66
  112. data/sentry-ruby/examples/rails-6.0/public/apple-touch-icon-precomposed.png +0 -0
  113. data/sentry-ruby/examples/rails-6.0/public/apple-touch-icon.png +0 -0
  114. data/sentry-ruby/examples/rails-6.0/public/favicon.ico +0 -0
  115. data/sentry-ruby/examples/rails-6.0/public/robots.txt +0 -1
  116. data/sentry-ruby/examples/rails-6.0/storage/.keep +0 -0
  117. data/sentry-ruby/examples/rails-6.0/test/application_system_test_case.rb +0 -5
  118. data/sentry-ruby/examples/rails-6.0/test/channels/application_cable/connection_test.rb +0 -11
  119. data/sentry-ruby/examples/rails-6.0/test/controllers/.keep +0 -0
  120. data/sentry-ruby/examples/rails-6.0/test/fixtures/.keep +0 -0
  121. data/sentry-ruby/examples/rails-6.0/test/fixtures/files/.keep +0 -0
  122. data/sentry-ruby/examples/rails-6.0/test/helpers/.keep +0 -0
  123. data/sentry-ruby/examples/rails-6.0/test/integration/.keep +0 -0
  124. data/sentry-ruby/examples/rails-6.0/test/mailers/.keep +0 -0
  125. data/sentry-ruby/examples/rails-6.0/test/models/.keep +0 -0
  126. data/sentry-ruby/examples/rails-6.0/test/system/.keep +0 -0
  127. data/sentry-ruby/examples/rails-6.0/test/test_helper.rb +0 -13
  128. data/sentry-ruby/examples/rails-6.0/vendor/.keep +0 -0
  129. data/sentry-ruby/examples/rails-6.0/yarn.lock +0 -7508
  130. data/sentry-ruby/lib/sentry.rb +0 -16
  131. data/sentry-ruby/lib/sentry/backtrace.rb +0 -128
  132. data/sentry-ruby/lib/sentry/client.rb +0 -162
  133. data/sentry-ruby/lib/sentry/client/state.rb +0 -40
  134. data/sentry-ruby/lib/sentry/configuration.rb +0 -533
  135. data/sentry-ruby/lib/sentry/event.rb +0 -209
  136. data/sentry-ruby/lib/sentry/interface.rb +0 -31
  137. data/sentry-ruby/lib/sentry/interfaces/exception.rb +0 -15
  138. data/sentry-ruby/lib/sentry/interfaces/http.rb +0 -16
  139. data/sentry-ruby/lib/sentry/interfaces/message.rb +0 -18
  140. data/sentry-ruby/lib/sentry/interfaces/single_exception.rb +0 -14
  141. data/sentry-ruby/lib/sentry/interfaces/stack_trace.rb +0 -69
  142. data/sentry-ruby/lib/sentry/linecache.rb +0 -44
  143. data/sentry-ruby/lib/sentry/logger.rb +0 -20
  144. data/sentry-ruby/lib/sentry/transports.rb +0 -19
  145. data/sentry-ruby/lib/sentry/transports/dummy.rb +0 -16
  146. data/sentry-ruby/lib/sentry/transports/http.rb +0 -66
  147. data/sentry-ruby/lib/sentry/transports/stdout.rb +0 -20
  148. data/sentry-ruby/lib/sentry/utils/deep_merge.rb +0 -22
  149. data/sentry-ruby/lib/sentry/utils/exception_cause_chain.rb +0 -20
  150. data/sentry-ruby/lib/sentry/version.rb +0 -3
  151. data/sentry-ruby/sentry-ruby.gemspec +0 -26
  152. data/sentry-ruby/spec/sentry/backtrace_spec.rb +0 -38
  153. data/sentry-ruby/spec/sentry/client_spec.rb +0 -443
  154. data/sentry-ruby/spec/sentry/configuration_spec.rb +0 -400
  155. data/sentry-ruby/spec/sentry/event_spec.rb +0 -238
  156. data/sentry-ruby/spec/sentry/interface_spec.rb +0 -38
  157. data/sentry-ruby/spec/sentry/interfaces/stack_trace_spec.rb +0 -11
  158. data/sentry-ruby/spec/sentry/linecache_spec.rb +0 -40
  159. data/sentry-ruby/spec/sentry/transports/http_spec.rb +0 -57
  160. data/sentry-ruby/spec/sentry/transports/stdout_spec.rb +0 -11
  161. data/sentry-ruby/spec/sentry_spec.rb +0 -9
  162. data/sentry-ruby/spec/spec_helper.rb +0 -49
  163. data/sentry-ruby/spec/support/linecache.txt +0 -6
@@ -1,16 +0,0 @@
1
- require "sentry/configuration"
2
- require "sentry/logger"
3
- require "sentry/event"
4
- require "sentry/client"
5
-
6
- module Sentry
7
- class Error < StandardError
8
- end
9
-
10
- def self.sys_command(command)
11
- result = `#{command} 2>&1` rescue nil
12
- return if result.nil? || result.empty? || ($CHILD_STATUS && $CHILD_STATUS.exitstatus != 0)
13
-
14
- result.strip
15
- end
16
- end
@@ -1,128 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- ## Inspired by Rails' and Airbrake's backtrace parsers.
4
-
5
- module Sentry
6
- # Front end to parsing the backtrace for each notice
7
- class Backtrace
8
- # Handles backtrace parsing line by line
9
- class Line
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
17
-
18
- # org.jruby.runtime.callsite.CachingCallSite.call(CachingCallSite.java:170)
19
- JAVA_INPUT_FORMAT = /^(.+)\.([^\.]+)\(([^\:]+)\:(\d+)\)$/.freeze
20
-
21
- # The file portion of the line (such as app/models/user.rb)
22
- attr_reader :file
23
-
24
- # The line number portion of the line
25
- attr_reader :number
26
-
27
- # The method of the line (such as index)
28
- attr_reader :method
29
-
30
- # The module name (JRuby)
31
- attr_reader :module_name
32
-
33
- attr_reader :in_app_pattern
34
-
35
- # Parses a single line of a given backtrace
36
- # @param [String] unparsed_line The raw line from +caller+ or some backtrace
37
- # @return [Line] The parsed backtrace line
38
- def self.parse(unparsed_line, in_app_pattern)
39
- ruby_match = unparsed_line.match(RUBY_INPUT_FORMAT)
40
- if ruby_match
41
- _, file, number, method = ruby_match.to_a
42
- file.sub!(/\.class$/, RB_EXTENSION)
43
- module_name = nil
44
- else
45
- java_match = unparsed_line.match(JAVA_INPUT_FORMAT)
46
- _, module_name, method, file, number = java_match.to_a
47
- end
48
- new(file, number, method, module_name, in_app_pattern)
49
- end
50
-
51
- def initialize(file, number, method, module_name, in_app_pattern)
52
- @file = file
53
- @module_name = module_name
54
- @number = number.to_i
55
- @method = method
56
- @in_app_pattern = in_app_pattern
57
- end
58
-
59
- def in_app
60
- if file =~ in_app_pattern
61
- true
62
- else
63
- false
64
- end
65
- end
66
-
67
- # Reconstructs the line in a readable fashion
68
- def to_s
69
- "#{file}:#{number}:in `#{method}'"
70
- end
71
-
72
- def ==(other)
73
- to_s == other.to_s
74
- end
75
-
76
- def inspect
77
- "<Line:#{self}>"
78
- end
79
- end
80
-
81
- APP_DIRS_PATTERN = /(bin|exe|app|config|lib|test)/.freeze
82
-
83
- # holder for an Array of Backtrace::Line instances
84
- attr_reader :lines
85
- attr_reader :configuration
86
-
87
- def self.parse(backtrace, configuration:)
88
- ruby_lines = backtrace.is_a?(Array) ? backtrace : backtrace.split(/\n\s*/)
89
-
90
- ruby_lines = configuration.backtrace_cleanup_callback.call(ruby_lines) if configuration&.backtrace_cleanup_callback
91
-
92
- in_app_pattern ||= begin
93
- project_root = configuration.project_root&.to_s
94
- Regexp.new("^(#{project_root}/)?#{configuration.app_dirs_pattern || APP_DIRS_PATTERN}")
95
- end
96
-
97
- lines = ruby_lines.to_a.map do |unparsed_line|
98
- Line.parse(unparsed_line, in_app_pattern)
99
- end
100
-
101
- new(lines)
102
- end
103
-
104
- def initialize(lines)
105
- @lines = lines
106
- end
107
-
108
- def inspect
109
- "<Backtrace: " + lines.map(&:inspect).join(", ") + ">"
110
- end
111
-
112
- def to_s
113
- content = []
114
- lines.each do |line|
115
- content << line
116
- end
117
- content.join("\n")
118
- end
119
-
120
- def ==(other)
121
- if other.respond_to?(:lines)
122
- lines == other.lines
123
- else
124
- false
125
- end
126
- end
127
- end
128
- end
@@ -1,162 +0,0 @@
1
- require "json"
2
- require "base64"
3
- require "sentry/transports"
4
- require "sentry/client/state"
5
- require 'sentry/utils/deep_merge'
6
-
7
- module Sentry
8
- class Client
9
- PROTOCOL_VERSION = '5'
10
- USER_AGENT = "sentry-ruby/#{Sentry::VERSION}"
11
- CONTENT_TYPE = 'application/json'
12
-
13
- attr_reader :transport, :configuration
14
-
15
- def initialize(configuration)
16
- @configuration = configuration
17
- @state = State.new
18
- @transport = case configuration.scheme
19
- when 'http', 'https'
20
- Transports::HTTP.new(configuration)
21
- when 'stdout'
22
- Transports::Stdout.new(configuration)
23
- when 'dummy'
24
- Transports::Dummy.new(configuration)
25
- else
26
- fail "Unknown transport scheme '#{configuration.scheme}'"
27
- end
28
- end
29
-
30
- def event_from_exception(exception, message: nil, extra: {}, backtrace: [], checksum: nil, release: nil, fingerprint: [])
31
- options = {
32
- message: message,
33
- extra: extra,
34
- backtrace: backtrace,
35
- checksum: checksum,
36
- fingerprint: fingerprint,
37
- configuration: configuration,
38
- release: release
39
- }
40
-
41
- exception_context =
42
- if exception.instance_variable_defined?(:@__sentry_context)
43
- exception.instance_variable_get(:@__sentry_context)
44
- elsif exception.respond_to?(:sentry_context)
45
- exception.sentry_context
46
- else
47
- {}
48
- end
49
-
50
- options = Utils::DeepMergeHash.deep_merge(exception_context, options)
51
-
52
- return unless @configuration.exception_class_allowed?(exception)
53
-
54
- Event.new(**options) do |evt|
55
- evt.add_exception_interface(exception)
56
- end
57
- end
58
-
59
- def event_from_message(message, extra: {}, backtrace: [], level: :error)
60
- options = {
61
- message: message,
62
- extra: extra,
63
- backtrace: backtrace,
64
- configuration: configuration,
65
- level: level
66
- }
67
- Event.new(**options)
68
- end
69
-
70
- def generate_auth_header
71
- now = Time.now.to_i.to_s
72
- fields = {
73
- 'sentry_version' => PROTOCOL_VERSION,
74
- 'sentry_client' => USER_AGENT,
75
- 'sentry_timestamp' => now,
76
- 'sentry_key' => configuration.public_key
77
- }
78
- fields['sentry_secret'] = configuration.secret_key unless configuration.secret_key.nil?
79
- 'Sentry ' + fields.map { |key, value| "#{key}=#{value}" }.join(', ')
80
- end
81
-
82
- def send_event(event, hint = nil)
83
- return false unless configuration.sending_allowed?(event)
84
-
85
- event = configuration.before_send.call(event, hint) if configuration.before_send
86
- if event.nil?
87
- configuration.logger.info "Discarded event because before_send returned nil"
88
- return
89
- end
90
-
91
- # Convert to hash
92
- event = event.to_hash
93
-
94
- unless @state.should_try?
95
- failed_send(nil, event)
96
- return
97
- end
98
-
99
- event_id = event[:event_id] || event['event_id']
100
- configuration.logger.info "Sending event #{event_id} to Sentry"
101
-
102
- content_type, encoded_data = encode(event)
103
-
104
- begin
105
- transport.send_event(generate_auth_header, encoded_data,
106
- :content_type => content_type)
107
- successful_send
108
- rescue => e
109
- failed_send(e, event)
110
- return
111
- end
112
-
113
- event
114
- end
115
-
116
- private
117
-
118
- def encode(event)
119
- encoded = JSON.fast_generate(event.to_hash)
120
-
121
- case configuration.encoding
122
- when 'gzip'
123
- ['application/octet-stream', Base64.strict_encode64(Zlib::Deflate.deflate(encoded))]
124
- else
125
- ['application/json', encoded]
126
- end
127
- end
128
-
129
- def successful_send
130
- @state.success
131
- end
132
-
133
- def failed_send(e, event)
134
- if e # exception was raised
135
- @state.failure
136
- configuration.logger.warn "Unable to record event with remote Sentry server (#{e.class} - #{e.message}):\n#{e.backtrace[0..10].join("\n")}"
137
- else
138
- configuration.logger.warn "Not sending event due to previous failure(s)."
139
- end
140
- configuration.logger.warn("Failed to submit event: #{get_log_message(event)}")
141
-
142
- # configuration.transport_failure_callback can be false & nil
143
- configuration.transport_failure_callback.call(event, e) if configuration.transport_failure_callback # rubocop:disable Style/SafeNavigation
144
- end
145
-
146
- def get_log_message(event)
147
- (event && event[:message]) || (event && event['message']) || get_message_from_exception(event) || '<no message value>'
148
- end
149
-
150
- def get_message_from_exception(event)
151
- (
152
- event &&
153
- event[:exception] &&
154
- event[:exception][:values] &&
155
- event[:exception][:values][0] &&
156
- event[:exception][:values][0][:type] &&
157
- event[:exception][:values][0][:value] &&
158
- "#{event[:exception][:values][0][:type]}: #{event[:exception][:values][0][:value]}"
159
- )
160
- end
161
- end
162
- end
@@ -1,40 +0,0 @@
1
- module Sentry
2
- class Client
3
- class State
4
- def initialize
5
- reset
6
- end
7
-
8
- def should_try?
9
- return true if @status == :online
10
-
11
- interval = @retry_after || [@retry_number, 6].min**2
12
- return true if Time.now - @last_check >= interval
13
-
14
- false
15
- end
16
-
17
- def failure(retry_after = nil)
18
- @status = :error
19
- @retry_number += 1
20
- @last_check = Time.now
21
- @retry_after = retry_after
22
- end
23
-
24
- def success
25
- reset
26
- end
27
-
28
- def reset
29
- @status = :online
30
- @retry_number = 0
31
- @last_check = nil
32
- @retry_after = nil
33
- end
34
-
35
- def failed?
36
- @status == :error
37
- end
38
- end
39
- end
40
- end
@@ -1,533 +0,0 @@
1
- require "uri"
2
- require "sentry/utils/exception_cause_chain"
3
- require "sentry/linecache"
4
-
5
- module Sentry
6
- class Configuration
7
- # Directories to be recognized as part of your app. e.g. if you
8
- # have an `engines` dir at the root of your project, you may want
9
- # to set this to something like /(app|config|engines|lib)/
10
- attr_accessor :app_dirs_pattern
11
-
12
- # Provide an object that responds to `call` to send events asynchronously.
13
- # E.g.: lambda { |event| Thread.new { Sentry.send_event(event) } }
14
- attr_reader :async
15
- alias async? async
16
-
17
- # An array of breadcrumbs loggers to be used. Available options are:
18
- # - :sentry_logger
19
- # - :active_support_logger
20
- attr_reader :breadcrumbs_logger
21
-
22
- # Number of lines of code context to capture, or nil for none
23
- attr_accessor :context_lines
24
-
25
- # RACK_ENV by default.
26
- attr_reader :current_environment
27
-
28
- # Encoding type for event bodies. Must be :json or :gzip.
29
- attr_reader :encoding
30
-
31
- # Whitelist of environments that will send notifications to Sentry. Array of Strings.
32
- attr_accessor :environments
33
-
34
- # Logger 'progname's to exclude from breadcrumbs
35
- attr_accessor :exclude_loggers
36
-
37
- # Array of exception classes that should never be sent. See IGNORE_DEFAULT.
38
- # You should probably append to this rather than overwrite it.
39
- attr_accessor :excluded_exceptions
40
-
41
- # Boolean to check nested exceptions when deciding if to exclude. Defaults to false
42
- attr_accessor :inspect_exception_causes_for_exclusion
43
- alias inspect_exception_causes_for_exclusion? inspect_exception_causes_for_exclusion
44
-
45
- # DSN component - set automatically if DSN provided
46
- attr_accessor :host
47
-
48
- # The Faraday adapter to be used. Will default to Net::HTTP when not set.
49
- attr_accessor :http_adapter
50
-
51
- # A Proc yeilding the faraday builder allowing for further configuration
52
- # of the faraday adapter
53
- attr_accessor :faraday_builder
54
-
55
- # You may provide your own LineCache for matching paths with source files.
56
- # This may be useful if you need to get source code from places other than
57
- # the disk. See Sentry::LineCache for the required interface you must implement.
58
- attr_accessor :linecache
59
-
60
- # Logger used by Sentry. In Rails, this is the Rails logger, otherwise
61
- # Sentry provides its own Sentry::Logger.
62
- attr_accessor :logger
63
-
64
- # Timeout waiting for the Sentry server connection to open in seconds
65
- attr_accessor :open_timeout
66
-
67
- # DSN component - set automatically if DSN provided
68
- attr_accessor :path
69
-
70
- # DSN component - set automatically if DSN provided
71
- attr_accessor :port
72
-
73
- # Project ID number to send to the Sentry server
74
- # If you provide a DSN, this will be set automatically.
75
- attr_accessor :project_id
76
-
77
- # Project directory root for in_app detection. Could be Rails root, etc.
78
- # Set automatically for Rails.
79
- attr_reader :project_root
80
-
81
- # Proxy information to pass to the HTTP adapter (via Faraday)
82
- attr_accessor :proxy
83
-
84
- # Public key for authentication with the Sentry server
85
- # If you provide a DSN, this will be set automatically.
86
- attr_accessor :public_key
87
-
88
- # Turns on ActiveSupport breadcrumbs integration
89
- attr_reader :rails_activesupport_breadcrumbs
90
-
91
- # Rails catches exceptions in the ActionDispatch::ShowExceptions or
92
- # ActionDispatch::DebugExceptions middlewares, depending on the environment.
93
- # When `rails_report_rescued_exceptions` is true (it is by default), Sentry
94
- # will report exceptions even when they are rescued by these middlewares.
95
- attr_accessor :rails_report_rescued_exceptions
96
-
97
- # Release tag to be passed with every event sent to Sentry.
98
- # We automatically try to set this to a git SHA or Capistrano release.
99
- attr_accessor :release
100
-
101
- # The sampling factor to apply to events. A value of 0.0 will not send
102
- # any events, and a value of 1.0 will send 100% of events.
103
- attr_accessor :sample_rate
104
-
105
- # Boolean - sanitize values that look like credit card numbers
106
- attr_accessor :sanitize_credit_cards
107
-
108
- # By default, Sentry censors Hash values when their keys match things like
109
- # "secret", "password", etc. Provide an array of Strings that, when matched in
110
- # a hash key, will be censored and not sent to Sentry.
111
- attr_accessor :sanitize_fields
112
-
113
- # If you're sure you want to override the default sanitization values, you can
114
- # add to them to an array of Strings here, e.g. %w(authorization password)
115
- attr_accessor :sanitize_fields_excluded
116
-
117
- # Sanitize additional HTTP headers - only Authorization is removed by default.
118
- attr_accessor :sanitize_http_headers
119
-
120
- # DSN component - set automatically if DSN provided.
121
- # Otherwise, can be one of "http", "https", or "dummy"
122
- attr_accessor :scheme
123
-
124
- # a proc/lambda that takes an array of stack traces
125
- # it'll be used to silence (reduce) backtrace of the exception
126
- #
127
- # for example:
128
- #
129
- # ```ruby
130
- # Sentry.configuration.backtrace_cleanup_callback = lambda do |backtrace|
131
- # Rails.backtrace_cleaner.clean(backtrace)
132
- # end
133
- # ```
134
- #
135
- attr_accessor :backtrace_cleanup_callback
136
-
137
- # Secret key for authentication with the Sentry server
138
- # If you provide a DSN, this will be set automatically.
139
- #
140
- # This is deprecated and not necessary for newer Sentry installations any more.
141
- attr_accessor :secret_key
142
-
143
- # Include module versions in reports - boolean.
144
- attr_accessor :send_modules
145
-
146
- # Simple server string - set this to the DSN found on your Sentry settings.
147
- attr_reader :server
148
-
149
- attr_accessor :server_name
150
-
151
- # Provide a configurable callback to determine event capture.
152
- # Note that the object passed into the block will be a String (messages) or
153
- # an exception.
154
- # e.g. lambda { |exc_or_msg| exc_or_msg.some_attr == false }
155
- attr_reader :should_capture
156
-
157
- # Silences ready message when true.
158
- attr_accessor :silence_ready
159
-
160
- # SSL settings passed directly to Faraday's ssl option
161
- attr_accessor :ssl
162
-
163
- # The path to the SSL certificate file
164
- attr_accessor :ssl_ca_file
165
-
166
- # Should the SSL certificate of the server be verified?
167
- attr_accessor :ssl_verification
168
-
169
- # Default tags for events. Hash.
170
- attr_accessor :tags
171
-
172
- # Timeout when waiting for the server to return data in seconds.
173
- attr_accessor :timeout
174
-
175
- # Optional Proc, called when the Sentry server cannot be contacted for any reason
176
- # E.g. lambda { |event| Thread.new { MyJobProcessor.send_email(event) } }
177
- attr_reader :transport_failure_callback
178
-
179
- # Optional Proc, called before sending an event to the server/
180
- # E.g.: lambda { |event, hint| event }
181
- # E.g.: lambda { |event, hint| nil }
182
- # E.g.: lambda { |event, hint|
183
- # event[:message] = 'a'
184
- # event
185
- # }
186
- attr_reader :before_send
187
-
188
- # Errors object - an Array that contains error messages. See #
189
- attr_reader :errors
190
-
191
- # the dsn value, whether it's set via `config.dsn=` or `ENV["SENTRY_DSN"]`
192
- attr_reader :dsn
193
-
194
- # Most of these errors generate 4XX responses. In general, Sentry clients
195
- # only automatically report 5xx responses.
196
- IGNORE_DEFAULT = [
197
- 'AbstractController::ActionNotFound',
198
- 'ActionController::BadRequest',
199
- 'ActionController::InvalidAuthenticityToken',
200
- 'ActionController::InvalidCrossOriginRequest',
201
- 'ActionController::MethodNotAllowed',
202
- 'ActionController::NotImplemented',
203
- 'ActionController::ParameterMissing',
204
- 'ActionController::RoutingError',
205
- 'ActionController::UnknownAction',
206
- 'ActionController::UnknownFormat',
207
- 'ActionController::UnknownHttpMethod',
208
- 'ActionDispatch::Http::Parameters::ParseError',
209
- 'ActionView::MissingTemplate',
210
- 'ActiveJob::DeserializationError', # Can cause infinite loops
211
- 'ActiveRecord::RecordNotFound',
212
- 'CGI::Session::CookieStore::TamperedWithCookie',
213
- 'Mongoid::Errors::DocumentNotFound',
214
- 'Rack::QueryParser::InvalidParameterError',
215
- 'Rack::QueryParser::ParameterTypeError',
216
- 'Sinatra::NotFound'
217
- ].freeze
218
-
219
- HEROKU_DYNO_METADATA_MESSAGE = "You are running on Heroku but haven't enabled Dyno Metadata. For Sentry's "\
220
- "release detection to work correctly, please run `heroku labs:enable runtime-dyno-metadata`".freeze
221
-
222
- LOG_PREFIX = "** [Sentry] ".freeze
223
- MODULE_SEPARATOR = "::".freeze
224
-
225
- AVAILABLE_BREADCRUMBS_LOGGERS = [:sentry_logger, :active_support_logger].freeze
226
-
227
- def initialize
228
- self.async = false
229
- self.breadcrumbs_logger = []
230
- self.context_lines = 3
231
- self.current_environment = current_environment_from_env
232
- self.encoding = 'gzip'
233
- self.environments = []
234
- self.exclude_loggers = []
235
- self.excluded_exceptions = IGNORE_DEFAULT.dup
236
- self.inspect_exception_causes_for_exclusion = false
237
- self.linecache = ::Sentry::LineCache.new
238
- self.logger = ::Sentry::Logger.new(STDOUT)
239
- self.open_timeout = 1
240
- self.project_root = detect_project_root
241
- @rails_activesupport_breadcrumbs = false
242
-
243
- self.rails_report_rescued_exceptions = true
244
- self.release = detect_release
245
- self.sample_rate = 1.0
246
- self.sanitize_credit_cards = true
247
- self.sanitize_fields = []
248
- self.sanitize_fields_excluded = []
249
- self.sanitize_http_headers = []
250
- self.send_modules = true
251
- self.server = ENV['SENTRY_DSN']
252
- self.server_name = server_name_from_env
253
- self.should_capture = false
254
- self.ssl_verification = true
255
- self.tags = {}
256
- self.timeout = 2
257
- self.transport_failure_callback = false
258
- self.before_send = false
259
- end
260
-
261
- def server=(value)
262
- return if value.nil?
263
-
264
- @dsn = value
265
-
266
- uri = URI.parse(value)
267
- uri_path = uri.path.split('/')
268
-
269
- if uri.user
270
- # DSN-style string
271
- self.project_id = uri_path.pop
272
- self.public_key = uri.user
273
- self.secret_key = !(uri.password.nil? || uri.password.empty?) ? uri.password : nil
274
- end
275
-
276
- self.scheme = uri.scheme
277
- self.host = uri.host
278
- self.port = uri.port if uri.port
279
- self.path = uri_path.join('/')
280
-
281
- # For anyone who wants to read the base server string
282
- @server = "#{scheme}://#{host}"
283
- @server += ":#{port}" unless port == { 'http' => 80, 'https' => 443 }[scheme]
284
- @server += path
285
- end
286
- alias dsn= server=
287
-
288
- def encoding=(encoding)
289
- raise(Error, 'Unsupported encoding') unless %w(gzip json).include? encoding
290
-
291
- @encoding = encoding
292
- end
293
-
294
- def async=(value)
295
- unless value == false || value.respond_to?(:call)
296
- raise(ArgumentError, "async must be callable (or false to disable)")
297
- end
298
-
299
- @async = value
300
- end
301
-
302
- def breadcrumbs_logger=(logger)
303
- loggers =
304
- if logger.is_a?(Array)
305
- logger
306
- else
307
- unless AVAILABLE_BREADCRUMBS_LOGGERS.include?(logger)
308
- raise Sentry::Error, "Unsupported breadcrumbs logger. Supported loggers: #{AVAILABLE_BREADCRUMBS_LOGGERS}"
309
- end
310
-
311
- Array(logger)
312
- end
313
-
314
- require "raven/breadcrumbs/sentry_logger" if loggers.include?(:sentry_logger)
315
-
316
- @breadcrumbs_logger = logger
317
- end
318
-
319
- def transport_failure_callback=(value)
320
- unless value == false || value.respond_to?(:call)
321
- raise(ArgumentError, "transport_failure_callback must be callable (or false to disable)")
322
- end
323
-
324
- @transport_failure_callback = value
325
- end
326
-
327
- def should_capture=(value)
328
- unless value == false || value.respond_to?(:call)
329
- raise ArgumentError, "should_capture must be callable (or false to disable)"
330
- end
331
-
332
- @should_capture = value
333
- end
334
-
335
- def before_send=(value)
336
- unless value == false || value.respond_to?(:call)
337
- raise ArgumentError, "before_send must be callable (or false to disable)"
338
- end
339
-
340
- @before_send = value
341
- end
342
-
343
- # Allows config options to be read like a hash
344
- #
345
- # @param [Symbol] option Key for a given attribute
346
- def [](option)
347
- public_send(option)
348
- end
349
-
350
- def current_environment=(environment)
351
- @current_environment = environment.to_s
352
- end
353
-
354
- def capture_allowed?(message_or_exc = nil)
355
- @errors = []
356
-
357
- valid? &&
358
- capture_in_current_environment? &&
359
- capture_allowed_by_callback?(message_or_exc) &&
360
- sample_allowed?
361
- end
362
- # If we cannot capture, we cannot send.
363
- alias sending_allowed? capture_allowed?
364
-
365
- def error_messages
366
- @errors = [errors[0]] + errors[1..-1].map(&:downcase) # fix case of all but first
367
- errors.join(", ")
368
- end
369
-
370
- def project_root=(root_dir)
371
- @project_root = root_dir
372
- end
373
-
374
- def rails_activesupport_breadcrumbs=(val)
375
- DeprecationHelper.deprecate_old_breadcrumbs_configuration(:active_support_logger)
376
- @rails_activesupport_breadcrumbs = val
377
- end
378
-
379
- def exception_class_allowed?(exc)
380
- if exc.is_a?(Sentry::Error)
381
- # Try to prevent error reporting loops
382
- logger.debug "Refusing to capture Sentry error: #{exc.inspect}"
383
- false
384
- elsif excluded_exception?(exc)
385
- logger.debug "User excluded error: #{exc.inspect}"
386
- false
387
- else
388
- true
389
- end
390
- end
391
-
392
- def enabled_in_current_env?
393
- environments.empty? || environments.include?(current_environment)
394
- end
395
-
396
- private
397
-
398
- def detect_project_root
399
- if defined? Rails.root # we are in a Rails application
400
- Rails.root.to_s
401
- else
402
- Dir.pwd
403
- end
404
- end
405
-
406
- def detect_release
407
- detect_release_from_env ||
408
- detect_release_from_git ||
409
- detect_release_from_capistrano ||
410
- detect_release_from_heroku
411
- rescue => e
412
- logger.error "Error detecting release: #{e.message}"
413
- end
414
-
415
- def excluded_exception?(incoming_exception)
416
- excluded_exceptions.any? do |excluded_exception|
417
- matches_exception?(get_exception_class(excluded_exception), incoming_exception)
418
- end
419
- end
420
-
421
- def get_exception_class(x)
422
- x.is_a?(Module) ? x : qualified_const_get(x)
423
- end
424
-
425
- def matches_exception?(excluded_exception_class, incoming_exception)
426
- if inspect_exception_causes_for_exclusion?
427
- Sentry::Utils::ExceptionCauseChain.exception_to_array(incoming_exception).any? { |cause| excluded_exception_class === cause }
428
- else
429
- excluded_exception_class === incoming_exception
430
- end
431
- end
432
-
433
- # In Ruby <2.0 const_get can't lookup "SomeModule::SomeClass" in one go
434
- def qualified_const_get(x)
435
- x = x.to_s
436
- if !x.match(/::/)
437
- Object.const_get(x)
438
- else
439
- x.split(MODULE_SEPARATOR).reject(&:empty?).inject(Object) { |a, e| a.const_get(e) }
440
- end
441
- rescue NameError # There's no way to safely ask if a constant exist for an unknown string
442
- nil
443
- end
444
-
445
- def detect_release_from_heroku
446
- return unless running_on_heroku?
447
- return if ENV['CI']
448
- logger.warn(HEROKU_DYNO_METADATA_MESSAGE) && return unless ENV['HEROKU_SLUG_COMMIT']
449
-
450
- ENV['HEROKU_SLUG_COMMIT']
451
- end
452
-
453
- def running_on_heroku?
454
- File.directory?("/etc/heroku")
455
- end
456
-
457
- def detect_release_from_capistrano
458
- revision_file = File.join(project_root, 'REVISION')
459
- revision_log = File.join(project_root, '..', 'revisions.log')
460
-
461
- if File.exist?(revision_file)
462
- File.read(revision_file).strip
463
- elsif File.exist?(revision_log)
464
- File.open(revision_log).to_a.last.strip.sub(/.*as release ([0-9]+).*/, '\1')
465
- end
466
- end
467
-
468
- def detect_release_from_git
469
- Sentry.sys_command("git rev-parse --short HEAD") if File.directory?(".git")
470
- end
471
-
472
- def detect_release_from_env
473
- ENV['SENTRY_RELEASE']
474
- end
475
-
476
- def capture_in_current_environment?
477
- return true if enabled_in_current_env?
478
-
479
- @errors << "Not configured to send/capture in environment '#{current_environment}'"
480
- false
481
- end
482
-
483
- def capture_allowed_by_callback?(message_or_exc)
484
- return true if !should_capture || message_or_exc.nil? || should_capture.call(message_or_exc)
485
-
486
- @errors << "should_capture returned false"
487
- false
488
- end
489
-
490
- def valid?
491
- return true if %w(server host path public_key project_id).all? { |k| public_send(k) }
492
-
493
- if server
494
- %w(server host path public_key project_id).map do |key|
495
- @errors << "No #{key} specified" unless public_send(key)
496
- end
497
- else
498
- @errors << "DSN not set"
499
- end
500
- false
501
- end
502
-
503
- def sample_allowed?
504
- return true if sample_rate == 1.0
505
-
506
- if Random::DEFAULT.rand >= sample_rate
507
- @errors << "Excluded by random sample"
508
- false
509
- else
510
- true
511
- end
512
- end
513
-
514
- # Try to resolve the hostname to an FQDN, but fall back to whatever
515
- # the load name is.
516
- def resolve_hostname
517
- Socket.gethostname ||
518
- Socket.gethostbyname(hostname).first rescue server_name
519
- end
520
-
521
- def current_environment_from_env
522
- ENV['SENTRY_CURRENT_ENV'] || ENV['SENTRY_ENVIRONMENT'] || ENV['RAILS_ENV'] || ENV['RACK_ENV'] || 'default'
523
- end
524
-
525
- def server_name_from_env
526
- if running_on_heroku?
527
- ENV['DYNO']
528
- else
529
- resolve_hostname
530
- end
531
- end
532
- end
533
- end