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