sentry-ruby 0.2.0 → 4.1.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: f8f89cd1b0354cede1b5aab23b0b8652fed01bcebc3af7f0cb45a13d0f1d99ba
4
- data.tar.gz: 38fa765f4acb958b8170a31017028a45cce342667bd8dee7dbff07c4e097ffc5
3
+ metadata.gz: 4cf12a695558927106256af0d85575b36bf2675b1ba87cf13baec2e40354055f
4
+ data.tar.gz: 418475b2abe315f62b642d38ced99b6c16b78ffa1fef7ef645203bf46dff72e9
5
5
  SHA512:
6
- metadata.gz: be0a56af7629bf528be987f62bcb0a4fd12430d75b7541acc6d946314306ab4968c214eb7a533695dcd8aa3b3f434225f8dffceecee4bc39a8b5bd45e168e3d1
7
- data.tar.gz: 383d6e88932c6ff3f6e79ca3c35c05d7a23151dd85db057e45dc8577f88673e8195659df3a0c01d71b1e67a61e7f1008eb36ab294047fdeea5cedf2a7d02f92c
6
+ metadata.gz: f4b5c90aad8d0249c29e901beb3569d4e0a89c53d35f8da459e97eb4134b989728c89ebc913b59f0db1b85c1903beedfcfb5968d5833d3fc2d5a6d209308212c
7
+ data.tar.gz: 86acbab302abb4d2cd66c9cc447486dcbebef127bbfbc03df69f2085057965166c3afc6a3f969d046b157255d1e88d54f85e7fac5581daa112e798eda04db2c7
@@ -1,5 +1,75 @@
1
1
  # Changelog
2
2
 
