sentry-raven 3.1.1 → 3.1.2

Sign up to get free protection for your applications and to get access to all the features.
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