sentry-ruby-core 4.3.1 → 4.3.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 8a2e4ce39cece4f17353a14a3984cfaf57b9fc1f9288915a36f9c5ae56e719cd
4
- data.tar.gz: 77ebe61492554532ce811320fbae436735c82ac3a0586176ee53b040211d6b81
3
+ metadata.gz: 85c558cf77534e3d3fea7d30e417171302f485042b8a09b3a1114c714f1b17ec
4
+ data.tar.gz: d8077c3cfee56f1427d03770dc8d28e9920bbba4d97e14e983d3b7a5a949be95
5
5
  SHA512:
6
- metadata.gz: 34504541c4743476d4360e7b452e8a7a4b9a3bd66d80878a768d839d8fe00e5294c2e385d62d50527ddf957368a660c8276342abf72a82079583c0a33385e29d
7
- data.tar.gz: d050d0b1bf6346553db6cc02e84b144908d877bd1883243526b0366e21eb97e924cf2f23c2c8ad10383785a90e05337615041ac6d9c87c36694d6077e3f6481d
6
+ metadata.gz: 9cc8fa4030f678d6b2cd34d1c5752e4da6065527ed598e6f43a14ab6adcb44fbe4f104b99de9dd65d45995f726fc074bf3944891348ce4491a385ce22acfa493
7
+ data.tar.gz: 8fc20069fbddcb6dba3206ea8d7578c9da54f5a0812c0388e9e1afc983befcaaaa3d32390af78b6f3bee6294e997455dbcc807d7543380bc20740b314534dd7b
data/CHANGELOG.md CHANGED
@@ -1,5 +1,15 @@
1
1
  # Changelog
2
2
 
