alec-gem 2.7.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 (79) hide show
  1. checksums.yaml +7 -0
  2. data/.rspec +1 -0
  3. data/.rubocop.yml +74 -0
  4. data/.travis.yml +47 -0
  5. data/Gemfile +38 -0
  6. data/Gemfile.lock +215 -0
  7. data/LICENSE +201 -0
  8. data/README.md +132 -0
  9. data/Rakefile +29 -0
  10. data/alec-gem.gemspec +22 -0
  11. data/changelog.md +442 -0
  12. data/docs/Makefile +130 -0
  13. data/docs/breadcrumbs.rst +51 -0
  14. data/docs/conf.py +228 -0
  15. data/docs/config.rst +260 -0
  16. data/docs/context.rst +141 -0
  17. data/docs/index.rst +113 -0
  18. data/docs/install.rst +40 -0
  19. data/docs/integrations/heroku.rst +11 -0
  20. data/docs/integrations/index.rst +59 -0
  21. data/docs/integrations/puma.rst +30 -0
  22. data/docs/integrations/rack.rst +27 -0
  23. data/docs/integrations/rails.rst +62 -0
  24. data/docs/make.bat +155 -0
  25. data/docs/processors.rst +124 -0
  26. data/docs/sentry-doc-config.json +31 -0
  27. data/docs/usage.rst +176 -0
  28. data/exe/raven +32 -0
  29. data/lib/raven.rb +3 -0
  30. data/lib/raven/backtrace.rb +137 -0
  31. data/lib/raven/base.rb +106 -0
  32. data/lib/raven/breadcrumbs.rb +76 -0
  33. data/lib/raven/breadcrumbs/activesupport.rb +19 -0
  34. data/lib/raven/breadcrumbs/logger.rb +93 -0
  35. data/lib/raven/cli.rb +59 -0
  36. data/lib/raven/client.rb +142 -0
  37. data/lib/raven/configuration.rb +434 -0
  38. data/lib/raven/context.rb +43 -0
  39. data/lib/raven/event.rb +259 -0
  40. data/lib/raven/instance.rb +221 -0
  41. data/lib/raven/integrations/delayed_job.rb +58 -0
  42. data/lib/raven/integrations/rack-timeout.rb +19 -0
  43. data/lib/raven/integrations/rack.rb +139 -0
  44. data/lib/raven/integrations/rails.rb +79 -0
  45. data/lib/raven/integrations/rails/active_job.rb +59 -0
  46. data/lib/raven/integrations/rails/controller_methods.rb +13 -0
  47. data/lib/raven/integrations/rails/controller_transaction.rb +13 -0
  48. data/lib/raven/integrations/rails/overrides/debug_exceptions_catcher.rb +31 -0
  49. data/lib/raven/integrations/rails/overrides/streaming_reporter.rb +23 -0
  50. data/lib/raven/integrations/railties.rb +1 -0
  51. data/lib/raven/integrations/rake.rb +18 -0
  52. data/lib/raven/integrations/sidekiq.rb +87 -0
  53. data/lib/raven/integrations/tasks.rb +11 -0
  54. data/lib/raven/interface.rb +25 -0
  55. data/lib/raven/interfaces/exception.rb +15 -0
  56. data/lib/raven/interfaces/http.rb +16 -0
  57. data/lib/raven/interfaces/message.rb +20 -0
  58. data/lib/raven/interfaces/single_exception.rb +14 -0
  59. data/lib/raven/interfaces/stack_trace.rb +69 -0
  60. data/lib/raven/linecache.rb +41 -0
  61. data/lib/raven/logger.rb +19 -0
  62. data/lib/raven/processor.rb +15 -0
  63. data/lib/raven/processor/cookies.rb +26 -0
  64. data/lib/raven/processor/http_headers.rb +55 -0
  65. data/lib/raven/processor/post_data.rb +22 -0
  66. data/lib/raven/processor/removecircularreferences.rb +17 -0
  67. data/lib/raven/processor/removestacktrace.rb +24 -0
  68. data/lib/raven/processor/sanitizedata.rb +88 -0
  69. data/lib/raven/processor/utf8conversion.rb +52 -0
  70. data/lib/raven/transports.rb +15 -0
  71. data/lib/raven/transports/dummy.rb +16 -0
  72. data/lib/raven/transports/http.rb +68 -0
  73. data/lib/raven/utils/deep_merge.rb +22 -0
  74. data/lib/raven/utils/real_ip.rb +62 -0
  75. data/lib/raven/version.rb +5 -0
  76. data/lib/sentry-raven-without-integrations.rb +1 -0
  77. data/lib/sentry-raven.rb +1 -0
  78. data/pkg/sentry-raven-2.7.2.gem +0 -0
  79. metadata +143 -0
