sentry-ruby-core 4.1.5 → 4.3.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: c7862b3ddbb49c77b2c47c1a9509cce1efa4c193d459d0b3bd07bebd6aa9b62e
4
- data.tar.gz: faca1cc6efce70d3f64e1266c2e32fc2d67352544f8bfc2b2a278bcbefca1a61
3
+ metadata.gz: 66ef212c06425a29b56b64935c1fb662633fa80fb9f58b9680b1d95220ee8b5d
4
+ data.tar.gz: 18e211d0c93d18717795b23290c2cb7da503b0dcd1690c1c8b51861c3a37ef98
5
5
  SHA512:
6
- metadata.gz: 76dbfe0e360744126dcfdfce35d1563fb14387bafb1196c315fd1ef5e9d57c09d4d627f5a5386610a031a4909fab28a659bdfcd66e96d00a2e56c8737c130358
7
- data.tar.gz: e4c26db4e8bcaa1c6a32c4acadc9d385356b3617b8d5e76ffeda773b9deb4da291a77eafef27aa7bb98539cca187f27d174a7d0cc16c1ef8204c380e46fd54fc
6
+ metadata.gz: e334875a26a04e45a78c37e7bb0014604cd2b400b89eb01faa3ae21adc1f9072e46227ce880c1406148e32d6a125504dc08ffab5e1ac61c0b3befbd31e5352ea
7
+ data.tar.gz: 4c01fb8d489a3d143a738180f3f68ba62d3882267ecf17b82c3cf0e509ab36a8b458699d022d5d55699baacaccd2acc3bfede0d332ae5b50776128ac5c164a2a
data/CHANGELOG.md CHANGED
@@ -1,5 +1,90 @@
1
1
  # Changelog
2
2
 