3
+ ## 4.3.2
4
+
5
+ - Correct type attribute's usages [#1354](https://github.com/getsentry/sentry-ruby/pull/1354)
6
+ - Fix sampling decision precedence [#1335](https://github.com/getsentry/sentry-ruby/pull/1335)
7
+ - Fix set_contexts [#1375](https://github.com/getsentry/sentry-ruby/pull/1375)
8
+ - Use thread variable instead of fiber variable to store the hub [#1380](https://github.com/getsentry/sentry-ruby/pull/1380)
9
+ - Fixes [#1374](https://github.com/getsentry/sentry-ruby/issues/1374)
10
+ - Fix Span/Transaction's nesting issue [#1382](https://github.com/getsentry/sentry-ruby/pull/1382)
11
+ - Fixes [#1372](https://github.com/getsentry/sentry-ruby/issues/1372)
12
+
3
13
  ## 4.3.1
4
14
 
5
15
  - Add Sentry.set_context helper [#1337](https://github.com/getsentry/sentry-ruby/pull/1337)
data/README.md CHANGED
@@ -10,23 +10,21 @@ _Bad software is everywhere, and we're tired of it. Sentry is on a mission to he
10
10
  Sentry SDK for Ruby
11
11
  ===========
12
12
 
13
-
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).**
15
-
16
- ---
13
+ | current version | build | coverage | downloads | semver stability |
14
+ | --- | ----- | -------- | --------- | ---------------- |
15
+ | [![Gem Version](https://img.shields.io/gem/v/sentry-ruby?label=sentry-ruby)](https://github.com/getsentry/sentry-ruby/blob/master/sentry-ruby/CHANGELOG.md) | ![Build Status](https://github.com/getsentry/sentry-ruby/workflows/sentry-ruby%20Test/badge.svg) | [![Coverage Status](https://img.shields.io/codecov/c/github/getsentry/sentry-ruby/master?logo=codecov)](https://codecov.io/gh/getsentry/sentry-ruby/branch/master) | [![Downloads](https://img.shields.io/gem/dt/sentry-ruby.svg)](https://rubygems.org/gems/sentry-ruby/) | [![SemVer stability](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) |
16
+ | [![Gem Version](https://img.shields.io/gem/v/sentry-rails?label=sentry-rails)](https://github.com/getsentry/sentry-ruby/blob/master/sentry-rails/CHANGELOG.md) | ![Build Status](https://github.com/getsentry/sentry-ruby/workflows/sentry-rails%20Test/badge.svg) | [![Coverage Status](https://img.shields.io/codecov/c/github/getsentry/sentry-ruby/master?logo=codecov)](https://codecov.io/gh/getsentry/sentry-ruby/branch/master) | [![Downloads](https://img.shields.io/gem/dt/sentry-rails.svg)](https://rubygems.org/gems/sentry-rails/) | [![SemVer stability](https://api.dependabot.com/badges/compatibility_score?dependency-name=sentry-rails&package-manager=bundler&version-scheme=semver)](https://dependabot.com/compatibility-score.html?dependency-name=sentry-rails&package-manager=bundler&version-scheme=semver) |
17
+ | [![Gem Version](https://img.shields.io/gem/v/sentry-sidekiq?label=sentry-sidekiq)](https://github.com/getsentry/sentry-ruby/blob/master/sentry-sidekiq/CHANGELOG.md) | ![Build Status](https://github.com/getsentry/sentry-ruby/workflows/sentry-sidekiq%20Test/badge.svg) | [![Coverage Status](https://img.shields.io/codecov/c/github/getsentry/sentry-ruby/master?logo=codecov)](https://codecov.io/gh/getsentry/sentry-ruby/branch/master) | [![Downloads](https://img.shields.io/gem/dt/sentry-sidekiq.svg)](https://rubygems.org/gems/sentry-sidekiq/) | [![SemVer stability](https://api.dependabot.com/badges/compatibility_score?dependency-name=sentry-sidekiq&package-manager=bundler&version-scheme=semver)](https://dependabot.com/compatibility-score.html?dependency-name=sentry-sidekiq&package-manager=bundler&version-scheme=semver) |
18
+ | [![Gem Version](https://img.shields.io/gem/v/sentry-delayed_job?label=sentry-delayed_job)](https://github.com/getsentry/sentry-ruby/blob/master/sentry-delayed_job/CHANGELOG.md) | ![Build Status](https://github.com/getsentry/sentry-ruby/workflows/sentry-delayed_job%20Test/badge.svg) | [![Coverage Status](https://img.shields.io/codecov/c/github/getsentry/sentry-ruby/master?logo=codecov)](https://codecov.io/gh/getsentry/sentry-ruby/branch/master) | [![Downloads](https://img.shields.io/gem/dt/sentry-delayed_job.svg)](https://rubygems.org/gems/sentry-delayed_job/) | [![SemVer stability](https://api.dependabot.com/badges/compatibility_score?dependency-name=sentry-delayed_job&package-manager=bundler&version-scheme=semver)](https://dependabot.com/compatibility-score.html?dependency-name=sentry-delayed_job&package-manager=bundler&version-scheme=semver) |
17
19
 
18
20
 
19
- [![Gem Version](https://img.shields.io/gem/v/sentry-ruby.svg)](https://rubygems.org/gems/sentry-ruby)
20
- ![Build Status](https://github.com/getsentry/sentry-ruby/workflows/sentry-ruby%20Test/badge.svg)
21
- [![Coverage Status](https://img.shields.io/codecov/c/github/getsentry/sentry-ruby/master?logo=codecov)](https://codecov.io/gh/getsentry/sentry-ruby/branch/master)
22
- [![Gem](https://img.shields.io/gem/dt/sentry-ruby.svg)](https://rubygems.org/gems/sentry-ruby/)
23
- [![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)
24
21
 
25
22
 
26
- [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
23
+ ## Migrate From sentry-raven
27
24
 
28
- The official Ruby-language client and integration layer for the [Sentry](https://github.com/getsentry/sentry) error reporting API.
25
+ **The old `sentry-raven` client has entered maintenance mode and was moved to [here](https://github.com/getsentry/sentry-ruby/tree/master/sentry-raven).**
29
26
 
27
+ 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/).
30
28
 
31
29
  ## Requirements
32
30
 
@@ -34,10 +32,6 @@ We test on Ruby 2.4, 2.5, 2.6, 2.7, and 3.0 at the latest patchlevel/teeny versi
34
32
 
35
33
  If you use self-hosted Sentry, please also make sure its version is above `20.6.0`.
36
34
 
37
- ## Migrate From sentry-raven
38
-
39
- 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/).
40
-
41
35
  ## Getting Started
42
36
 
43
37
  ### Install
@@ -247,10 +241,10 @@ Of course, you can always assign the information on a per-event basis:
247
241
  Sentry.capture_exception(exception, tags: {foo: "bar"})
248
242
  ```
249
243
 
250
- ## More Information
251
-
252
- - [Documentation](https://docs.sentry.io/platforms/ruby/)
253
- - [Bug Tracker](https://github.com/getsentry/sentry-ruby/issues)
254
- - [Forum](https://forum.sentry.io/)
255
- - [Discord](https://discord.gg/ez5KZN7)
244
+ ## Resources
256
245
 
246
+ * [![Ruby docs](https://img.shields.io/badge/documentation-sentry.io-green.svg?label=ruby%20docs)](https://docs.sentry.io/platforms/ruby/)
247
+ * [![Forum](https://img.shields.io/badge/forum-sentry-green.svg)](https://forum.sentry.io/c/sdks)
248
+ * [![Discord Chat](https://img.shields.io/discord/621778831602221064?logo=discord&logoColor=ffffff&color=7389D8)](https://discord.gg/PXa5Apfe7K)
249
+ * [![Stack Overflow](https://img.shields.io/badge/stack%20overflow-sentry-green.svg)](https://stackoverflow.com/questions/tagged/sentry)
250
+ * [![Twitter Follow](https://img.shields.io/twitter/follow/getsentry?label=getsentry&style=social)](https://twitter.com/intent/follow?screen_name=getsentry)
data/lib/sentry-ruby.rb CHANGED
@@ -68,7 +68,7 @@ module Sentry
68
68
  client = Client.new(config)
69
69
  scope = Scope.new(max_breadcrumbs: config.max_breadcrumbs)
70
70
  hub = Hub.new(client, scope)
71
- Thread.current[THREAD_LOCAL] = hub
71
+ Thread.current.thread_variable_set(THREAD_LOCAL, hub)
72
72
  @main_hub = hub
73
73
  @background_worker = Sentry::BackgroundWorker.new(config)
74
74
  end
@@ -92,7 +92,7 @@ module Sentry
92
92
  # ideally, we should do this proactively whenever a new thread is created
93
93
  # but it's impossible for the SDK to keep track every new thread
94
94
  # so we need to use this rather passive way to make sure the app doesn't crash
95
- Thread.current[THREAD_LOCAL] || clone_hub_to_current_thread
95
+ Thread.current.thread_variable_get(THREAD_LOCAL) || clone_hub_to_current_thread
96
96
  end
97
97
 
98
98
  # Returns the current active client.
@@ -107,7 +107,7 @@ module Sentry
107
107
 
108
108
  # Clones the main thread's active hub and stores it to the current thread.
109
109
  def clone_hub_to_current_thread
110
- Thread.current[THREAD_LOCAL] = get_main_hub.clone
110
+ Thread.current.thread_variable_set(THREAD_LOCAL, get_main_hub.clone)
111
111
  end
112
112
 
113
113
  # Takes a block and yields the current active scope.
data/lib/sentry/client.rb CHANGED
@@ -72,7 +72,7 @@ module Sentry
72
72
  def send_event(event, hint = nil)
73
73
  event_type = event.is_a?(Event) ? event.type : event["type"]
74
74
 
75
- if event_type == "event" && configuration.before_send
75
+ if event_type != TransactionEvent::TYPE && configuration.before_send
76
76
  event = configuration.before_send.call(event, hint)
77
77
 
78
78
  if event.nil?
@@ -85,8 +85,9 @@ module Sentry
85
85
 
86
86
  event
87
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)}" }
88
+ loggable_event_type = (event_type || "event").capitalize
89
+ logger.error(LOGGER_PROGNAME) { "#{loggable_event_type} sending failed: #{e.message}" }
90
+ logger.error(LOGGER_PROGNAME) { "Unreported #{loggable_event_type}: #{Event.get_log_message(event.to_hash)}" }
90
91
  raise
91
92
  end
92
93
 
@@ -110,8 +111,8 @@ module Sentry
110
111
  async_block.call(event_hash)
111
112
  end
112
113
  rescue => e
113
- event_type = event_hash["type"]
114
- logger.error(LOGGER_PROGNAME) { "Async #{event_type} sending failed: #{e.message}" }
114
+ loggable_event_type = event_hash["type"] || "event"
115
+ logger.error(LOGGER_PROGNAME) { "Async #{loggable_event_type} sending failed: #{e.message}" }
115
116
  send_event(event, hint)
116
117
  end
117
118
 
data/lib/sentry/event.rb CHANGED
@@ -100,7 +100,6 @@ module Sentry
100
100
  end
101
101
 
102
102
  def type
103
- "event"
104
103
  end
105
104
 
106
105
  def to_hash
data/lib/sentry/hub.rb CHANGED
@@ -69,11 +69,19 @@ module Sentry
69
69
  @stack.pop
70
70
  end
71
71
 
72
- def start_transaction(transaction: nil, configuration: Sentry.configuration, **options)
72
+ def start_transaction(transaction: nil, configuration: Sentry.configuration, custom_sampling_context: {}, **options)
73
73
  return unless configuration.tracing_enabled?
74
74
 
75
75
  transaction ||= Transaction.new(**options)
76
- transaction.set_initial_sample_decision(configuration: current_client.configuration)
76
+
77
+ sampling_context = {
78
+ transaction_context: transaction.to_hash,
79
+ parent_sampled: transaction.parent_sampled
80
+ }
81
+
82
+ sampling_context.merge!(custom_sampling_context)
83
+
84
+ transaction.set_initial_sample_decision(configuration: current_client.configuration, sampling_context: sampling_context)
77
85
  transaction
78
86
  end
79
87
 
data/lib/sentry/scope.rb CHANGED
@@ -126,7 +126,7 @@ module Sentry
126
126
 
127
127
  def set_contexts(contexts_hash)
128
128
  check_argument_type!(contexts_hash, Hash)
129
- @contexts = contexts_hash
129
+ @contexts.merge!(contexts_hash)
130
130
  end
131
131
 
132
132
  def set_context(key, value)
@@ -146,8 +146,7 @@ module Sentry
146
146
  end
147
147
 
148
148
  def get_transaction
149
- # transaction will always be the first in the span_recorder
150
- span.span_recorder.spans.first if span
149
+ span.transaction if span
151
150
  end
152
151
 
153
152
  def get_span
data/lib/sentry/span.rb CHANGED
@@ -19,7 +19,7 @@ module Sentry
19
19
 
20
20
 
21
21
  attr_reader :trace_id, :span_id, :parent_span_id, :sampled, :start_timestamp, :timestamp, :description, :op, :status, :tags, :data
22
- attr_accessor :span_recorder
22
+ attr_accessor :span_recorder, :transaction
23
23
 
24
24
  def initialize(description: nil, op: nil, status: nil, trace_id: nil, parent_span_id: nil, sampled: nil, start_timestamp: nil, timestamp: nil)
25
25
  @trace_id = trace_id || SecureRandom.uuid.delete("-")
@@ -78,7 +78,15 @@ module Sentry
78
78
 
79
79
  def start_child(**options)
80
80
  options = options.dup.merge(trace_id: @trace_id, parent_span_id: @span_id, sampled: @sampled)
81
- Span.new(**options)
81
+ new_span = Span.new(**options)
82
+ new_span.transaction = transaction
83
+ new_span.span_recorder = span_recorder
84
+
85
+ if span_recorder
86
+ span_recorder.add(new_span)
87
+ end
88
+
89
+ new_span
82
90
  end
83
91
 
84
92
  def with_child_span(**options, &block)
@@ -17,12 +17,8 @@ module Sentry
17
17
 
18
18
  @name = name
19
19
  @parent_sampled = parent_sampled
20
- set_span_recorder
21
- end
22
-
23
- def set_span_recorder
24
- @span_recorder = SpanRecorder.new(1000)
25
- @span_recorder.add(self)
20
+ @transaction = self
21
+ init_span_recorder
26
22
  end
27
23
 
28
24
  def self.from_sentry_trace(sentry_trace, configuration: Sentry.configuration, **options)
@@ -33,14 +29,14 @@ module Sentry
33
29
  return if match.nil?
34
30
  trace_id, parent_span_id, sampled_flag = match[1..3]
35
31
 
36
- sampled =
32
+ parent_sampled =
37
33
  if sampled_flag.nil?
38
34
  nil
39
35
  else
40
36
  sampled_flag != "0"
41
37
  end
42
38
 
43
- new(trace_id: trace_id, parent_span_id: parent_span_id, parent_sampled: sampled, sampled: sampled, **options)
39
+ new(trace_id: trace_id, parent_span_id: parent_span_id, parent_sampled: parent_sampled, **options)
44
40
  end
45
41
 
46
42
  def to_hash
@@ -49,20 +45,9 @@ module Sentry
49
45
  hash
50
46
  end
51
47
 
52
- def start_child(**options)
53
- child_span = super
54
- child_span.span_recorder = @span_recorder
55
-
56
- if @sampled
57
- @span_recorder.add(child_span)
58
- end
59
-
60
- child_span
61
- end
62
-
63
48
  def deep_dup
64
49
  copy = super
65
- copy.set_span_recorder
50
+ copy.init_span_recorder(@span_recorder.max_length)
66
51
 
67
52
  @span_recorder.spans.each do |span|
68
53
  # span_recorder's first span is the current span, which should not be added to the copy's spans
@@ -73,7 +58,7 @@ module Sentry
73
58
  copy
74
59
  end
75
60
 
76
- def set_initial_sample_decision(sampling_context: {}, configuration: Sentry.configuration)
61
+ def set_initial_sample_decision(sampling_context:, configuration: Sentry.configuration)
77
62
  unless configuration.tracing_enabled?
78
63
  @sampled = false
79
64
  return
@@ -81,20 +66,19 @@ module Sentry
81
66
 
82
67
  return unless @sampled.nil?
83
68
 
84
- transaction_description = generate_transaction_description
85
-
86
- logger = configuration.logger
87
- sample_rate = configuration.traces_sample_rate
88
69
  traces_sampler = configuration.traces_sampler
89
70
 
90
- if traces_sampler.is_a?(Proc)
91
- sampling_context = sampling_context.merge(
92
- parent_sampled: @parent_sampled,
93
- transaction_context: self.to_hash
94
- )
71
+ sample_rate =
72
+ if traces_sampler.is_a?(Proc)
73
+ traces_sampler.call(sampling_context)
74
+ elsif !sampling_context[:parent_sampled].nil?
75
+ sampling_context[:parent_sampled]
76
+ else
77
+ configuration.traces_sample_rate
78
+ end
95
79
 
96
- sample_rate = traces_sampler.call(sampling_context)
97
- end
80
+ transaction_description = generate_transaction_description
81
+ logger = configuration.logger
98
82
 
99
83
  unless [true, false].include?(sample_rate) || (sample_rate.is_a?(Numeric) && sample_rate >= 0.0 && sample_rate <= 1.0)
100
84
  @sampled = false
@@ -137,6 +121,13 @@ module Sentry
137
121
  hub.capture_event(event)
138
122
  end
139
123
 
124
+ protected
125
+
126
+ def init_span_recorder(limit = 1000)
127
+ @span_recorder = SpanRecorder.new(limit)
128
+ @span_recorder.add(self)
129
+ end
130
+
140
131
  private
141
132
 
142
133
  def generate_transaction_description
@@ -2,6 +2,8 @@
2
2
 
3
3
  module Sentry
4
4
  class TransactionEvent < Event
5
+ TYPE = "transaction"
6
+
5
7
  ATTRIBUTES = %i(
6
8
  event_id level timestamp start_timestamp
7
9
  release environment server_name modules
@@ -17,7 +19,7 @@ module Sentry
17
19
  end
18
20
 
19
21
  def type
20
- "transaction"
22
+ TYPE
21
23
  end
22
24
 
23
25
  def to_hash
@@ -24,7 +24,7 @@ module Sentry
24
24
  return
25
25
  end
26
26
 
27
- encoded_data = prepare_encoded_event(event)
27
+ encoded_data = encode(event)
28
28
 
29
29
  return nil unless encoded_data
30
30
 
@@ -45,29 +45,22 @@ module Sentry
45
45
  'Sentry ' + fields.map { |key, value| "#{key}=#{value}" }.join(', ')
46
46
  end
47
47
 
48
- def encode(event_hash)
49
- event_id = event_hash[:event_id] || event_hash['event_id']
50
- event_type = event_hash[:type] || event_hash['type']
48
+ def encode(event)
49
+ # Convert to hash
50
+ event_hash = event.to_hash
51
+
52
+ event_id = event_hash[:event_id] || event_hash["event_id"]
53
+ item_type = event_hash[:type] || event_hash["type"] || "event"
51
54
 
52
55
  envelope = <<~ENVELOPE
53
56
  {"event_id":"#{event_id}","dsn":"#{configuration.dsn.to_s}","sdk":#{Sentry.sdk_meta.to_json},"sent_at":"#{Sentry.utc_now.iso8601}"}
54
- {"type":"#{event_type}","content_type":"application/json"}
57
+ {"type":"#{item_type}","content_type":"application/json"}
55
58
  #{JSON.generate(event_hash)}
56
59
  ENVELOPE
57
60
 
58
- envelope
59
- end
60
-
61
- private
62
-
63
- def prepare_encoded_event(event)
64
- # Convert to hash
65
- event_hash = event.to_hash
61
+ configuration.logger.info(LOGGER_PROGNAME) { "Sending envelope [#{item_type}] #{event_id} to Sentry" }
66
62
 
67
- event_id = event_hash[:event_id] || event_hash["event_id"]
68
- event_type = event_hash[:type] || event_hash["type"]
69
- configuration.logger.info(LOGGER_PROGNAME) { "Sending #{event_type} #{event_id} to Sentry" }
70
- encode(event_hash)
63
+ envelope
71
64
  end
72
65
  end
73
66
  end
@@ -1,3 +1,3 @@
1
1
  module Sentry
2
- VERSION = "4.3.1"
2
+ VERSION = "4.3.2"
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: sentry-ruby-core
3
3
  version: !ruby/object:Gem::Version
4
- version: 4.3.1
4
+ version: 4.3.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Sentry Team
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2021-03-24 00:00:00.000000000 Z
11
+ date: 2021-04-06 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: faraday
@@ -124,7 +124,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
124
124
  - !ruby/object:Gem::Version
125
125
  version: '0'
126
126
  requirements: []
127
- rubygems_version: 3.0.3
127
+ rubygems_version: 3.0.3.1
128
128
  signing_key:
129
129
  specification_version: 4
130
130
  summary: A gem that provides a client interface for the Sentry error logger