@@ -0,0 +1,59 @@
1
+ module Raven
2
+ class CLI
3
+ def self.test(dsn = nil, silent = false, config = nil) # rubocop:disable all
4
+ config ||= Raven.configuration
5
+
6
+ config.logger = if silent
7
+ ::Logger.new(nil)
8
+ else
9
+ logger = ::Logger.new(STDOUT)
10
+ logger.formatter = proc do |_severity, _datetime, _progname, msg|
11
+ "-> #{msg}\n"
12
+ end
13
+ logger
14
+ end
15
+
16
+ config.timeout = 5
17
+ config.dsn = dsn if dsn
18
+
19
+ # wipe out env settings to ensure we send the event
20
+ unless config.capture_allowed?
21
+ env_name = config.environments.pop || 'production'
22
+ config.current_environment = env_name
23
+ end
24
+
25
+ instance = Raven::Instance.new(nil, config)
26
+
27
+ instance.logger.debug "Sending a test event:"
28
+ instance.logger.debug ""
29
+
30
+ begin
31
+ 1 / 0
32
+ rescue ZeroDivisionError => exception
33
+ evt = instance.capture_exception(exception)
34
+ end
35
+
36
+ if evt && !(evt.is_a? Thread)
37
+ if evt.is_a? Hash
38
+ instance.logger.debug "-> event ID: #{evt[:event_id]}"
39
+ else
40
+ instance.logger.debug "-> event ID: #{evt.id}"
41
+ end
42
+ elsif evt # async configuration
43
+ if evt.value.is_a? Hash
44
+ instance.logger.debug "-> event ID: #{evt.value[:event_id]}"
45
+ else
46
+ instance.logger.debug "-> event ID: #{evt.value.id}"
47
+ end
48
+ else
49
+ instance.logger.debug ""
50
+ instance.logger.debug "An error occurred while attempting to send the event."
51
+ exit 1
52
+ end
53
+
54
+ instance.logger.debug ""
55
+ instance.logger.debug "Done!"
56
+ evt
57
+ end
58
+ end
59
+ end
@@ -0,0 +1,142 @@
1
+ # frozen_string_literal: true
2
+ require 'base64'
3
+ require 'json'
4
+ require 'zlib'
5
+
6
+ module Raven
7
+ # Encodes events and sends them to the Sentry server.
8
+ class Client
9
+ PROTOCOL_VERSION = '5'.freeze
10
+ USER_AGENT = "raven-ruby/#{Raven::VERSION}".freeze
11
+ CONTENT_TYPE = 'application/json'.freeze
12
+
13
+ attr_accessor :configuration
14
+
15
+ def initialize(configuration)
16
+ @configuration = configuration
17
+ @processors = configuration.processors.map { |v| v.new(self) }
18
+ @state = ClientState.new
19
+ end
20
+
21
+ def send_event(event)
22
+ return false unless configuration.sending_allowed?(event)
23
+
24
+ # Convert to hash
25
+ event = event.to_hash
26
+
27
+ unless @state.should_try?
28
+ failed_send(nil, event)
29
+ return
30
+ end
31
+
32
+ configuration.logger.info "Sending event #{event[:event_id]} to Sentry"
33
+
34
+ content_type, encoded_data = encode(event)
35
+
36
+ begin
37
+ transport.send_event(generate_auth_header, encoded_data,
38
+ :content_type => content_type)
39
+ successful_send
40
+ rescue => e
41
+ failed_send(e, event)
42
+ return
43
+ end
44
+
45
+ event
46
+ end
47
+
48
+ def transport
49
+ @transport ||=
50
+ case configuration.scheme
51
+ when 'http', 'https'
52
+ Transports::HTTP.new(configuration)
53
+ when 'dummy'
54
+ Transports::Dummy.new(configuration)
55
+ else
56
+ fail "Unknown transport scheme '#{configuration.scheme}'"
57
+ end
58
+ end
59
+
60
+ private
61
+
62
+ def encode(event)
63
+ hash = @processors.reduce(event.to_hash) { |a, e| e.process(a) }
64
+ encoded = JSON.fast_generate(hash)
65
+
66
+ case configuration.encoding
67
+ when 'gzip'
68
+ ['application/octet-stream', Base64.strict_encode64(Zlib::Deflate.deflate(encoded))]
69
+ else
70
+ ['application/json', encoded]
71
+ end
72
+ end
73
+
74
+ def get_log_message(event)
75
+ (event && event[:message]) || '<no message value>'
76
+ end
77
+
78
+ def generate_auth_header
79
+ now = Time.now.to_i.to_s
80
+ fields = {
81
+ 'sentry_version' => PROTOCOL_VERSION,
82
+ 'sentry_client' => USER_AGENT,
83
+ 'sentry_timestamp' => now,
84
+ 'sentry_key' => configuration.public_key,
85
+ 'sentry_secret' => configuration.secret_key
86
+ }
87
+ 'Sentry ' + fields.map { |key, value| "#{key}=#{value}" }.join(', ')
88
+ end
89
+
90
+ def successful_send
91
+ @state.success
92
+ end
93
+
94
+ def failed_send(e, event)
95
+ @state.failure
96
+ if e # exception was raised
97
+ configuration.logger.error "Unable to record event with remote Sentry server (#{e.class} - #{e.message}):\n#{e.backtrace[0..10].join("\n")}"
98
+ else
99
+ configuration.logger.error "Not sending event due to previous failure(s)."
100
+ end
101
+ configuration.logger.error("Failed to submit event: #{get_log_message(event)}")
102
+ configuration.transport_failure_callback.call(event) if configuration.transport_failure_callback
103
+ end
104
+ end
105
+
106
+ class ClientState
107
+ def initialize
108
+ reset
109
+ end
110
+
111
+ def should_try?
112
+ return true if @status == :online
113
+
114
+ interval = @retry_after || [@retry_number, 6].min**2
115
+ return true if Time.now - @last_check >= interval
116
+
117
+ false
118
+ end
119
+
120
+ def failure(retry_after = nil)
121
+ @status = :error
122
+ @retry_number += 1
123
+ @last_check = Time.now
124
+ @retry_after = retry_after
125
+ end
126
+
127
+ def success
128
+ reset
129
+ end
130
+
131
+ def reset
132
+ @status = :online
133
+ @retry_number = 0
134
+ @last_check = nil
135
+ @retry_after = nil
136
+ end
137
+
138
+ def failed?
139
+ @status == :error
140
+ end
141
+ end
142
+ end
@@ -0,0 +1,434 @@
1
+ require 'uri'
2
+
3
+ module Raven
4
+ class Configuration
5
+ # Directories to be recognized as part of your app. e.g. if you
6
+ # have an `engines` dir at the root of your project, you may want
7
+ # to set this to something like /(app|config|engines|lib)/
8
+ attr_accessor :app_dirs_pattern
9
+
10
+ # Provide an object that responds to `call` to send events asynchronously.
11
+ # E.g.: lambda { |event| Thread.new { Raven.send_event(event) } }
12
+ attr_reader :async
13
+ alias async? async
14
+
15
+ # Number of lines of code context to capture, or nil for none
16
+ attr_accessor :context_lines
17
+
18
+ # RACK_ENV by default.
19
+ attr_reader :current_environment
20
+
21
+ # Encoding type for event bodies. Must be :json or :gzip.
22
+ attr_reader :encoding
23
+
24
+ # Whitelist of environments that will send notifications to Sentry. Array of Strings.
25
+ attr_accessor :environments
26
+
27
+ # Logger 'progname's to exclude from breadcrumbs
28
+ attr_accessor :exclude_loggers
29
+
30
+ # Array of exception classes that should never be sent. See IGNORE_DEFAULT.
31
+ # You should probably append to this rather than overwrite it.
32
+ attr_accessor :excluded_exceptions
33
+
34
+ # DSN component - set automatically if DSN provided
35
+ attr_accessor :host
36
+
37
+ # The Faraday adapter to be used. Will default to Net::HTTP when not set.
38
+ attr_accessor :http_adapter
39
+
40
+ # A Proc yeilding the faraday builder allowing for further configuration
41
+ # of the faraday adapter
42
+ attr_accessor :faraday_builder
43
+
44
+ # You may provide your own LineCache for matching paths with source files.
45
+ # This may be useful if you need to get source code from places other than
46
+ # the disk. See Raven::LineCache for the required interface you must implement.
47
+ attr_accessor :linecache
48
+
49
+ # Logger used by Raven. In Rails, this is the Rails logger, otherwise
50
+ # Raven provides its own Raven::Logger.
51
+ attr_accessor :logger
52
+
53
+ # Timeout waiting for the Sentry server connection to open in seconds
54
+ attr_accessor :open_timeout
55
+
56
+ # DSN component - set automatically if DSN provided
57
+ attr_accessor :path
58
+
59
+ # DSN component - set automatically if DSN provided
60
+ attr_accessor :port
61
+
62
+ # Processors to run on data before sending upstream. See DEFAULT_PROCESSORS.
63
+ # You should probably append to this rather than overwrite it.
64
+ attr_accessor :processors
65
+
66
+ # Project ID number to send to the Sentry server
67
+ # If you provide a DSN, this will be set automatically.
68
+ attr_accessor :project_id
69
+
70
+ # Project directory root for in_app detection. Could be Rails root, etc.
71
+ # Set automatically for Rails.
72
+ attr_reader :project_root
73
+
74
+ # Proxy information to pass to the HTTP adapter (via Faraday)
75
+ attr_accessor :proxy
76
+
77
+ # Public key for authentication with the Sentry server
78
+ # If you provide a DSN, this will be set automatically.
79
+ attr_accessor :public_key
80
+
81
+ # Turns on ActiveSupport breadcrumbs integration
82
+ attr_accessor :rails_activesupport_breadcrumbs
83
+
84
+ # Rails catches exceptions in the ActionDispatch::ShowExceptions or
85
+ # ActionDispatch::DebugExceptions middlewares, depending on the environment.
86
+ # When `rails_report_rescued_exceptions` is true (it is by default), Raven
87
+ # will report exceptions even when they are rescued by these middlewares.
88
+ attr_accessor :rails_report_rescued_exceptions
89
+
90
+ # Release tag to be passed with every event sent to Sentry.
91
+ # We automatically try to set this to a git SHA or Capistrano release.
92
+ attr_accessor :release
93
+
94
+ # The sampling factor to apply to events. A value of 0.0 will not send
95
+ # any events, and a value of 1.0 will send 100% of events.
96
+ attr_accessor :sample_rate
97
+
98
+ # Boolean - sanitize values that look like credit card numbers
99
+ attr_accessor :sanitize_credit_cards
100
+
101
+ # By default, Sentry censors Hash values when their keys match things like
102
+ # "secret", "password", etc. Provide an array of Strings that, when matched in
103
+ # a hash key, will be censored and not sent to Sentry.
104
+ attr_accessor :sanitize_fields
105
+
106
+ # If you're sure you want to override the default sanitization values, you can
107
+ # add to them to an array of Strings here, e.g. %w(authorization password)
108
+ attr_accessor :sanitize_fields_excluded
109
+
110
+ # Sanitize additional HTTP headers - only Authorization is removed by default.
111
+ attr_accessor :sanitize_http_headers
112
+
113
+ # DSN component - set automatically if DSN provided.
114
+ # Otherwise, can be one of "http", "https", or "dummy"
115
+ attr_accessor :scheme
116
+
117
+ # Secret key for authentication with the Sentry server
118
+ # If you provide a DSN, this will be set automatically.
119
+ attr_accessor :secret_key
120
+
121
+ # Include module versions in reports - boolean.
122
+ attr_accessor :send_modules
123
+
124
+ # Simple server string - set this to the DSN found on your Sentry settings.
125
+ attr_reader :server
126
+
127
+ attr_accessor :server_name
128
+
129
+ # Provide a configurable callback to determine event capture.
130
+ # Note that the object passed into the block will be a String (messages) or
131
+ # an exception.
132
+ # e.g. lambda { |exc_or_msg| exc_or_msg.some_attr == false }
133
+ attr_reader :should_capture
134
+
135
+ # Silences ready message when true.
136
+ attr_accessor :silence_ready
137
+
138
+ # SSL settings passed directly to Faraday's ssl option
139
+ attr_accessor :ssl
140
+
141
+ # The path to the SSL certificate file
142
+ attr_accessor :ssl_ca_file
143
+
144
+ # Should the SSL certificate of the server be verified?
145
+ attr_accessor :ssl_verification
146
+
147
+ # Default tags for events. Hash.
148
+ attr_accessor :tags
149
+
150
+ # Timeout when waiting for the server to return data in seconds.
151
+ attr_accessor :timeout
152
+
153
+ # Optional Proc, called when the Sentry server cannot be contacted for any reason
154
+ # E.g. lambda { |event| Thread.new { MyJobProcessor.send_email(event) } }
155
+ attr_reader :transport_failure_callback
156
+
157
+ # Errors object - an Array that contains error messages. See #
158
+ attr_reader :errors
159
+
160
+ IGNORE_DEFAULT = [
161
+ 'AbstractController::ActionNotFound',
162
+ 'ActionController::InvalidAuthenticityToken',
163
+ 'ActionController::RoutingError',
164
+ 'ActionController::UnknownAction',
165
+ 'ActiveRecord::RecordNotFound',
166
+ 'CGI::Session::CookieStore::TamperedWithCookie',
167
+ 'Mongoid::Errors::DocumentNotFound',
168
+ 'Sinatra::NotFound',
169
+ 'ActiveJob::DeserializationError'
170
+ ].freeze
171
+
172
+ # Note the order - we have to remove circular references and bad characters
173
+ # before passing to other processors.
174
+ DEFAULT_PROCESSORS = [
175
+ Raven::Processor::RemoveCircularReferences,
176
+ Raven::Processor::UTF8Conversion,
177
+ Raven::Processor::SanitizeData,
178
+ Raven::Processor::Cookies,
179
+ Raven::Processor::PostData,
180
+ Raven::Processor::HTTPHeaders
181
+ ].freeze
182
+
183
+ LOG_PREFIX = "** [Raven] ".freeze
184
+ MODULE_SEPARATOR = "::".freeze
185
+
186
+ def initialize
187
+ self.async = false
188
+ self.context_lines = 3
189
+ self.current_environment = current_environment_from_env
190
+ self.encoding = 'gzip'
191
+ self.environments = []
192
+ self.exclude_loggers = []
193
+ self.excluded_exceptions = IGNORE_DEFAULT.dup
194
+ self.linecache = ::Raven::LineCache.new
195
+ self.logger = ::Raven::Logger.new(STDOUT)
196
+ self.open_timeout = 1
197
+ self.processors = DEFAULT_PROCESSORS.dup
198
+ self.project_root = detect_project_root
199
+ self.rails_activesupport_breadcrumbs = false
200
+ self.rails_report_rescued_exceptions = true
201
+ self.release = detect_release
202
+ self.sample_rate = 1.0
203
+ self.sanitize_credit_cards = true
204
+ self.sanitize_fields = []
205
+ self.sanitize_fields_excluded = []
206
+ self.sanitize_http_headers = []
207
+ self.send_modules = true
208
+ self.server = ENV['SENTRY_DSN']
209
+ self.server_name = server_name_from_env
210
+ self.should_capture = false
211
+ self.ssl_verification = true
212
+ self.tags = {}
213
+ self.timeout = 2
214
+ self.transport_failure_callback = false
215
+ end
216
+
217
+ def server=(value)
218
+ return if value.nil?
219
+ uri = URI.parse(value)
220
+ uri_path = uri.path.split('/')
221
+
222
+ if uri.user
223
+ # DSN-style string
224
+ self.project_id = uri_path.pop
225
+ self.public_key = uri.user
226
+ self.secret_key = uri.password
227
+ end
228
+
229
+ self.scheme = uri.scheme
230
+ self.host = uri.host
231
+ self.port = uri.port if uri.port
232
+ self.path = uri_path.join('/')
233
+
234
+ # For anyone who wants to read the base server string
235
+ @server = "#{scheme}://#{host}"
236
+ @server << ":#{port}" unless port == { 'http' => 80, 'https' => 443 }[scheme]
237
+ @server << path
238
+ end
239
+ alias dsn= server=
240
+
241
+ def encoding=(encoding)
242
+ raise(Error, 'Unsupported encoding') unless %w(gzip json).include? encoding
243
+ @encoding = encoding
244
+ end
245
+
246
+ def async=(value)
247
+ unless value == false || value.respond_to?(:call)
248
+ raise(ArgumentError, "async must be callable (or false to disable)")
249
+ end
250
+ @async = value
251
+ end
252
+
253
+ def transport_failure_callback=(value)
254
+ unless value == false || value.respond_to?(:call)
255
+ raise(ArgumentError, "transport_failure_callback must be callable (or false to disable)")
256
+ end
257
+ @transport_failure_callback = value
258
+ end
259
+
260
+ def should_capture=(value)
261
+ unless value == false || value.respond_to?(:call)
262
+ raise ArgumentError, "should_capture must be callable (or false to disable)"
263
+ end
264
+ @should_capture = value
265
+ end
266
+
267
+ # Allows config options to be read like a hash
268
+ #
269
+ # @param [Symbol] option Key for a given attribute
270
+ def [](option)
271
+ public_send(option)
272
+ end
273
+
274
+ def current_environment=(environment)
275
+ @current_environment = environment.to_s
276
+ end
277
+
278
+ def capture_allowed?(message_or_exc = nil)
279
+ @errors = []
280
+
281
+ valid? &&
282
+ capture_in_current_environment? &&
283
+ capture_allowed_by_callback?(message_or_exc) &&
284
+ sample_allowed?
285
+ end
286
+ # If we cannot capture, we cannot send.
287
+ alias sending_allowed? capture_allowed?
288
+
289
+ def error_messages
290
+ @errors = [errors[0]] + errors[1..-1].map(&:downcase) # fix case of all but first
291
+ errors.join(", ")
292
+ end
293
+
294
+ def project_root=(root_dir)
295
+ @project_root = root_dir
296
+ Backtrace::Line.instance_variable_set(:@in_app_pattern, nil) # blow away cache
297
+ end
298
+
299
+ def exception_class_allowed?(exc)
300
+ if exc.is_a?(Raven::Error)
301
+ # Try to prevent error reporting loops
302
+ logger.debug "Refusing to capture Raven error: #{exc.inspect}"
303
+ false
304
+ elsif excluded_exception?(exc)
305
+ logger.debug "User excluded error: #{exc.inspect}"
306
+ false
307
+ else
308
+ true
309
+ end
310
+ end
311
+
312
+ private
313
+
314
+ def detect_project_root
315
+ if defined? Rails.root # we are in a Rails application
316
+ Rails.root.to_s
317
+ else
318
+ Dir.pwd
319
+ end
320
+ end
321
+
322
+ def detect_release
323
+ detect_release_from_git ||
324
+ detect_release_from_capistrano ||
325
+ detect_release_from_heroku
326
+ rescue => ex
327
+ logger.error "Error detecting release: #{ex.message}"
328
+ end
329
+
330
+ def excluded_exception?(exc)
331
+ excluded_exceptions.any? { |x| get_exception_class(x) === exc }
332
+ end
333
+
334
+ def get_exception_class(x)
335
+ x.is_a?(Module) ? x : qualified_const_get(x)
336
+ end
337
+
338
+ # In Ruby <2.0 const_get can't lookup "SomeModule::SomeClass" in one go
339
+ def qualified_const_get(x)
340
+ x = x.to_s
341
+ if !x.match(/::/)
342
+ Object.const_get(x)
343
+ else
344
+ x.split(MODULE_SEPARATOR).reject(&:empty?).inject(Object) { |a, e| a.const_get(e) }
345
+ end
346
+ rescue NameError # There's no way to safely ask if a constant exist for an unknown string
347
+ nil
348
+ end
349
+
350
+ def detect_release_from_heroku
351
+ return unless running_on_heroku?
352
+ logger.warn(heroku_dyno_metadata_message) && return unless ENV['HEROKU_SLUG_COMMIT']
353
+
354
+ ENV['HEROKU_SLUG_COMMIT']
355
+ end
356
+
357
+ def running_on_heroku?
358
+ File.directory?("/etc/heroku")
359
+ end
360
+
361
+ def heroku_dyno_metadata_message
362
+ "You are running on Heroku but haven't enabled Dyno Metadata. For Sentry's "\
363
+ "release detection to work correctly, please run `heroku labs:enable runtime-dyno-metadata`"
364
+ end
365
+
366
+ def detect_release_from_capistrano
367
+ revision_file = File.join(project_root, 'REVISION')
368
+ revision_log = File.join(project_root, '..', 'revisions.log')
369
+
370
+ if File.exist?(revision_file)
371
+ File.read(revision_file).strip
372
+ elsif File.exist?(revision_log)
373
+ File.open(revision_log).to_a.last.strip.sub(/.*as release ([0-9]+).*/, '\1')
374
+ end
375
+ end
376
+
377
+ def detect_release_from_git
378
+ Raven.sys_command("git rev-parse --short HEAD") if File.directory?(".git")
379
+ end
380
+
381
+ def capture_in_current_environment?
382
+ return true unless environments.any? && !environments.include?(current_environment)
383
+ @errors << "Not configured to send/capture in environment '#{current_environment}'"
384
+ false
385
+ end
386
+
387
+ def capture_allowed_by_callback?(message_or_exc)
388
+ return true if !should_capture || message_or_exc.nil? || should_capture.call(*[message_or_exc])
389
+ @errors << "should_capture returned false"
390
+ false
391
+ end
392
+
393
+ def valid?
394
+ return true if %w(server host path public_key secret_key project_id).all? { |k| public_send(k) }
395
+ if server
396
+ %w(server host path public_key secret_key project_id).map do |key|
397
+ @errors << "No #{key} specified" unless public_send(key)
398
+ end
399
+ else
400
+ @errors << "DSN not set"
401
+ end
402
+ false
403
+ end
404
+
405
+ def sample_allowed?
406
+ return true if sample_rate == 1.0
407
+ if Random::DEFAULT.rand >= sample_rate
408
+ @errors << "Excluded by random sample"
409
+ false
410
+ else
411
+ true
412
+ end
413
+ end
414
+
415
+ # Try to resolve the hostname to an FQDN, but fall back to whatever
416
+ # the load name is.
417
+ def resolve_hostname
418
+ Socket.gethostname ||
419
+ Socket.gethostbyname(hostname).first rescue server_name
420
+ end
421
+
422
+ def current_environment_from_env
423
+ ENV['SENTRY_CURRENT_ENV'] || ENV['RAILS_ENV'] || ENV['RACK_ENV'] || 'default'
424
+ end
425
+
426
+ def server_name_from_env
427
+ if running_on_heroku?
428
+ ENV['DYNO']
429
+ else
430
+ resolve_hostname
431
+ end
432
+ end
433
+ end
434
+ end