3
+ ## 4.3.0
4
+
5
+ ### Features
6
+
7
+ - Allow configuring BreadcrumbBuffer's size limit [#1310](https://github.com/getsentry/sentry-ruby/pull/1310)
8
+
9
+ ```ruby
10
+ # the SDK will only store 10 breadcrumbs (default is 100)
11
+ config.max_breadcrumbs = 10
12
+ ```
13
+
14
+ - Compress event payload by default [#1314](https://github.com/getsentry/sentry-ruby/pull/1314)
15
+
16
+ ### Refatorings
17
+
18
+ - Refactor interface construction [#1296](https://github.com/getsentry/sentry-ruby/pull/1296)
19
+ - Refactor tracing implementation [#1309](https://github.com/getsentry/sentry-ruby/pull/1309)
20
+
21
+ ### Bug Fixes
22
+ - Improve SDK's error handling [#1298](https://github.com/getsentry/sentry-ruby/pull/1298)
23
+ - Fixes [#1246](https://github.com/getsentry/sentry-ruby/issues/1246) and [#1289](https://github.com/getsentry/sentry-ruby/issues/1289)
24
+ - Please read [#1290](https://github.com/getsentry/sentry-ruby/issues/1290) to see the full specification
25
+ - Treat query string as pii too [#1302](https://github.com/getsentry/sentry-ruby/pull/1302)
26
+ - Fixes [#1301](https://github.com/getsentry/sentry-ruby/issues/1301)
27
+ - Ignore sentry-trace when tracing is not enabled [#1308](https://github.com/getsentry/sentry-ruby/pull/1308)
28
+ - Fixes [#1307](https://github.com/getsentry/sentry-ruby/issues/1307)
29
+ - Return nil from logger methods instead of breadcrumb buffer [#1299](https://github.com/getsentry/sentry-ruby/pull/1299)
30
+ - Exceptions with nil message shouldn't cause issues [#1327](https://github.com/getsentry/sentry-ruby/pull/1327)
31
+ - Fixes [#1323](https://github.com/getsentry/sentry-ruby/issues/1323)
32
+ - Fix sampling decision with sentry-trace and add more tests [#1326](https://github.com/getsentry/sentry-ruby/pull/1326)
33
+
34
+ ## 4.2.2
35
+
36
+ - Add thread_id to Exception interface [#1291](https://github.com/getsentry/sentry-ruby/pull/1291)
37
+ - always convert trusted proxies to string [#1288](https://github.com/getsentry/sentry-ruby/pull/1288)
38
+ - fixes [#1274](https://github.com/getsentry/sentry-ruby/issues/1274)
39
+
40
+ ## 4.2.1
41
+
42
+ ### Bug Fixes
43
+
44
+ - Ignore invalid values for sentry-trace header that don't match the required format [#1265](https://github.com/getsentry/sentry-ruby/pull/1265)
45
+ - Transaction created by `.from_sentry_trace` should inherit sampling decision [#1269](https://github.com/getsentry/sentry-ruby/pull/1269)
46
+ - Transaction's sample rate should accept any numeric value [#1278](https://github.com/getsentry/sentry-ruby/pull/1278)
47
+
48
+ ## 4.2.0
49
+
50
+ ### Features
51
+
52
+ - Add configuration option for trusted proxies [#1126](https://github.com/getsentry/sentry-ruby/pull/1126)
53
+
54
+ ```ruby
55
+ config.trusted_proxies = ["2.2.2.2"] # this ip address will be skipped when computing users' ip addresses
56
+ ```
57
+
58
+ - Add ThreadsInterface [#1178](https://github.com/getsentry/sentry-ruby/pull/1178)
59
+
60
+ <img width="1029" alt="an exception event that has the new threads interface" src="https://user-images.githubusercontent.com/5079556/103459223-98b64c00-4d48-11eb-9ebb-ee58f15e647e.png">
61
+
62
+ - Support `config.before_breadcrumb` [#1253](https://github.com/getsentry/sentry-ruby/pull/1253)
63
+
64
+ ```ruby
65
+ # this will be called before every breadcrumb is added to the breadcrumb buffer
66
+ # you can use it to
67
+ # - remove the data you don't want to send
68
+ # - add additional info to the data
69
+ config.before_breadcrumb = lambda do |breadcrumb, hint|
70
+ breadcrumb.message = "foo"
71
+ breadcrumb
72
+ end
73
+ ```
74
+
75
+ - Add ability to have many post initialization callbacks [#1261](https://github.com/getsentry/sentry-ruby/pull/1261)
76
+
77
+ ### Bug Fixes
78
+
79
+ - Inspect exception cause by default & don't exclude ActiveJob::DeserializationError [#1180](https://github.com/getsentry/sentry-ruby/pull/1180)
80
+ - Fixes [#1071](https://github.com/getsentry/sentry-ruby/issues/1071)
81
+
82
+ ## 4.1.6
83
+
84
+ - Don't detect project root for Rails apps [#1243](https://github.com/getsentry/sentry-ruby/pull/1243)
85
+ - Separate individual breadcrumb's data serialization [#1250](https://github.com/getsentry/sentry-ruby/pull/1250)
86
+ - Capture sentry-trace with the correct http header key [#1260](https://github.com/getsentry/sentry-ruby/pull/1260)
87
+
3
88
  ## 4.1.5
4
89
 
5
90
  - Serialize event hint before passing it to the async block [#1231](https://github.com/getsentry/sentry-ruby/pull/1231)
@@ -134,4 +219,3 @@ Fix require reference
134
219
  ## 0.1.0
135
220
 
136
221
  First version
137
-
data/Gemfile CHANGED
@@ -3,6 +3,9 @@ source "https://rubygems.org"
3
3
  gem "sentry-ruby-core", path: "./"
4
4
  gem "sentry-ruby", path: "./"
5
5
 
6
+ # TODO: Remove this if https://github.com/jruby/jruby/issues/6547 is addressed
7
+ gem "i18n", "<= 1.8.7"
8
+
6
9
  gem "rake", "~> 12.0"
7
10
  gem "rspec", "~> 3.0"
8
11
  gem "codecov", "0.2.12"
data/Makefile ADDED
@@ -0,0 +1,4 @@
1
+ build:
2
+ bundle install
3
+ gem build sentry-ruby-core.gemspec
4
+ gem build sentry-ruby.gemspec
data/README.md CHANGED
@@ -2,10 +2,14 @@
2
2
  <a href="https://sentry.io" target="_blank" align="center">
3
3
  <img src="https://sentry-brand.storage.googleapis.com/sentry-logo-black.png" width="280">
4
4
  </a>
5
- <br>
5
+ <br />
6
6
  </p>
7
7
 
8
- # sentry-ruby, the Ruby Client for Sentry
8
+ _Bad software is everywhere, and we're tired of it. Sentry is on a mission to help developers write better software faster, so we can get back to enjoying technology. If you want to join us [<kbd>**Check out our open positions**</kbd>](https://sentry.io/careers/)_
9
+
10
+ Sentry SDK for Ruby
11
+ ===========
12
+
9
13
 
10
14
  **The old `sentry-raven` client has entered maintenance mode and was moved to [here](https://github.com/getsentry/sentry-ruby/tree/master/sentry-raven).**
11
15
 
@@ -26,7 +30,7 @@ The official Ruby-language client and integration layer for the [Sentry](https:/
26
30
 
27
31
  ## Requirements
28
32
 
29
- We test on Ruby 2.4, 2.5, 2.6 and 2.7 at the latest patchlevel/teeny version. We also support JRuby 9.0.
33
+ We test on Ruby 2.4, 2.5, 2.6, 2.7, and 3.0 at the latest patchlevel/teeny version. We also support JRuby 9.0.
30
34
 
31
35
  If you use self-hosted Sentry, please also make sure its version is above `20.6.0`.
32
36
 
@@ -47,6 +51,7 @@ and depends on the integrations you want to have, you might also want to install
47
51
  ```ruby
48
52
  gem "sentry-rails"
49
53
  gem "sentry-sidekiq"
54
+ gem "sentry-delayed_job"
50
55
  # and mores to come in the future!
51
56
  ```
52
57
 
@@ -136,6 +141,7 @@ We also provide integrations with popular frameworks/libraries with the related
136
141
 
137
142
  - [sentry-rails](https://github.com/getsentry/sentry-ruby/tree/master/sentry-rails)
138
143
  - [sentry-sidekiq](https://github.com/getsentry/sentry-ruby/tree/master/sentry-sidekiq)
144
+ - [sentry-delayed_job](https://github.com/getsentry/sentry-ruby/tree/master/sentry-delayed_job)
139
145
 
140
146
  ### More configuration
141
147
 
@@ -143,32 +149,7 @@ You're all set - but there's a few more settings you may want to know about too!
143
149
 
144
150
  #### Blocking v.s. Non-blocking
145
151
 
146
- **Before version 4.1.0**, `sentry-ruby` sends every event immediately. But it can be configured to send asynchronously:
147
-
148
- ```ruby
149
- config.async = lambda { |event, hint|
150
- Thread.new { Sentry.send_event(event, hint) }
151
- }
152
- ```
153
-
154
- Using a thread to send events will be adequate for truly parallel Ruby platforms such as JRuby, though the benefit on MRI/CRuby will be limited. If the async callback raises an exception, Sentry will attempt to send synchronously.
155
-
156
- Note that the naive example implementation has a major drawback - it can create an infinite number of threads. We recommend creating a background job, using your background job processor, that will send Sentry notifications in the background.
157
-
158
- ```ruby
159
- config.async = lambda { |event, hint| SentryJob.perform_later(event, hint) }
160
-
161
- class SentryJob < ActiveJob::Base
162
- queue_as :default
163
-
164
- def perform(event, hint)
165
- Sentry.send_event(event, hint)
166
- end
167
- end
168
- ```
169
-
170
-
171
- **After version 4.1.0**, `sentry-ruby` sends events asynchronously by default. The functionality works like this:
152
+ `sentry-ruby` sends events asynchronously by default. The functionality works like this:
172
153
 
173
154
  1. When the SDK is initialized, a `Sentry::BackgroundWorker` will be initialized too.
174
155
  2. When an event is passed to `Client#capture_event`, instead of sending it directly with `Client#send_event`, we'll let the worker do it.
@@ -202,6 +183,21 @@ If you want to send a particular event immediately, you can use event hints to d
202
183
  Sentry.capture_message("send me now!", hint: { background: false })
203
184
  ```
204
185
 
186
+ ##### `config.async`
187
+
188
+ You can also use `config.async` to send events with you own worker:
189
+
190
+ ```ruby
191
+ config.async = lambda { |event, hint| SentryJob.perform_later(event, hint) }
192
+ ```
193
+
194
+ And if you use `sentry-rails`, you can directly use the job we defined for you:
195
+
196
+ ```ruby
197
+ config.async = lambda { |event, hint| Sentry::SendEventJob.perform_later(event, hint) }
198
+ ```
199
+
200
+
205
201
  #### Contexts
206
202
 
207
203
  In sentry-ruby, every event will inherit their contextual data from the current scope. So you can enrich the event's data by configuring the current scope like:
data/lib/sentry-ruby.rb CHANGED
@@ -3,6 +3,7 @@ require "forwardable"
3
3
  require "time"
4
4
 
5
5
  require "sentry/version"
6
+ require "sentry/exceptions"
6
7
  require "sentry/core_ext/object/deep_dup"
7
8
  require "sentry/utils/argument_checking_helper"
8
9
  require "sentry/configuration"
@@ -26,9 +27,6 @@ require "sentry/background_worker"
26
27
  end
27
28
 
28
29
  module Sentry
29
- class Error < StandardError
30
- end
31
-
32
30
  META = { "name" => "sentry.ruby", "version" => Sentry::VERSION }.freeze
33
31
 
34
32
  LOGGER_PROGNAME = "sentry".freeze
@@ -68,7 +66,7 @@ module Sentry
68
66
  config = Configuration.new
69
67
  yield(config) if block_given?
70
68
  client = Client.new(config)
71
- scope = Scope.new
69
+ scope = Scope.new(max_breadcrumbs: config.max_breadcrumbs)
72
70
  hub = Hub.new(client, scope)
73
71
  Thread.current[THREAD_LOCAL] = hub
74
72
  @main_hub = hub
@@ -1,5 +1,6 @@
1
1
  require "concurrent/executor/thread_pool_executor"
2
2
  require "concurrent/executor/immediate_executor"
3
+ require "concurrent/configuration"
3
4
 
4
5
  module Sentry
5
6
  class BackgroundWorker
@@ -1,5 +1,7 @@
1
1
  module Sentry
2
2
  class Breadcrumb
3
+ DATA_SERIALIZATION_ERROR_MESSAGE = "[data were removed due to serialization issues]"
4
+
3
5
  attr_accessor :category, :data, :message, :level, :timestamp, :type
4
6
 
5
7
  def initialize(category: nil, data: nil, message: nil, timestamp: nil, level: nil, type: nil)
@@ -13,13 +15,30 @@ module Sentry
13
15
 
14
16
  def to_hash
15
17
  {
16
- :category => @category,
17
- :data => @data,
18
- :level => @level,
19
- :message => @message,
20
- :timestamp => @timestamp,
21
- :type => @type
18
+ category: @category,
19
+ data: serialized_data,
20
+ level: @level,
21
+ message: @message,
22
+ timestamp: @timestamp,
23
+ type: @type
22
24
  }
23
25
  end
26
+
27
+ private
28
+
29
+ def serialized_data
30
+ begin
31
+ ::JSON.parse(::JSON.generate(@data))
32
+ rescue Exception => e
33
+ Sentry.logger.debug(LOGGER_PROGNAME) do
34
+ <<~MSG
35
+ can't serialize breadcrumb data because of error: #{e}
36
+ data: #{@data}
37
+ MSG
38
+ end
39
+
40
+ DATA_SERIALIZATION_ERROR_MESSAGE
41
+ end
42
+ end
24
43
  end
25
44
  end
@@ -14,6 +14,7 @@ module Sentry
14
14
  def add(*args, &block)
15
15
  super
16
16
  add_breadcrumb(*args, &block)
17
+ nil
17
18
  end
18
19
 
19
20
  def add_breadcrumb(severity, message = nil, progname = nil)
@@ -2,12 +2,13 @@ require "sentry/breadcrumb"
2
2
 
3
3
  module Sentry
4
4
  class BreadcrumbBuffer
5
+ DEFAULT_SIZE = 100
5
6
  include Enumerable
6
7
 
7
8
  attr_accessor :buffer
8
9
 
9
- def initialize(size = 100)
10
- @buffer = Array.new(size)
10
+ def initialize(size = nil)
11
+ @buffer = Array.new(size || DEFAULT_SIZE)
11
12
  end
12
13
 
13
14
  def record(crumb)
@@ -34,7 +35,7 @@ module Sentry
34
35
 
35
36
  def to_hash
36
37
  {
37
- :values => members.map(&:to_hash)
38
+ values: members.map(&:to_hash)
38
39
  }
39
40
  end
40
41
 
data/lib/sentry/client.rb CHANGED
@@ -2,10 +2,11 @@ require "sentry/transport"
2
2
 
3
3
  module Sentry
4
4
  class Client
5
- attr_reader :transport, :configuration
5
+ attr_reader :transport, :configuration, :logger
6
6
 
7
7
  def initialize(configuration)
8
8
  @configuration = configuration
9
+ @logger = configuration.logger
9
10
 
10
11
  if transport_class = configuration.transport.transport_class
11
12
  @transport = transport_class.new(configuration)
@@ -26,32 +27,17 @@ module Sentry
26
27
  scope.apply_to_event(event, hint)
27
28
 
28
29
  if async_block = configuration.async
29
- begin
30
- # We have to convert to a JSON-like hash, because background job
31
- # processors (esp ActiveJob) may not like weird types in the event hash
32
- event_hash = event.to_json_compatible
33
-
34
- if async_block.arity == 2
35
- hint = JSON.parse(JSON.generate(hint))
36
- async_block.call(event_hash, hint)
37
- else
38
- async_block.call(event_hash)
39
- end
40
- rescue => e
41
- configuration.logger.error(LOGGER_PROGNAME) { "async event sending failed: #{e.message}" }
42
- send_event(event, hint)
43
- end
30
+ dispatch_async_event(async_block, event, hint)
31
+ elsif hint.fetch(:background, true)
32
+ dispatch_background_event(event, hint)
44
33
  else
45
- if hint.fetch(:background, true)
46
- Sentry.background_worker.perform do
47
- send_event(event, hint)
48
- end
49
- else
50
- send_event(event, hint)
51
- end
34
+ send_event(event, hint)
52
35
  end
53
36
 
54
37
  event
38
+ rescue => e
39
+ logger.error(LOGGER_PROGNAME) { "Event capturing failed: #{e.message}" }
40
+ nil
55
41
  end
56
42
 
57
43
  def event_from_exception(exception, hint = {})
@@ -60,12 +46,15 @@ module Sentry
60
46
 
61
47
  Event.new(configuration: configuration, integration_meta: integration_meta).tap do |event|
62
48
  event.add_exception_interface(exception)
49
+ event.add_threads_interface(crashed: true)
63
50
  end
64
51
  end
65
52
 
66
53
  def event_from_message(message, hint = {})
67
54
  integration_meta = Sentry.integrations[hint[:integration]]
68
- Event.new(configuration: configuration, integration_meta: integration_meta, message: message)
55
+ event = Event.new(configuration: configuration, integration_meta: integration_meta, message: message)
56
+ event.add_threads_interface(backtrace: caller)
57
+ event
69
58
  end
70
59
 
71
60
  def event_from_transaction(transaction)
@@ -82,16 +71,49 @@ module Sentry
82
71
 
83
72
  def send_event(event, hint = nil)
84
73
  event_type = event.is_a?(Event) ? event.type : event["type"]
85
- event = configuration.before_send.call(event, hint) if configuration.before_send && event_type == "event"
86
74
 
87
- if event.nil?
88
- configuration.logger.info(LOGGER_PROGNAME) { "Discarded event because before_send returned nil" }
89
- return
75
+ if event_type == "event" && configuration.before_send
76
+ event = configuration.before_send.call(event, hint)
77
+
78
+ if event.nil?
79
+ logger.info(LOGGER_PROGNAME) { "Discarded event because before_send returned nil" }
80
+ return
81
+ end
90
82
  end
91
83
 
92
84
  transport.send_event(event)
93
85
 
94
86
  event
87
+ rescue => e
88
+ logger.error(LOGGER_PROGNAME) { "#{event_type.capitalize} sending failed: #{e.message}" }
89
+ logger.error(LOGGER_PROGNAME) { "Unreported #{event_type.capitalize}: #{Event.get_log_message(event.to_hash)}" }
90
+ raise
91
+ end
92
+
93
+ private
94
+
95
+ def dispatch_background_event(event, hint)
96
+ Sentry.background_worker.perform do
97
+ send_event(event, hint)
98
+ end
95
99
  end
100
+
101
+ def dispatch_async_event(async_block, event, hint)
102
+ # We have to convert to a JSON-like hash, because background job
103
+ # processors (esp ActiveJob) may not like weird types in the event hash
104
+ event_hash = event.to_json_compatible
105
+
106
+ if async_block.arity == 2
107
+ hint = JSON.parse(JSON.generate(hint))
108
+ async_block.call(event_hash, hint)
109
+ else
110
+ async_block.call(event_hash)
111
+ end
112
+ rescue => e
113
+ event_type = event_hash["type"]
114
+ logger.error(LOGGER_PROGNAME) { "Async #{event_type} sending failed: #{e.message}" }
115
+ send_event(event, hint)
116
+ end
117
+
96
118
  end
97
119
  end