sentry-raven 1.2.3 → 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/lib/raven/backtrace.rb +3 -4
- data/lib/raven/base.rb +5 -4
- data/lib/raven/cli.rb +3 -3
- data/lib/raven/client.rb +3 -3
- data/lib/raven/configuration.rb +159 -133
- data/lib/raven/event.rb +32 -24
- data/lib/raven/instance.rb +9 -2
- data/lib/raven/integrations/delayed_job.rb +7 -8
- data/lib/raven/integrations/rack-timeout.rb +16 -0
- data/lib/raven/integrations/rack.rb +2 -3
- data/lib/raven/integrations/rails/active_job.rb +1 -1
- data/lib/raven/integrations/rake.rb +1 -1
- data/lib/raven/integrations/sidekiq.rb +4 -4
- data/lib/raven/interfaces.rb +1 -3
- data/lib/raven/interfaces/exception.rb +1 -3
- data/lib/raven/interfaces/single_exception.rb +1 -3
- data/lib/raven/interfaces/stack_trace.rb +8 -8
- data/lib/raven/linecache.rb +1 -6
- data/lib/raven/logger.rb +1 -1
- data/lib/raven/processor.rb +4 -0
- data/lib/raven/processor/cookies.rb +2 -2
- data/lib/raven/processor/http_headers.rb +42 -0
- data/lib/raven/processor/post_data.rb +1 -1
- data/lib/raven/processor/sanitizedata.rb +9 -14
- data/lib/raven/transports.rb +2 -2
- data/lib/raven/utils/real_ip.rb +62 -0
- data/lib/raven/version.rb +1 -1
- metadata +5 -3
- data/lib/raven/processor/truncator.rb +0 -22
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 44601f24d6796ddf4c83b31e84b4bce0bebda016
|
4
|
+
data.tar.gz: e06fca1cc97d57477771fabd6b8a05a0d8ac0192
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 007530478a48c41c6d61ce78cb776a73e78935c8cedeb8232a0acee4d9356a616ffaf71f679cadb79c141b1a27c9e99ec73449539c44b48b332f83f0cea0f9ac
|
7
|
+
data.tar.gz: e3c28440058749694dba1637d8da5d374e753b44189416a19411dda21b3ec082caca521e2643001ee4292954b4b15572621f2dbcc745da5cc687552a6ec4b121
|
data/lib/raven/backtrace.rb
CHANGED
@@ -1,16 +1,15 @@
|
|
1
1
|
## Inspired by Rails' and Airbrake's backtrace parsers.
|
2
2
|
|
3
3
|
module Raven
|
4
|
-
|
5
4
|
# Front end to parsing the backtrace for each notice
|
6
5
|
class Backtrace
|
7
6
|
# Handles backtrace parsing line by line
|
8
7
|
class Line
|
9
8
|
# regexp (optionnally allowing leading X: for windows support)
|
10
|
-
RUBY_INPUT_FORMAT =
|
9
|
+
RUBY_INPUT_FORMAT = /^((?:[a-zA-Z]:)?[^:]+|<.*>):(\d+)(?::in `([^']+)')?$/
|
11
10
|
|
12
11
|
# org.jruby.runtime.callsite.CachingCallSite.call(CachingCallSite.java:170)
|
13
|
-
JAVA_INPUT_FORMAT =
|
12
|
+
JAVA_INPUT_FORMAT = /^(.+)\.([^\.]+)\(([^\:]+)\:(\d+)\)$/
|
14
13
|
|
15
14
|
# The file portion of the line (such as app/models/user.rb)
|
16
15
|
attr_reader :file
|
@@ -47,7 +46,7 @@ module Raven
|
|
47
46
|
end
|
48
47
|
|
49
48
|
def in_app
|
50
|
-
if
|
49
|
+
if file =~ self.class.in_app_pattern
|
51
50
|
true
|
52
51
|
else
|
53
52
|
false
|
data/lib/raven/base.rb
CHANGED
@@ -7,7 +7,7 @@ require 'raven/processor/removecircularreferences'
|
|
7
7
|
require 'raven/processor/utf8conversion'
|
8
8
|
require 'raven/processor/cookies'
|
9
9
|
require 'raven/processor/post_data'
|
10
|
-
require 'raven/processor/
|
10
|
+
require 'raven/processor/http_headers'
|
11
11
|
require 'raven/configuration'
|
12
12
|
require 'raven/context'
|
13
13
|
require 'raven/client'
|
@@ -19,13 +19,14 @@ require 'raven/interfaces/single_exception'
|
|
19
19
|
require 'raven/interfaces/stack_trace'
|
20
20
|
require 'raven/interfaces/http'
|
21
21
|
require 'raven/utils/deep_merge'
|
22
|
+
require 'raven/utils/real_ip'
|
22
23
|
require 'raven/instance'
|
23
24
|
|
24
25
|
require 'forwardable'
|
25
26
|
require 'English'
|
26
27
|
|
27
28
|
module Raven
|
28
|
-
AVAILABLE_INTEGRATIONS = %w
|
29
|
+
AVAILABLE_INTEGRATIONS = %w(delayed_job railties sidekiq rack rack-timeout rake).freeze
|
29
30
|
|
30
31
|
class << self
|
31
32
|
extend Forwardable
|
@@ -63,7 +64,7 @@ module Raven
|
|
63
64
|
integrations_to_load = Raven::AVAILABLE_INTEGRATIONS & only_integrations
|
64
65
|
not_found_integrations = only_integrations - integrations_to_load
|
65
66
|
if not_found_integrations.any?
|
66
|
-
|
67
|
+
logger.warn "Integrations do not exist: #{not_found_integrations.join ', '}"
|
67
68
|
end
|
68
69
|
integrations_to_load &= Gem.loaded_specs.keys
|
69
70
|
# TODO(dcramer): integrations should have some additional checks baked-in
|
@@ -78,7 +79,7 @@ module Raven
|
|
78
79
|
def load_integration(integration)
|
79
80
|
require "raven/integrations/#{integration}"
|
80
81
|
rescue Exception => error
|
81
|
-
|
82
|
+
logger.warn "Unable to load raven/integrations/#{integration}: #{error}"
|
82
83
|
end
|
83
84
|
|
84
85
|
def safely_prepend(module_name, opts = {})
|
data/lib/raven/cli.rb
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
module Raven
|
2
2
|
class CLI
|
3
|
-
def self.test(dsn = nil, silent = false)
|
3
|
+
def self.test(dsn = nil, silent = false) # rubocop:disable all
|
4
4
|
if silent
|
5
5
|
Raven.configuration.logger = ::Logger.new(nil)
|
6
6
|
else
|
@@ -17,7 +17,7 @@ module Raven
|
|
17
17
|
Raven.configuration.dsn = dsn if dsn
|
18
18
|
|
19
19
|
# wipe out env settings to ensure we send the event
|
20
|
-
unless Raven.configuration.
|
20
|
+
unless Raven.configuration.capture_allowed?
|
21
21
|
env_name = Raven.configuration.environments.pop || 'production'
|
22
22
|
Raven.logger.debug "Setting environment to #{env_name}"
|
23
23
|
Raven.configuration.current_environment = env_name
|
@@ -40,7 +40,7 @@ module Raven
|
|
40
40
|
else
|
41
41
|
Raven.logger.debug "-> event ID: #{evt.id}"
|
42
42
|
end
|
43
|
-
elsif evt #async configuration
|
43
|
+
elsif evt # async configuration
|
44
44
|
if evt.value.is_a? Hash
|
45
45
|
Raven.logger.debug "-> event ID: #{evt.value[:event_id]}"
|
46
46
|
else
|
data/lib/raven/client.rb
CHANGED
@@ -38,7 +38,7 @@ module Raven
|
|
38
38
|
|
39
39
|
begin
|
40
40
|
transport.send_event(generate_auth_header, encoded_data,
|
41
|
-
|
41
|
+
:content_type => content_type)
|
42
42
|
successful_send
|
43
43
|
rescue => e
|
44
44
|
failed_send(e, event)
|
@@ -63,7 +63,7 @@ module Raven
|
|
63
63
|
private
|
64
64
|
|
65
65
|
def encode(event)
|
66
|
-
hash = @processors.reduce(event.to_hash) { |
|
66
|
+
hash = @processors.reduce(event.to_hash) { |a, e| e.process(a) }
|
67
67
|
encoded = JSON.generate(hash)
|
68
68
|
|
69
69
|
case configuration.encoding
|
@@ -115,7 +115,7 @@ module Raven
|
|
115
115
|
def should_try?
|
116
116
|
return true if @status == :online
|
117
117
|
|
118
|
-
interval = @retry_after || [@retry_number, 6].min
|
118
|
+
interval = @retry_after || [@retry_number, 6].min**2
|
119
119
|
return true if Time.now - @last_check >= interval
|
120
120
|
|
121
121
|
false
|
data/lib/raven/configuration.rb
CHANGED
@@ -3,120 +3,140 @@ require 'uri'
|
|
3
3
|
|
4
4
|
module Raven
|
5
5
|
class Configuration
|
6
|
-
#
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
attr_accessor :public_key
|
11
|
-
|
12
|
-
# Secret key for authentication with the Sentry server
|
13
|
-
attr_accessor :secret_key
|
6
|
+
# Directories to be recognized as part of your app. e.g. if you
|
7
|
+
# have an `engines` dir at the root of your project, you may want
|
8
|
+
# to set this to something like /(app|config|engines|lib)/
|
9
|
+
attr_accessor :app_dirs_pattern
|
14
10
|
|
15
|
-
#
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
attr_accessor :path
|
11
|
+
# Provide an object that responds to `call` to send events asynchronously.
|
12
|
+
# E.g.: lambda { |event| Thread.new { Raven.send_event(event) } }
|
13
|
+
attr_reader :async
|
14
|
+
alias async? async
|
20
15
|
|
21
|
-
#
|
22
|
-
attr_accessor :
|
16
|
+
# Number of lines of code context to capture, or nil for none
|
17
|
+
attr_accessor :context_lines
|
23
18
|
|
24
|
-
#
|
25
|
-
attr_reader :
|
19
|
+
# RACK_ENV by default.
|
20
|
+
attr_reader :current_environment
|
26
21
|
|
27
|
-
# Encoding type for event bodies
|
22
|
+
# Encoding type for event bodies. Must be :json or :gzip.
|
28
23
|
attr_reader :encoding
|
29
24
|
|
30
|
-
#
|
31
|
-
attr_accessor :logger
|
32
|
-
|
33
|
-
# Silence ready message
|
34
|
-
attr_accessor :silence_ready
|
35
|
-
|
36
|
-
# Number of lines of code context to capture, or nil for none
|
37
|
-
attr_accessor :context_lines
|
38
|
-
|
39
|
-
# Whitelist of environments that will send notifications to Sentry
|
25
|
+
# Whitelist of environments that will send notifications to Sentry. Array of Strings.
|
40
26
|
attr_accessor :environments
|
41
27
|
|
42
|
-
#
|
43
|
-
attr_accessor :
|
28
|
+
# Logger 'progname's to exclude from breadcrumbs
|
29
|
+
attr_accessor :exclude_loggers
|
44
30
|
|
45
|
-
#
|
31
|
+
# Array of exception classes that should never be sent. See IGNORE_DEFAULT.
|
32
|
+
# You should probably append to this rather than overwrite it.
|
46
33
|
attr_accessor :excluded_exceptions
|
47
34
|
|
48
|
-
#
|
49
|
-
attr_accessor :
|
35
|
+
# DSN component - set automatically if DSN provided
|
36
|
+
attr_accessor :host
|
50
37
|
|
51
|
-
#
|
52
|
-
attr_accessor :
|
38
|
+
# The Faraday adapter to be used. Will default to Net::HTTP when not set.
|
39
|
+
attr_accessor :http_adapter
|
53
40
|
|
54
|
-
#
|
41
|
+
# Logger used by Raven. In Rails, this is the Rails logger, otherwise
|
42
|
+
# Raven provides its own Raven::Logger.
|
43
|
+
attr_accessor :logger
|
44
|
+
|
45
|
+
# Timeout waiting for the Sentry server connection to open in seconds
|
55
46
|
attr_accessor :open_timeout
|
56
47
|
|
57
|
-
#
|
58
|
-
attr_accessor :
|
48
|
+
# DSN component - set automatically if DSN provided
|
49
|
+
attr_accessor :path
|
59
50
|
|
60
|
-
#
|
61
|
-
attr_accessor :
|
51
|
+
# DSN component - set automatically if DSN provided
|
52
|
+
attr_accessor :port
|
62
53
|
|
63
|
-
#
|
64
|
-
|
54
|
+
# Processors to run on data before sending upstream. See DEFAULT_PROCESSORS.
|
55
|
+
# You should probably append to this rather than overwrite it.
|
56
|
+
attr_accessor :processors
|
65
57
|
|
66
|
-
#
|
58
|
+
# Project ID number to send to the Sentry server
|
59
|
+
# If you provide a DSN, this will be set automatically.
|
60
|
+
attr_accessor :project_id
|
61
|
+
|
62
|
+
# Project directory root for in_app detection. Could be Rails root, etc.
|
63
|
+
# Set automatically for Rails.
|
64
|
+
attr_reader :project_root
|
65
|
+
|
66
|
+
# Proxy information to pass to the HTTP adapter (via Faraday)
|
67
67
|
attr_accessor :proxy
|
68
68
|
|
69
|
-
|
69
|
+
# Public key for authentication with the Sentry server
|
70
|
+
# If you provide a DSN, this will be set automatically.
|
71
|
+
attr_accessor :public_key
|
70
72
|
|
71
|
-
#
|
72
|
-
attr_accessor :
|
73
|
+
# Turns on ActiveSupport breadcrumbs integration
|
74
|
+
attr_accessor :rails_activesupport_breadcrumbs
|
73
75
|
|
74
|
-
|
76
|
+
# Rails catches exceptions in the ActionDispatch::ShowExceptions or
|
77
|
+
# ActionDispatch::DebugExceptions middlewares, depending on the environment.
|
78
|
+
# When `rails_report_rescued_exceptions` is true (it is by default), Raven
|
79
|
+
# will report exceptions even when they are rescued by these middlewares.
|
80
|
+
attr_accessor :rails_report_rescued_exceptions
|
75
81
|
|
82
|
+
# Release tag to be passed with every event sent to Sentry.
|
83
|
+
# We automatically try to set this to a git SHA or Capistrano release.
|
76
84
|
attr_accessor :release
|
77
85
|
|
78
|
-
#
|
79
|
-
attr_accessor :
|
86
|
+
# Boolean - sanitize values that look like credit card numbers
|
87
|
+
attr_accessor :sanitize_credit_cards
|
80
88
|
|
81
|
-
#
|
82
|
-
|
89
|
+
# By default, Sentry censors Hash values when their keys match things like
|
90
|
+
# "secret", "password", etc. Provide an array of Strings that, when matched in
|
91
|
+
# a hash key, will be censored and not sent to Sentry.
|
92
|
+
attr_accessor :sanitize_fields
|
83
93
|
|
84
|
-
#
|
85
|
-
|
94
|
+
# Sanitize additional HTTP headers - only Authorization is removed by default.
|
95
|
+
attr_accessor :sanitize_http_headers
|
86
96
|
|
87
|
-
#
|
88
|
-
|
97
|
+
# DSN component - set automatically if DSN provided.
|
98
|
+
# Otherwise, can be one of "http", "https", or "dummy"
|
99
|
+
attr_accessor :scheme
|
89
100
|
|
90
|
-
#
|
91
|
-
#
|
92
|
-
|
93
|
-
attr_accessor :app_dirs_pattern
|
101
|
+
# Secret key for authentication with the Sentry server
|
102
|
+
# If you provide a DSN, this will be set automatically.
|
103
|
+
attr_accessor :secret_key
|
94
104
|
|
95
|
-
#
|
96
|
-
|
97
|
-
# When `rails_report_rescued_exceptions` is true (it is by default), Raven
|
98
|
-
# will report exceptions even when they are rescued by these middlewares.
|
99
|
-
attr_accessor :rails_report_rescued_exceptions
|
100
|
-
# Deprecated accessor
|
101
|
-
attr_reader :catch_debugged_exceptions
|
105
|
+
# Include module versions in reports - boolean.
|
106
|
+
attr_accessor :send_modules
|
102
107
|
|
103
|
-
#
|
104
|
-
|
108
|
+
# Simple server string - set this to the DSN found on your Sentry settings.
|
109
|
+
attr_reader :server
|
105
110
|
|
106
|
-
|
111
|
+
attr_accessor :server_name
|
112
|
+
|
113
|
+
# Provide a configurable callback to determine event capture.
|
114
|
+
# Note that the object passed into the block will be a String (messages) or
|
115
|
+
# an exception.
|
116
|
+
# e.g. lambda { |exc_or_msg| exc_or_msg.some_attr == false }
|
107
117
|
attr_accessor :should_capture
|
108
118
|
|
109
|
-
#
|
110
|
-
attr_accessor :
|
119
|
+
# Silences ready message when true.
|
120
|
+
attr_accessor :silence_ready
|
111
121
|
|
112
|
-
#
|
113
|
-
attr_accessor :
|
122
|
+
# SSL settings passed directly to Faraday's ssl option
|
123
|
+
attr_accessor :ssl
|
114
124
|
|
115
|
-
#
|
116
|
-
attr_accessor :
|
125
|
+
# The path to the SSL certificate file
|
126
|
+
attr_accessor :ssl_ca_file
|
117
127
|
|
118
|
-
#
|
119
|
-
attr_accessor :
|
128
|
+
# Should the SSL certificate of the server be verified?
|
129
|
+
attr_accessor :ssl_verification
|
130
|
+
|
131
|
+
# Default tags for events. Hash.
|
132
|
+
attr_accessor :tags
|
133
|
+
|
134
|
+
# Timeout when waiting for the server to return data in seconds.
|
135
|
+
attr_accessor :timeout
|
136
|
+
|
137
|
+
# Optional Proc, called when the Sentry server cannot be contacted for any reason
|
138
|
+
# E.g. lambda { |event| Thread.new { MyJobProcessor.send_email(event) } }
|
139
|
+
attr_reader :transport_failure_callback
|
120
140
|
|
121
141
|
IGNORE_DEFAULT = [
|
122
142
|
'AbstractController::ActionNotFound',
|
@@ -126,46 +146,45 @@ module Raven
|
|
126
146
|
'ActiveRecord::RecordNotFound',
|
127
147
|
'CGI::Session::CookieStore::TamperedWithCookie',
|
128
148
|
'Mongoid::Errors::DocumentNotFound',
|
129
|
-
'Sinatra::NotFound'
|
149
|
+
'Sinatra::NotFound'
|
130
150
|
].freeze
|
131
151
|
|
152
|
+
# Note the order - we have to remove circular references and bad characters
|
153
|
+
# before passing to other processors.
|
132
154
|
DEFAULT_PROCESSORS = [
|
133
|
-
Raven::Processor::Truncator,
|
134
155
|
Raven::Processor::RemoveCircularReferences,
|
135
156
|
Raven::Processor::UTF8Conversion,
|
136
157
|
Raven::Processor::SanitizeData,
|
137
158
|
Raven::Processor::Cookies,
|
138
159
|
Raven::Processor::PostData,
|
160
|
+
Raven::Processor::HTTPHeaders
|
139
161
|
].freeze
|
140
162
|
|
141
163
|
def initialize
|
142
|
-
self.
|
143
|
-
|
164
|
+
self.async = false
|
165
|
+
self.context_lines = 3
|
144
166
|
self.current_environment = ENV['RAILS_ENV'] || ENV['RACK_ENV'] || 'default'
|
145
|
-
self.send_modules = true
|
146
|
-
self.excluded_exceptions = IGNORE_DEFAULT.dup
|
147
|
-
self.processors = DEFAULT_PROCESSORS.dup
|
148
|
-
self.ssl_verification = true
|
149
167
|
self.encoding = 'gzip'
|
150
|
-
self.
|
168
|
+
self.environments = []
|
169
|
+
self.exclude_loggers = []
|
170
|
+
self.excluded_exceptions = IGNORE_DEFAULT.dup
|
151
171
|
self.open_timeout = 1
|
172
|
+
self.processors = DEFAULT_PROCESSORS.dup
|
152
173
|
self.proxy = nil
|
153
|
-
self.tags = {}
|
154
|
-
self.async = false
|
155
|
-
self.rails_report_rescued_exceptions = true
|
156
174
|
self.rails_activesupport_breadcrumbs = false
|
157
|
-
self.
|
158
|
-
self.sanitize_fields = []
|
159
|
-
self.sanitize_credit_cards = true
|
160
|
-
self.event_bytesize_limit = 8_000
|
161
|
-
self.environments = []
|
162
|
-
self.exclude_loggers = []
|
163
|
-
|
175
|
+
self.rails_report_rescued_exceptions = true
|
164
176
|
self.release = detect_release
|
165
|
-
|
166
|
-
|
167
|
-
self.
|
168
|
-
self.
|
177
|
+
self.sanitize_credit_cards = true
|
178
|
+
self.sanitize_fields = []
|
179
|
+
self.sanitize_http_headers = []
|
180
|
+
self.send_modules = true
|
181
|
+
self.server = ENV['SENTRY_DSN'] if ENV['SENTRY_DSN']
|
182
|
+
self.server_name = resolve_hostname
|
183
|
+
self.should_capture = false
|
184
|
+
self.ssl_verification = true
|
185
|
+
self.tags = {}
|
186
|
+
self.timeout = 2
|
187
|
+
self.transport_failure_callback = false
|
169
188
|
end
|
170
189
|
|
171
190
|
def server=(value)
|
@@ -189,38 +208,46 @@ module Raven
|
|
189
208
|
@server << ":#{port}" unless port == { 'http' => 80, 'https' => 443 }[scheme]
|
190
209
|
@server << path
|
191
210
|
end
|
211
|
+
alias dsn= server=
|
192
212
|
|
193
213
|
def encoding=(encoding)
|
194
|
-
raise
|
214
|
+
raise(Error, 'Unsupported encoding') unless %w(gzip json).include? encoding
|
195
215
|
@encoding = encoding
|
196
216
|
end
|
197
217
|
|
198
|
-
alias dsn= server=
|
199
|
-
|
200
218
|
def async=(value)
|
201
|
-
|
219
|
+
unless value == false || value.respond_to?(:call)
|
220
|
+
raise(ArgumentError, "async must be callable (or false to disable)")
|
221
|
+
end
|
202
222
|
@async = value
|
203
223
|
end
|
204
224
|
|
205
|
-
alias async? async
|
206
|
-
|
207
225
|
def transport_failure_callback=(value)
|
208
|
-
|
226
|
+
unless value == false || value.respond_to?(:call)
|
227
|
+
raise(ArgumentError, "transport_failure_callback must be callable (or false to disable)")
|
228
|
+
end
|
209
229
|
@transport_failure_callback = value
|
210
230
|
end
|
211
231
|
|
232
|
+
def should_capture=(value)
|
233
|
+
unless value == false || value.respond_to?(:call)
|
234
|
+
raise ArgumentError, "should_capture must be callable (or false to disable)"
|
235
|
+
end
|
236
|
+
@should_capture = value
|
237
|
+
end
|
238
|
+
|
212
239
|
# Allows config options to be read like a hash
|
213
240
|
#
|
214
241
|
# @param [Symbol] option Key for a given attribute
|
215
242
|
def [](option)
|
216
|
-
|
243
|
+
public_send(option)
|
217
244
|
end
|
218
245
|
|
219
246
|
def current_environment=(environment)
|
220
247
|
@current_environment = environment.to_s
|
221
248
|
end
|
222
249
|
|
223
|
-
def capture_allowed?(message_or_exc)
|
250
|
+
def capture_allowed?(message_or_exc = nil)
|
224
251
|
capture_in_current_environment? &&
|
225
252
|
capture_allowed_by_callback?(message_or_exc)
|
226
253
|
end
|
@@ -228,26 +255,10 @@ module Raven
|
|
228
255
|
# If we cannot capture, we cannot send.
|
229
256
|
alias sending_allowed? capture_allowed?
|
230
257
|
|
231
|
-
def capture_in_current_environment?
|
232
|
-
!!server && (environments.empty? || environments.include?(current_environment))
|
233
|
-
end
|
234
|
-
|
235
|
-
def capture_allowed_by_callback?(message_or_exc)
|
236
|
-
return true unless should_capture
|
237
|
-
should_capture.call(*[message_or_exc])
|
238
|
-
end
|
239
|
-
|
240
258
|
def verify!
|
241
|
-
|
242
|
-
|
243
|
-
|
244
|
-
raise Error.new('No project ID specified') unless project_id
|
245
|
-
end
|
246
|
-
|
247
|
-
def detect_release
|
248
|
-
detect_release_from_heroku ||
|
249
|
-
detect_release_from_capistrano ||
|
250
|
-
detect_release_from_git
|
259
|
+
%w(server public_key secret_key project_id).each do |key|
|
260
|
+
raise(Error, "No #{key} specified") unless public_send key
|
261
|
+
end
|
251
262
|
end
|
252
263
|
|
253
264
|
def project_root=(root_dir)
|
@@ -255,11 +266,10 @@ module Raven
|
|
255
266
|
Backtrace::Line.instance_variable_set(:@in_app_pattern, nil) # blow away cache
|
256
267
|
end
|
257
268
|
|
258
|
-
def
|
259
|
-
|
260
|
-
|
261
|
-
|
262
|
-
self.rails_report_rescued_exceptions = boolean
|
269
|
+
def detect_release
|
270
|
+
detect_release_from_heroku ||
|
271
|
+
detect_release_from_capistrano ||
|
272
|
+
detect_release_from_git
|
263
273
|
end
|
264
274
|
|
265
275
|
private
|
@@ -278,5 +288,21 @@ module Raven
|
|
278
288
|
def detect_release_from_git
|
279
289
|
`git rev-parse --short HEAD`.strip if File.directory?(".git") rescue nil
|
280
290
|
end
|
291
|
+
|
292
|
+
def capture_in_current_environment?
|
293
|
+
!!server && (environments.empty? || environments.include?(current_environment))
|
294
|
+
end
|
295
|
+
|
296
|
+
def capture_allowed_by_callback?(message_or_exc)
|
297
|
+
return true if !should_capture || message_or_exc.nil?
|
298
|
+
should_capture.call(*[message_or_exc])
|
299
|
+
end
|
300
|
+
|
301
|
+
# Try to resolve the hostname to an FQDN, but fall back to whatever
|
302
|
+
# the load name is.
|
303
|
+
def resolve_hostname
|
304
|
+
Socket.gethostname ||
|
305
|
+
Socket.gethostbyname(hostname).first rescue server_name
|
306
|
+
end
|
281
307
|
end
|
282
308
|
end
|
data/lib/raven/event.rb
CHANGED
@@ -8,7 +8,6 @@ require 'raven/error'
|
|
8
8
|
require 'raven/linecache'
|
9
9
|
|
10
10
|
module Raven
|
11
|
-
|
12
11
|
class Event
|
13
12
|
LOG_LEVELS = {
|
14
13
|
"debug" => 10,
|
@@ -16,7 +15,7 @@ module Raven
|
|
16
15
|
"warn" => 30,
|
17
16
|
"warning" => 30,
|
18
17
|
"error" => 40,
|
19
|
-
"fatal" => 50
|
18
|
+
"fatal" => 50
|
20
19
|
}.freeze
|
21
20
|
|
22
21
|
BACKTRACE_RE = /^(.+?):(\d+)(?::in `(.+?)')?$/
|
@@ -25,15 +24,15 @@ module Raven
|
|
25
24
|
|
26
25
|
attr_reader :id
|
27
26
|
attr_accessor :project, :message, :timestamp, :time_spent, :level, :logger,
|
28
|
-
|
29
|
-
|
27
|
+
:culprit, :server_name, :release, :modules, :extra, :tags, :context, :configuration,
|
28
|
+
:checksum, :fingerprint, :environment
|
30
29
|
|
31
30
|
def initialize(init = {})
|
32
31
|
@configuration = Raven.configuration
|
33
32
|
@interfaces = {}
|
34
33
|
@breadcrumbs = Raven.breadcrumbs
|
35
34
|
@context = Raven.context
|
36
|
-
@id =
|
35
|
+
@id = SecureRandom.uuid
|
37
36
|
@project = nil
|
38
37
|
@message = nil
|
39
38
|
@timestamp = Time.now.utc
|
@@ -59,6 +58,10 @@ module Raven
|
|
59
58
|
end
|
60
59
|
end
|
61
60
|
|
61
|
+
if @context.rack_env
|
62
|
+
@context.user[:ip_address] = calculate_real_ip_from_rack
|
63
|
+
end
|
64
|
+
|
62
65
|
init.each_pair { |key, val| instance_variable_set('@' + key.to_s, val) }
|
63
66
|
|
64
67
|
@user = @context.user.merge(@user)
|
@@ -67,7 +70,7 @@ module Raven
|
|
67
70
|
|
68
71
|
# Some type coercion
|
69
72
|
@timestamp = @timestamp.strftime('%Y-%m-%dT%H:%M:%S') if @timestamp.is_a?(Time)
|
70
|
-
@time_spent = (@time_spent*1000).to_i if @time_spent.is_a?(Float)
|
73
|
+
@time_spent = (@time_spent * 1000).to_i if @time_spent.is_a?(Float)
|
71
74
|
@level = LOG_LEVELS[@level.to_s.downcase] if @level.is_a?(String) || @level.is_a?(Symbol)
|
72
75
|
end
|
73
76
|
|
@@ -99,7 +102,9 @@ module Raven
|
|
99
102
|
end
|
100
103
|
|
101
104
|
def from_message(message, options = {})
|
105
|
+
message = message.byteslice(0...10_000) # Messages limited to 10kb
|
102
106
|
configuration = options[:configuration] || Raven.configuration
|
107
|
+
|
103
108
|
new(options) do |evt|
|
104
109
|
evt.configuration = configuration
|
105
110
|
evt.message = message
|
@@ -133,9 +138,7 @@ module Raven
|
|
133
138
|
|
134
139
|
while exc.respond_to?(:cause) && exc.cause
|
135
140
|
exc = exc.cause
|
136
|
-
if context.include?(exc.object_id)
|
137
|
-
break
|
138
|
-
end
|
141
|
+
break if context.include?(exc.object_id)
|
139
142
|
exceptions << exc
|
140
143
|
context.add(exc.object_id)
|
141
144
|
end
|
@@ -194,7 +197,7 @@ module Raven
|
|
194
197
|
|
195
198
|
def interface(name, value = nil, &block)
|
196
199
|
int = Raven.find_interface(name)
|
197
|
-
raise
|
200
|
+
raise(Error, "Unknown interface: #{name}") unless int
|
198
201
|
@interfaces[int.name] = int.new(value, &block) if value || block
|
199
202
|
@interfaces[int.name]
|
200
203
|
end
|
@@ -215,7 +218,7 @@ module Raven
|
|
215
218
|
:time_spent => @time_spent,
|
216
219
|
:level => @level,
|
217
220
|
:project => @project,
|
218
|
-
:platform => PLATFORM
|
221
|
+
:platform => PLATFORM
|
219
222
|
}
|
220
223
|
data[:logger] = @logger if @logger
|
221
224
|
data[:culprit] = @culprit if @culprit
|
@@ -236,7 +239,7 @@ module Raven
|
|
236
239
|
end
|
237
240
|
|
238
241
|
def get_file_context(filename, lineno, context)
|
239
|
-
return nil, nil, nil unless Raven::LineCache.
|
242
|
+
return nil, nil, nil unless Raven::LineCache.valid_file?(filename)
|
240
243
|
lines = Array.new(2 * context + 1) do |i|
|
241
244
|
Raven::LineCache.getline(filename, lineno - context + i)
|
242
245
|
end
|
@@ -248,24 +251,29 @@ module Raven
|
|
248
251
|
"#{lastframe.filename} in #{lastframe.function} at line #{lastframe.lineno}" if lastframe
|
249
252
|
end
|
250
253
|
|
254
|
+
def to_json_compatible
|
255
|
+
JSON.parse(JSON.generate(to_hash))
|
256
|
+
end
|
257
|
+
|
251
258
|
# For cross-language compat
|
252
259
|
class << self
|
253
|
-
alias
|
254
|
-
alias
|
255
|
-
alias
|
256
|
-
alias
|
260
|
+
alias captureException from_exception
|
261
|
+
alias captureMessage from_message
|
262
|
+
alias capture_exception from_exception
|
263
|
+
alias capture_message from_message
|
257
264
|
end
|
258
265
|
|
259
266
|
private
|
260
267
|
|
261
|
-
|
262
|
-
|
263
|
-
|
264
|
-
|
265
|
-
|
266
|
-
|
267
|
-
|
268
|
-
|
268
|
+
# When behind a proxy (or if the user is using a proxy), we can't use
|
269
|
+
# REMOTE_ADDR to determine the Event IP, and must use other headers instead.
|
270
|
+
def calculate_real_ip_from_rack
|
271
|
+
Utils::RealIp.new(
|
272
|
+
:remote_addr => context.rack_env["REMOTE_ADDR"],
|
273
|
+
:client_ip => context.rack_env["HTTP_CLIENT_IP"],
|
274
|
+
:real_ip => context.rack_env["HTTP_X_REAL_IP"],
|
275
|
+
:forwarded_for => context.rack_env["HTTP_X_FORWARDED_FOR"]
|
276
|
+
).calculate_ip
|
269
277
|
end
|
270
278
|
end
|
271
279
|
end
|
data/lib/raven/instance.rb
CHANGED
@@ -58,7 +58,7 @@ module Raven
|
|
58
58
|
# Tell the log that the client is good to go
|
59
59
|
def report_status
|
60
60
|
return if configuration.silence_ready
|
61
|
-
if configuration.
|
61
|
+
if configuration.capture_allowed?
|
62
62
|
logger.info "Raven #{VERSION} ready to catch errors"
|
63
63
|
else
|
64
64
|
logger.info "Raven #{VERSION} configured not to capture errors."
|
@@ -119,7 +119,14 @@ module Raven
|
|
119
119
|
if (evt = Event.send("from_" + message_or_exc, obj, options))
|
120
120
|
yield evt if block_given?
|
121
121
|
if configuration.async?
|
122
|
-
|
122
|
+
begin
|
123
|
+
# We have to convert to a JSON-like hash, because background job
|
124
|
+
# processors (esp ActiveJob) may not like weird types in the event hash
|
125
|
+
configuration.async.call(evt.to_json_compatible)
|
126
|
+
rescue => ex
|
127
|
+
Raven.logger.error("async event sending failed: #{ex.message}")
|
128
|
+
send_event(evt)
|
129
|
+
end
|
123
130
|
else
|
124
131
|
send_event(evt)
|
125
132
|
end
|
@@ -21,7 +21,7 @@ module Delayed
|
|
21
21
|
:locked_by => job.locked_by,
|
22
22
|
:queue => job.queue,
|
23
23
|
:created_at => job.created_at
|
24
|
-
|
24
|
+
}
|
25
25
|
}
|
26
26
|
# last_error can be nil
|
27
27
|
extra[:last_error] = job.last_error[0...100] if job.last_error
|
@@ -33,12 +33,12 @@ module Delayed
|
|
33
33
|
extra[:active_job] = job.payload_object.job_data
|
34
34
|
end
|
35
35
|
::Raven.capture_exception(exception,
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
36
|
+
:logger => 'delayed_job',
|
37
|
+
:tags => {
|
38
|
+
:delayed_job_queue => job.queue,
|
39
|
+
:delayed_job_id => job.id
|
40
|
+
},
|
41
|
+
:extra => extra)
|
42
42
|
|
43
43
|
# Make sure we propagate the failure!
|
44
44
|
raise exception
|
@@ -49,7 +49,6 @@ module Delayed
|
|
49
49
|
end
|
50
50
|
end
|
51
51
|
end
|
52
|
-
|
53
52
|
end
|
54
53
|
end
|
55
54
|
|
@@ -0,0 +1,16 @@
|
|
1
|
+
# rubocop:disable Style/FileName
|
2
|
+
# We need to do this because of the way integration loading works
|
3
|
+
require 'rack-timeout'
|
4
|
+
|
5
|
+
# This integration is a good example of how to change how exceptions
|
6
|
+
# get grouped by Sentry's UI. Simply override #raven_context in
|
7
|
+
# the exception class, and append something to the fingerprint
|
8
|
+
# that will distinguish exceptions in the way you desire.
|
9
|
+
module RackTimeoutExtensions
|
10
|
+
def raven_context
|
11
|
+
{ :fingerprint => ["{{ default }}", env["REQUEST_URI"]] }
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
Rack::Timeout::Error.include RackTimeoutExtensions
|
16
|
+
Rack::Timeout::RequestTimeoutException.include RackTimeoutExtensions
|
@@ -51,7 +51,6 @@ module Raven
|
|
51
51
|
rescue Error
|
52
52
|
raise # Don't capture Raven errors
|
53
53
|
rescue Exception => e
|
54
|
-
Raven.logger.debug "Collecting %p: %s" % [ e.class, e.message ]
|
55
54
|
Raven::Rack.capture_exception(e, env)
|
56
55
|
raise
|
57
56
|
end
|
@@ -84,8 +83,8 @@ module Raven
|
|
84
83
|
def read_data_from(request)
|
85
84
|
if request.form_data?
|
86
85
|
request.POST
|
87
|
-
elsif request.body
|
88
|
-
data = request.body.read
|
86
|
+
elsif request.body # JSON requests, etc
|
87
|
+
data = request.body.read(2048) # Sentry server limit
|
89
88
|
request.body.rewind
|
90
89
|
data
|
91
90
|
end
|
@@ -4,7 +4,7 @@ require 'raven/integrations/tasks'
|
|
4
4
|
|
5
5
|
module Rake
|
6
6
|
class Application
|
7
|
-
alias
|
7
|
+
alias orig_display_error_messsage display_error_message
|
8
8
|
def display_error_message(ex)
|
9
9
|
Raven.capture_exception ex, :logger => 'rake', :tags => { 'rake_task' => @name }
|
10
10
|
orig_display_error_messsage(ex)
|
@@ -8,7 +8,7 @@ module Raven
|
|
8
8
|
yield
|
9
9
|
rescue Exception => ex
|
10
10
|
Raven.capture_exception(ex, :extra => { :sidekiq => msg },
|
11
|
-
:time_spent => Time.now-started_at)
|
11
|
+
:time_spent => Time.now - started_at)
|
12
12
|
raise
|
13
13
|
ensure
|
14
14
|
Context.clear!
|
@@ -26,10 +26,10 @@ if Sidekiq::VERSION < '3'
|
|
26
26
|
end
|
27
27
|
else
|
28
28
|
Sidekiq.configure_server do |config|
|
29
|
-
config.error_handlers <<
|
29
|
+
config.error_handlers << proc do |ex, context|
|
30
30
|
Raven.capture_exception(ex, :extra => {
|
31
|
-
|
32
|
-
|
31
|
+
:sidekiq => filter_context(context)
|
32
|
+
})
|
33
33
|
end
|
34
34
|
end
|
35
35
|
end
|
data/lib/raven/interfaces.rb
CHANGED
@@ -1,6 +1,4 @@
|
|
1
1
|
module Raven
|
2
|
-
|
3
|
-
# TODO: a constant isn't appropriate here, refactor
|
4
2
|
INTERFACES = {} # rubocop:disable Style/MutableConstant
|
5
3
|
|
6
4
|
class Interface
|
@@ -17,7 +15,7 @@ module Raven
|
|
17
15
|
end
|
18
16
|
|
19
17
|
def to_hash
|
20
|
-
Hash[instance_variables.map { |name| [name[1..-1].to_sym, instance_variable_get(name)] }
|
18
|
+
Hash[instance_variables.map { |name| [name[1..-1].to_sym, instance_variable_get(name)] }]
|
21
19
|
end
|
22
20
|
end
|
23
21
|
|
@@ -34,7 +34,7 @@ module Raven
|
|
34
34
|
end
|
35
35
|
|
36
36
|
def filename
|
37
|
-
return nil if
|
37
|
+
return nil if abs_path.nil?
|
38
38
|
|
39
39
|
prefix =
|
40
40
|
if under_project_root? && in_app
|
@@ -45,7 +45,7 @@ module Raven
|
|
45
45
|
longest_load_path
|
46
46
|
end
|
47
47
|
|
48
|
-
prefix ?
|
48
|
+
prefix ? abs_path[prefix.to_s.chomp(File::SEPARATOR).length + 1..-1] : abs_path
|
49
49
|
end
|
50
50
|
|
51
51
|
def under_project_root?
|
@@ -57,16 +57,16 @@ module Raven
|
|
57
57
|
end
|
58
58
|
|
59
59
|
def longest_load_path
|
60
|
-
$LOAD_PATH.select { |s|
|
60
|
+
$LOAD_PATH.select { |s| abs_path.start_with?(s.to_s) }.sort_by { |s| s.to_s.length }.last
|
61
61
|
end
|
62
62
|
|
63
63
|
def to_hash(*args)
|
64
64
|
data = super(*args)
|
65
|
-
data[:filename] =
|
66
|
-
data.delete(:vars) unless
|
67
|
-
data.delete(:pre_context) unless
|
68
|
-
data.delete(:post_context) unless
|
69
|
-
data.delete(:context_line) unless
|
65
|
+
data[:filename] = filename
|
66
|
+
data.delete(:vars) unless vars && !vars.empty?
|
67
|
+
data.delete(:pre_context) unless pre_context && !pre_context.empty?
|
68
|
+
data.delete(:post_context) unless post_context && !post_context.empty?
|
69
|
+
data.delete(:context_line) unless context_line && !context_line.empty?
|
70
70
|
data
|
71
71
|
end
|
72
72
|
end
|
data/lib/raven/linecache.rb
CHANGED
@@ -1,14 +1,9 @@
|
|
1
|
-
# A much simpler source line cacher because linecache sucks at platform compat
|
2
|
-
|
3
1
|
module Raven
|
4
2
|
class LineCache
|
5
3
|
class << self
|
6
|
-
# TODO: a constant isn't appropriate here, refactor
|
7
|
-
# also would there be threading bugs essentially using this as a class
|
8
|
-
# variable?
|
9
4
|
CACHE = {} # rubocop:disable Style/MutableConstant
|
10
5
|
|
11
|
-
def
|
6
|
+
def valid_file?(path)
|
12
7
|
lines = getlines(path)
|
13
8
|
!lines.nil?
|
14
9
|
end
|
data/lib/raven/logger.rb
CHANGED
data/lib/raven/processor.rb
CHANGED
@@ -3,10 +3,10 @@ module Raven
|
|
3
3
|
def process(data)
|
4
4
|
if data[:request]
|
5
5
|
# Remove possibly sensitive cookies
|
6
|
-
data[:request][:cookies] =
|
6
|
+
data[:request][:cookies] = STRING_MASK if data[:request][:cookies]
|
7
7
|
|
8
8
|
if data[:request][:headers] && data[:request][:headers]["Cookie"]
|
9
|
-
data[:request][:headers]["Cookie"] =
|
9
|
+
data[:request][:headers]["Cookie"] = STRING_MASK
|
10
10
|
end
|
11
11
|
end
|
12
12
|
|
@@ -0,0 +1,42 @@
|
|
1
|
+
module Raven
|
2
|
+
class Processor::HTTPHeaders < Processor
|
3
|
+
DEFAULT_FIELDS = ["Authorization"].freeze
|
4
|
+
|
5
|
+
attr_accessor :sanitize_http_headers
|
6
|
+
|
7
|
+
def initialize(client)
|
8
|
+
super
|
9
|
+
self.sanitize_http_headers = client.configuration.sanitize_http_headers
|
10
|
+
end
|
11
|
+
|
12
|
+
def process(data)
|
13
|
+
if data[:request] && data[:request][:headers]
|
14
|
+
data[:request][:headers].keys.select { |k| fields_re.match(k.to_s) }.each do |k|
|
15
|
+
data[:request][:headers][k] = STRING_MASK
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
data
|
20
|
+
end
|
21
|
+
|
22
|
+
private
|
23
|
+
|
24
|
+
def matches_regexes?(k)
|
25
|
+
fields_re.match(k.to_s)
|
26
|
+
end
|
27
|
+
|
28
|
+
def fields_re
|
29
|
+
@fields_re ||= /#{(DEFAULT_FIELDS | sanitize_http_headers).map do |f|
|
30
|
+
use_boundary?(f) ? "\\b#{f}\\b" : f
|
31
|
+
end.join("|")}/i
|
32
|
+
end
|
33
|
+
|
34
|
+
def use_boundary?(string)
|
35
|
+
!DEFAULT_FIELDS.include?(string) && !special_characters?(string)
|
36
|
+
end
|
37
|
+
|
38
|
+
def special_characters?(string)
|
39
|
+
REGEX_SPECIAL_CHARACTERS.select { |r| string.include?(r) }.any?
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
@@ -2,7 +2,7 @@ module Raven
|
|
2
2
|
class Processor::PostData < Processor
|
3
3
|
def process(data)
|
4
4
|
if data[:request] && data[:request][:method] == "POST"
|
5
|
-
data[:request][:data] =
|
5
|
+
data[:request][:data] = STRING_MASK # Remove possibly sensitive POST data
|
6
6
|
end
|
7
7
|
|
8
8
|
data
|
@@ -3,11 +3,8 @@ require 'json'
|
|
3
3
|
|
4
4
|
module Raven
|
5
5
|
class Processor::SanitizeData < Processor
|
6
|
-
STRING_MASK = '********'.freeze
|
7
|
-
INT_MASK = 0
|
8
6
|
DEFAULT_FIELDS = %w(authorization password passwd secret ssn social(.*)?sec).freeze
|
9
7
|
CREDIT_CARD_RE = /^(?:\d[ -]*?){13,16}$/
|
10
|
-
REGEX_SPECIAL_CHARACTERS = %w(. $ ^ { [ ( | ) * + ?).freeze
|
11
8
|
|
12
9
|
attr_accessor :sanitize_fields, :sanitize_credit_cards
|
13
10
|
|
@@ -18,23 +15,23 @@ module Raven
|
|
18
15
|
end
|
19
16
|
|
20
17
|
def process(value)
|
21
|
-
value.each_with_object(value) { |(k,v), memo| memo[k] = sanitize(k,v) }
|
18
|
+
value.each_with_object(value) { |(k, v), memo| memo[k] = sanitize(k, v) }
|
22
19
|
end
|
23
20
|
|
24
|
-
def sanitize(k,v)
|
21
|
+
def sanitize(k, v)
|
25
22
|
if v.is_a?(Hash)
|
26
23
|
process(v)
|
27
24
|
elsif v.is_a?(Array)
|
28
|
-
v.map{|a| sanitize(k, a)}
|
25
|
+
v.map { |a| sanitize(k, a) }
|
29
26
|
elsif k.to_s == 'query_string'
|
30
27
|
sanitize_query_string(v)
|
31
|
-
elsif v.is_a?(Integer) && matches_regexes?(k,v)
|
28
|
+
elsif v.is_a?(Integer) && matches_regexes?(k, v)
|
32
29
|
INT_MASK
|
33
30
|
elsif v.is_a?(String)
|
34
31
|
if fields_re.match(v.to_s) && (json = parse_json_or_nil(v))
|
35
|
-
#if this string is actually a json obj, convert and sanitize
|
32
|
+
# if this string is actually a json obj, convert and sanitize
|
36
33
|
json.is_a?(Hash) ? process(json).to_json : v
|
37
|
-
elsif matches_regexes?(k,v)
|
34
|
+
elsif matches_regexes?(k, v)
|
38
35
|
STRING_MASK
|
39
36
|
else
|
40
37
|
v
|
@@ -72,11 +69,9 @@ module Raven
|
|
72
69
|
end
|
73
70
|
|
74
71
|
def parse_json_or_nil(string)
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
nil
|
79
|
-
end
|
72
|
+
JSON.parse(string)
|
73
|
+
rescue JSON::ParserError, NoMethodError
|
74
|
+
nil
|
80
75
|
end
|
81
76
|
end
|
82
77
|
end
|
data/lib/raven/transports.rb
CHANGED
@@ -9,8 +9,8 @@ module Raven
|
|
9
9
|
@configuration = configuration
|
10
10
|
end
|
11
11
|
|
12
|
-
def send_event #(auth_header, data, options = {})
|
13
|
-
raise NotImplementedError
|
12
|
+
def send_event # (auth_header, data, options = {})
|
13
|
+
raise NotImplementedError, 'Abstract method not implemented'
|
14
14
|
end
|
15
15
|
|
16
16
|
protected
|
@@ -0,0 +1,62 @@
|
|
1
|
+
require 'ipaddr'
|
2
|
+
|
3
|
+
# Based on ActionDispatch::RemoteIp. All security-related precautions from that
|
4
|
+
# middleware have been removed, because the Event IP just needs to be accurate,
|
5
|
+
# and spoofing an IP here only makes data inaccurate, not insecure. Don't re-use
|
6
|
+
# this module if you have to *trust* the IP address.
|
7
|
+
module Raven
|
8
|
+
module Utils
|
9
|
+
class RealIp
|
10
|
+
LOCAL_ADDRESSES = [
|
11
|
+
"127.0.0.1", # localhost IPv4
|
12
|
+
"::1", # localhost IPv6
|
13
|
+
"fc00::/7", # private IPv6 range fc00::/7
|
14
|
+
"10.0.0.0/8", # private IPv4 range 10.x.x.x
|
15
|
+
"172.16.0.0/12", # private IPv4 range 172.16.0.0 .. 172.31.255.255
|
16
|
+
"192.168.0.0/16", # private IPv4 range 192.168.x.x
|
17
|
+
].map { |proxy| IPAddr.new(proxy) }
|
18
|
+
|
19
|
+
attr_accessor :ip, :ip_addresses
|
20
|
+
|
21
|
+
def initialize(ip_addresses)
|
22
|
+
self.ip_addresses = ip_addresses
|
23
|
+
end
|
24
|
+
|
25
|
+
def calculate_ip
|
26
|
+
# CGI environment variable set by Rack
|
27
|
+
remote_addr = ips_from(ip_addresses[:remote_addr]).last
|
28
|
+
|
29
|
+
# Could be a CSV list and/or repeated headers that were concatenated.
|
30
|
+
client_ips = ips_from(ip_addresses[:client_ip])
|
31
|
+
real_ips = ips_from(ip_addresses[:real_ip])
|
32
|
+
forwarded_ips = ips_from(ip_addresses[:forwarded_for])
|
33
|
+
|
34
|
+
ips = [client_ips, real_ips, forwarded_ips, remote_addr].flatten.compact
|
35
|
+
|
36
|
+
# If every single IP option is in the trusted list, just return REMOTE_ADDR
|
37
|
+
self.ip = filter_local_addresses(ips).first || remote_addr
|
38
|
+
end
|
39
|
+
|
40
|
+
protected
|
41
|
+
|
42
|
+
def ips_from(header)
|
43
|
+
# Split the comma-separated list into an array of strings
|
44
|
+
ips = header ? header.strip.split(/[,\s]+/) : []
|
45
|
+
ips.select do |ip|
|
46
|
+
begin
|
47
|
+
# Only return IPs that are valid according to the IPAddr#new method
|
48
|
+
range = IPAddr.new(ip).to_range
|
49
|
+
# we want to make sure nobody is sneaking a netmask in
|
50
|
+
range.begin == range.end
|
51
|
+
rescue ArgumentError
|
52
|
+
nil
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
def filter_local_addresses(ips)
|
58
|
+
ips.reject { |ip| LOCAL_ADDRESSES.any? { |proxy| proxy === ip } }
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
data/lib/raven/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: sentry-raven
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
4
|
+
version: 2.0.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Sentry Team
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2016-
|
11
|
+
date: 2016-09-26 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: faraday
|
@@ -138,6 +138,7 @@ files:
|
|
138
138
|
- lib/raven/event.rb
|
139
139
|
- lib/raven/instance.rb
|
140
140
|
- lib/raven/integrations/delayed_job.rb
|
141
|
+
- lib/raven/integrations/rack-timeout.rb
|
141
142
|
- lib/raven/integrations/rack.rb
|
142
143
|
- lib/raven/integrations/rails.rb
|
143
144
|
- lib/raven/integrations/rails/active_job.rb
|
@@ -158,16 +159,17 @@ files:
|
|
158
159
|
- lib/raven/logger.rb
|
159
160
|
- lib/raven/processor.rb
|
160
161
|
- lib/raven/processor/cookies.rb
|
162
|
+
- lib/raven/processor/http_headers.rb
|
161
163
|
- lib/raven/processor/post_data.rb
|
162
164
|
- lib/raven/processor/removecircularreferences.rb
|
163
165
|
- lib/raven/processor/removestacktrace.rb
|
164
166
|
- lib/raven/processor/sanitizedata.rb
|
165
|
-
- lib/raven/processor/truncator.rb
|
166
167
|
- lib/raven/processor/utf8conversion.rb
|
167
168
|
- lib/raven/transports.rb
|
168
169
|
- lib/raven/transports/dummy.rb
|
169
170
|
- lib/raven/transports/http.rb
|
170
171
|
- lib/raven/utils/deep_merge.rb
|
172
|
+
- lib/raven/utils/real_ip.rb
|
171
173
|
- lib/raven/version.rb
|
172
174
|
- lib/sentry-raven-without-integrations.rb
|
173
175
|
- lib/sentry-raven.rb
|
@@ -1,22 +0,0 @@
|
|
1
|
-
module Raven
|
2
|
-
class Processor::Truncator < Processor
|
3
|
-
attr_accessor :event_bytesize_limit
|
4
|
-
|
5
|
-
def initialize(client)
|
6
|
-
super
|
7
|
-
self.event_bytesize_limit = client.configuration.event_bytesize_limit
|
8
|
-
end
|
9
|
-
|
10
|
-
def process(value)
|
11
|
-
value.each_with_object(value) { |(k, v), memo| memo[k] = truncate(v) }
|
12
|
-
end
|
13
|
-
|
14
|
-
def truncate(v)
|
15
|
-
if v.respond_to?(:bytesize) && v.bytesize >= event_bytesize_limit
|
16
|
-
v.byteslice(0...event_bytesize_limit)
|
17
|
-
else
|
18
|
-
v
|
19
|
-
end
|
20
|
-
end
|
21
|
-
end
|
22
|
-
end
|