3
+ ## 4.1.1
4
+
5
+ - Fix NoMethodError when sending is not allowed [#1161](https://github.com/getsentry/sentry-ruby/pull/1161)
6
+ - Add notification for users who still use deprecated middlewares [#1160](https://github.com/getsentry/sentry-ruby/pull/1160)
7
+ - Improve top-level api safety [#1161](https://github.com/getsentry/sentry-ruby/pull/1161)
8
+
9
+ ## 4.1.0
10
+
11
+ - Separate rack integration [#1138](https://github.com/getsentry/sentry-ruby/pull/1138)
12
+ - Fixes [#1136](https://github.com/getsentry/sentry-ruby/pull/1136)
13
+ - Fix event sampling [#1144](https://github.com/getsentry/sentry-ruby/pull/1144)
14
+ - Merge & rename 2 Rack middlewares [#1147](https://github.com/getsentry/sentry-ruby/pull/1147)
15
+ - Fixes [#1153](https://github.com/getsentry/sentry-ruby/pull/1153)
16
+ - Removed `Sentry::Rack::Tracing` middleware and renamed `Sentry::Rack::CaptureException` to `Sentry::Rack::CaptureExceptions`.
17
+ - Deep-copy spans [#1148](https://github.com/getsentry/sentry-ruby/pull/1148)
18
+ - Move span recorder related code from Span to Transaction [#1149](https://github.com/getsentry/sentry-ruby/pull/1149)
19
+ - Check SDK initialization before running integrations [#1151](https://github.com/getsentry/sentry-ruby/pull/1151)
20
+ - Fixes [#1145](https://github.com/getsentry/sentry-ruby/pull/1145)
21
+ - Refactor transport [#1154](https://github.com/getsentry/sentry-ruby/pull/1154)
22
+ - Implement non-blocking event sending [#1155](https://github.com/getsentry/sentry-ruby/pull/1155)
23
+ - Added `background_worker_threads` configuration option.
24
+
25
+ ### Noticeable Changes
26
+
27
+ #### Middleware Changes
28
+
29
+ `Sentry::Rack::Tracing` is now removed. And `Sentry::Rack::CaptureException` has been renamed to `Sentry::Rack::CaptureExceptions`.
30
+
31
+ #### Events Are Sent Asynchronously
32
+
33
+ `sentry-ruby` now sends events asynchronously by default. The functionality works like this:
34
+
35
+ 1. When the SDK is initialized, a `Sentry::BackgroundWorker` will be initialized too.
36
+ 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.
37
+ 3. The worker will have a number of threads. And the one of the idle threads will pick the job and call `Client#send_event`.
38
+ - If all the threads are busy, new jobs will be put into a queue, which has a limit of 30.
39
+ - If the queue size is exceeded, new events will be dropped.
40
+
41
+ However, if you still prefer to use your own async approach, that's totally fine. If you have `config.async` set, the worker won't initialize a thread pool and won't be used either.
42
+
43
+ This functionality also introduces a new `background_worker_threads` config option. It allows you to decide how many threads should the worker hold. By default, the value will be the number of the processors your machine has. For example, if your machine has 4 processors, the value would be 4.
44
+
45
+ Of course, you can always override the value to fit your use cases, like
46
+
47
+ ```ruby
48
+ config.background_worker_threads = 5 # the worker will have 5 threads for sending events
49
+ ```
50
+
51
+ You can also disable this new non-blocking behaviour by giving a `0` value:
52
+
53
+ ```ruby
54
+ config.background_worker_threads = 0 # all events will be sent synchronously
55
+ ```
56
+
57
+ ## 4.0.1
58
+
59
+ - Add rake integration: [1137](https://github.com/getsentry/sentry-ruby/pull/1137)
60
+ - Make Event's interfaces accessible: [1135](https://github.com/getsentry/sentry-ruby/pull/1135)
61
+ - ActiveSupportLogger should only record events that has a started time: [1132](https://github.com/getsentry/sentry-ruby/pull/1132)
62
+
63
+ ## 4.0.0
64
+
65
+ - Only documents update for the official release and no API/feature changes.
66
+
67
+ ## 0.3.0
68
+
69
+ - Major API changes: [1123](https://github.com/getsentry/sentry-ruby/pull/1123)
70
+ - Support event hint: [1122](https://github.com/getsentry/sentry-ruby/pull/1122)
71
+ - Add request-id tag to events: [1120](https://github.com/getsentry/sentry-ruby/pull/1120) (by @tvec)
72
+
3
73
  ## 0.2.0
4
74
 
5
75
  - Multiple fixes and refactorings
data/Gemfile CHANGED
@@ -8,7 +8,7 @@ gem "rspec", "~> 3.0"
8
8
  gem "codecov"
9
9
 
10
10
  gem "pry"
11
- gem "rack"
11
+ gem "rack" unless ENV["WITHOUT_RACK"] == "1"
12
12
 
13
13
  gem "benchmark-ips"
14
14
  gem "benchmark_driver"
data/README.md CHANGED
@@ -7,6 +7,8 @@
7
7
 
8
8
  # sentry-ruby, the Ruby Client for Sentry
9
9
 
10
+ **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
+
10
12
  ---
11
13
 
12
14
 
@@ -17,7 +19,7 @@
17
19
  [![SemVer](https://api.dependabot.com/badges/compatibility_score?dependency-name=sentry-ruby&package-manager=bundler&version-scheme=semver)](https://dependabot.com/compatibility-score.html?dependency-name=sentry-ruby&package-manager=bundler&version-scheme=semver)
18
20
 
19
21
 
20
- [Documentation](https://docs.sentry.io/clients/ruby/) | [Bug Tracker](https://github.com/getsentry/sentry-ruby/issues) | [Forum](https://forum.sentry.io/) | IRC: irc.freenode.net, #sentry
22
+ [Documentation](https://docs.sentry.io/platforms/ruby/) | [Bug Tracker](https://github.com/getsentry/sentry-ruby/issues) | [Forum](https://forum.sentry.io/) | IRC: irc.freenode.net, #sentry
21
23
 
22
24
  The official Ruby-language client and integration layer for the [Sentry](https://github.com/getsentry/sentry) error reporting API.
23
25
 
@@ -26,6 +28,10 @@ The official Ruby-language client and integration layer for the [Sentry](https:/
26
28
 
27
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.
28
30
 
31
+ ## Migrate From sentry-raven
32
+
33
+ If you're using `sentry-raven`, we recommend you to migrate to this new SDK. You can find the benefits of migrating and how to do it in our [migration guide](https://docs.sentry.io/platforms/ruby/migration/).
34
+
29
35
  ## Getting Started
30
36
 
31
37
  ### Install
@@ -70,17 +76,46 @@ Sentry.init do |config|
70
76
  end
71
77
  ```
72
78
 
79
+ ### Performance Monitoring
80
+
81
+ You can activate performance monitoring by enabling traces sampling:
82
+
83
+ ```ruby
84
+ Sentry.init do |config|
85
+ # set a uniform sample rate between 0.0 and 1.0
86
+ config.traces_sample_rate = 0.2
87
+
88
+ # or control sampling dynamically
89
+ config.traces_sampler = lambda do |sampling_context|
90
+ # sampling_context[:transaction_context] contains the information about the transaction
91
+ # sampling_context[:parent_sampled] contains the transaction's parent's sample decision
92
+ true # return value can be a boolean or a float between 0.0 and 1.0
93
+ end
94
+ end
95
+ ```
96
+
97
+ To lean more about performance monitoring, please visit the [official documentation](https://docs.sentry.io/platforms/ruby/performance).
98
+
73
99
  ### Usage
74
100
 
75
101
  `sentry-ruby` has a default integration with `Rack`, so you only need to use the middleware in your application like:
76
102
 
77
- ```
78
- require 'rack'
103
+ ```ruby
79
104
  require 'sentry-ruby'
80
105
 
81
- use Sentry::Rack::CaptureException
106
+ Sentry.init do |config|
107
+ config.dsn = 'https://examplePublicKey@o0.ingest.sentry.io/0'
108
+
109
+ # To activate performance monitoring, set one of these options.
110
+ # We recommend adjusting the value in production:
111
+ config.traces_sample_rate = 0.5
112
+ # or
113
+ config.traces_sampler = lambda do |context|
114
+ true
115
+ end
116
+ end
82
117
 
83
- run theapp
118
+ use Sentry::Rack::CaptureExceptions
84
119
  ```
85
120
 
86
121
  Otherwise, Sentry you can always use the capture helpers manually
@@ -104,9 +139,9 @@ We also provide integrations with popular frameworks/libraries with the related
104
139
 
105
140
  You're all set - but there's a few more settings you may want to know about too!
106
141
 
107
- #### async
142
+ #### Blocking v.s. Non-blocking
108
143
 
109
- When an error or message occurs, the notification is immediately sent to Sentry. Sentry can be configured to send asynchronously:
144
+ **Before version 4.1.0**, `sentry-ruby` sends every event immediately. But it can be configured to send asynchronously:
110
145
 
111
146
  ```ruby
112
147
  config.async = lambda { |event|
@@ -130,6 +165,41 @@ class SentryJob < ActiveJob::Base
130
165
  end
131
166
  ```
132
167
 
168
+
169
+ **After version 4.1.0**, `sentry-ruby` sends events asynchronously by default. The functionality works like this:
170
+
171
+ 1. When the SDK is initialized, a `Sentry::BackgroundWorker` will be initialized too.
172
+ 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.
173
+ 3. The worker will have a number of threads. And the one of the idle threads will pick the job and call `Client#send_event`.
174
+ - If all the threads are busy, new jobs will be put into a queue, which has a limit of 30.
175
+ - If the queue size is exceeded, new events will be dropped.
176
+
177
+ However, if you still prefer to use your own async approach, that's totally fine. If you have `config.async` set, the worker won't initialize a thread pool and won't be used either.
178
+
179
+ ##### About `Sentry::BackgroundWorker`
180
+
181
+ - The worker is built on top of the [concurrent-ruby](https://github.com/ruby-concurrency/concurrent-ruby) gem's [ThreadPoolExecutor](http://ruby-concurrency.github.io/concurrent-ruby/master/Concurrent/ThreadPoolExecutor.html), which is also used by Rails ActiveJob's async adapter. This should minimize the risk of messing up client applications with our own thread pool implementaion.
182
+
183
+ This functionality also introduces a new `background_worker_threads` config option. It allows you to decide how many threads should the worker hold. By default, the value will be the number of the processors your machine has. For example, if your machine has 4 processors, the value would be 4.
184
+
185
+ Of course, you can always override the value to fit your use cases, like
186
+
187
+ ```ruby
188
+ config.background_worker_threads = 5 # the worker will have 5 threads for sending events
189
+ ```
190
+
191
+ You can also disable this new non-blocking behaviour by giving a `0` value:
192
+
193
+ ```ruby
194
+ config.background_worker_threads = 0 # all events will be sent synchronously
195
+ ```
196
+
197
+ If you want to send a particular event immediately, you can use event hints to do it:
198
+
199
+ ```ruby
200
+ Sentry.capture_message("send me now!", hint: { background: false })
201
+ ```
202
+
133
203
  #### Contexts
134
204
 
135
205
  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:
@@ -148,6 +218,15 @@ end
148
218
  Sentry.capture_exception(exception) # the event will carry all those information now
149
219
  ```
150
220
 
221
+ Or use top-level setters
222
+
223
+
224
+ ```ruby
225
+ Sentry.set_user(id: 1, email: "test@example.com")
226
+ Sentry.set_tags(tag_1: "foo", tag_2: "bar")
227
+ Sentry.set_extras(order_number: 1234, tickets_count: 4)
228
+ ```
229
+
151
230
  Or build up a temporary scope for local information:
152
231
 
153
232
  ```ruby
@@ -172,7 +251,8 @@ Sentry.capture_exception(exception, tags: {foo: "bar"})
172
251
 
173
252
  ## More Information
174
253
 
175
- * [Documentation](https://docs.sentry.io/clients/ruby/)
254
+ * [Documentation](https://docs.sentry.io/platforms/ruby/)
176
255
  * [Bug Tracker](https://github.com/getsentry/sentry-ruby/issues)
177
256
  * [Forum](https://forum.sentry.io/)
178
257
  - [Discord](https://discord.gg/ez5KZN7)
258
+
@@ -1,3 +1,6 @@
1
+ require "forwardable"
2
+ require "time"
3
+
1
4
  require "sentry/version"
2
5
  require "sentry/core_ext/object/deep_dup"
3
6
  require "sentry/configuration"
@@ -7,7 +10,17 @@ require "sentry/transaction_event"
7
10
  require "sentry/span"
8
11
  require "sentry/transaction"
9
12
  require "sentry/hub"
10
- require "sentry/rack"
13
+ require "sentry/background_worker"
14
+
15
+ def safely_require(lib)
16
+ begin
17
+ require lib
18
+ rescue LoadError
19
+ end
20
+ end
21
+
22
+ safely_require "sentry/rake"
23
+ safely_require "sentry/rack"
11
24
 
12
25
  module Sentry
13
26
  class Error < StandardError
@@ -28,6 +41,12 @@ module Sentry
28
41
  end
29
42
 
30
43
  class << self
44
+ extend Forwardable
45
+
46
+ def_delegators :get_current_scope, :set_tags, :set_extras, :set_user
47
+
48
+ attr_accessor :background_worker
49
+
31
50
  def init(&block)
32
51
  config = Configuration.new
33
52
  yield(config)
@@ -36,6 +55,11 @@ module Sentry
36
55
  hub = Hub.new(client, scope)
37
56
  Thread.current[THREAD_LOCAL] = hub
38
57
  @main_hub = hub
58
+ @background_worker = Sentry::BackgroundWorker.new(config)
59
+ end
60
+
61
+ def initialized?
62
+ !!@main_hub
39
63
  end
40
64
 
41
65
  def get_main_hub
@@ -46,8 +70,8 @@ module Sentry
46
70
  configuration.logger
47
71
  end
48
72
 
49
- def breadcrumbs
50
- get_current_scope.breadcrumbs
73
+ def add_breadcrumb(breadcrumb, &block)
74
+ get_current_scope.breadcrumbs.record(breadcrumb, &block)
51
75
  end
52
76
 
53
77
  def configuration
@@ -55,7 +79,7 @@ module Sentry
55
79
  end
56
80
 
57
81
  def get_current_client
58
- get_current_hub.current_client
82
+ get_current_hub&.current_client
59
83
  end
60
84
 
61
85
  def get_current_hub
@@ -72,15 +96,15 @@ module Sentry
72
96
  end
73
97
 
74
98
  def get_current_scope
75
- get_current_hub.current_scope
99
+ get_current_hub&.current_scope
76
100
  end
77
101
 
78
102
  def with_scope(&block)
79
- get_current_hub.with_scope(&block)
103
+ get_current_hub&.with_scope(&block)
80
104
  end
81
105
 
82
106
  def configure_scope(&block)
83
- get_current_hub.configure_scope(&block)
107
+ get_current_hub&.configure_scope(&block)
84
108
  end
85
109
 
86
110
  def send_event(event)
@@ -88,23 +112,23 @@ module Sentry
88
112
  end
89
113
 
90
114
  def capture_event(event)
91
- get_current_hub.capture_event(event)
115
+ get_current_hub&.capture_event(event)
92
116
  end
93
117
 
94
118
  def capture_exception(exception, **options, &block)
95
- get_current_hub.capture_exception(exception, **options, &block)
119
+ get_current_hub&.capture_exception(exception, **options, &block)
96
120
  end
97
121
 
98
122
  def capture_message(message, **options, &block)
99
- get_current_hub.capture_message(message, **options, &block)
123
+ get_current_hub&.capture_message(message, **options, &block)
100
124
  end
101
125
 
102
126
  def start_transaction(**options)
103
- get_current_hub.start_transaction(**options)
127
+ get_current_hub&.start_transaction(**options)
104
128
  end
105
129
 
106
130
  def last_event_id
107
- get_current_hub.last_event_id
131
+ get_current_hub&.last_event_id
108
132
  end
109
133
 
110
134
  def sys_command(command)
@@ -0,0 +1,37 @@
1
+ require "concurrent/executor/thread_pool_executor"
2
+ require "concurrent/executor/immediate_executor"
3
+
4
+ module Sentry
5
+ class BackgroundWorker
6
+ attr_reader :max_queue, :number_of_threads
7
+
8
+ def initialize(configuration)
9
+ @max_queue = 30
10
+ @number_of_threads = configuration.background_worker_threads
11
+
12
+ @executor =
13
+ if configuration.async?
14
+ configuration.logger.debug(LOGGER_PROGNAME) { "config.async is set, BackgroundWorker is disabled" }
15
+ Concurrent::ImmediateExecutor.new
16
+ elsif @number_of_threads == 0
17
+ configuration.logger.debug(LOGGER_PROGNAME) { "config.background_worker_threads is set to 0, all events will be sent synchronously" }
18
+ Concurrent::ImmediateExecutor.new
19
+ else
20
+ configuration.logger.debug(LOGGER_PROGNAME) { "initialized a background worker with #{@number_of_threads} threads" }
21
+
22
+ Concurrent::ThreadPoolExecutor.new(
23
+ min_threads: 0,
24
+ max_threads: @number_of_threads,
25
+ max_queue: @max_queue,
26
+ fallback_policy: :discard
27
+ )
28
+ end
29
+ end
30
+
31
+ def perform(&block)
32
+ @executor.post do
33
+ block.call
34
+ end
35
+ end
36
+ end
37
+ end
@@ -2,13 +2,13 @@ module Sentry
2
2
  class Breadcrumb
3
3
  attr_accessor :category, :data, :message, :level, :timestamp, :type
4
4
 
5
- def initialize
6
- @category = nil
7
- @data = {}
8
- @level = nil
9
- @message = nil
10
- @timestamp = Sentry.utc_now.to_i
11
- @type = nil
5
+ def initialize(category: nil, data: nil, message: nil, timestamp: nil, level: nil, type: nil)
6
+ @category = category
7
+ @data = data || {}
8
+ @level = level
9
+ @message = message
10
+ @timestamp = timestamp || Sentry.utc_now.to_i
11
+ @type = type
12
12
  end
13
13
 
14
14
  def to_hash
@@ -58,17 +58,15 @@ module Sentry
58
58
  last_crumb = current_breadcrumbs.peek
59
59
  # try to avoid dupes from logger broadcasts
60
60
  if last_crumb.nil? || last_crumb.message != message
61
- current_breadcrumbs.record do |crumb|
62
- crumb.level = Sentry::Breadcrumb::SentryLogger::LEVELS.fetch(severity, nil)
63
- crumb.category = category
64
- crumb.message = message
65
- crumb.type =
66
- if severity >= 3
67
- "error"
68
- else
69
- crumb.level
70
- end
71
- end
61
+ level = Sentry::Breadcrumb::SentryLogger::LEVELS.fetch(severity, nil)
62
+ crumb = Sentry::Breadcrumb.new(
63
+ level: level,
64
+ category: category,
65
+ message: message,
66
+ type: severity >= 3 ? "error" : level
67
+ )
68
+
69
+ Sentry.add_breadcrumb(crumb)
72
70
  end
73
71
  end
74
72
 
@@ -80,7 +78,7 @@ module Sentry
80
78
  end
81
79
 
82
80
  def current_breadcrumbs
83
- Sentry.breadcrumbs
81
+ Sentry.get_current_scope.breadcrumbs
84
82
  end
85
83
  end
86
84
  end