sentry-ruby 5.3.1 → 5.16.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (76) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +11 -0
  3. data/.rspec +2 -0
  4. data/.yardopts +2 -0
  5. data/CHANGELOG.md +313 -0
  6. data/Gemfile +26 -0
  7. data/Makefile +4 -0
  8. data/README.md +11 -8
  9. data/Rakefile +20 -0
  10. data/bin/console +18 -0
  11. data/bin/setup +8 -0
  12. data/lib/sentry/background_worker.rb +79 -0
  13. data/lib/sentry/backpressure_monitor.rb +75 -0
  14. data/lib/sentry/backtrace.rb +124 -0
  15. data/lib/sentry/baggage.rb +70 -0
  16. data/lib/sentry/breadcrumb/sentry_logger.rb +90 -0
  17. data/lib/sentry/breadcrumb.rb +76 -0
  18. data/lib/sentry/breadcrumb_buffer.rb +64 -0
  19. data/lib/sentry/check_in_event.rb +60 -0
  20. data/lib/sentry/client.rb +248 -0
  21. data/lib/sentry/configuration.rb +650 -0
  22. data/lib/sentry/core_ext/object/deep_dup.rb +61 -0
  23. data/lib/sentry/core_ext/object/duplicable.rb +155 -0
  24. data/lib/sentry/cron/configuration.rb +23 -0
  25. data/lib/sentry/cron/monitor_check_ins.rb +75 -0
  26. data/lib/sentry/cron/monitor_config.rb +53 -0
  27. data/lib/sentry/cron/monitor_schedule.rb +42 -0
  28. data/lib/sentry/dsn.rb +53 -0
  29. data/lib/sentry/envelope.rb +93 -0
  30. data/lib/sentry/error_event.rb +38 -0
  31. data/lib/sentry/event.rb +156 -0
  32. data/lib/sentry/exceptions.rb +9 -0
  33. data/lib/sentry/hub.rb +316 -0
  34. data/lib/sentry/integrable.rb +32 -0
  35. data/lib/sentry/interface.rb +16 -0
  36. data/lib/sentry/interfaces/exception.rb +43 -0
  37. data/lib/sentry/interfaces/request.rb +134 -0
  38. data/lib/sentry/interfaces/single_exception.rb +67 -0
  39. data/lib/sentry/interfaces/stacktrace.rb +87 -0
  40. data/lib/sentry/interfaces/stacktrace_builder.rb +79 -0
  41. data/lib/sentry/interfaces/threads.rb +42 -0
  42. data/lib/sentry/linecache.rb +47 -0
  43. data/lib/sentry/logger.rb +20 -0
  44. data/lib/sentry/net/http.rb +106 -0
  45. data/lib/sentry/profiler.rb +233 -0
  46. data/lib/sentry/propagation_context.rb +134 -0
  47. data/lib/sentry/puma.rb +32 -0
  48. data/lib/sentry/rack/capture_exceptions.rb +79 -0
  49. data/lib/sentry/rack.rb +5 -0
  50. data/lib/sentry/rake.rb +28 -0
  51. data/lib/sentry/redis.rb +108 -0
  52. data/lib/sentry/release_detector.rb +39 -0
  53. data/lib/sentry/scope.rb +360 -0
  54. data/lib/sentry/session.rb +33 -0
  55. data/lib/sentry/session_flusher.rb +90 -0
  56. data/lib/sentry/span.rb +273 -0
  57. data/lib/sentry/test_helper.rb +84 -0
  58. data/lib/sentry/transaction.rb +359 -0
  59. data/lib/sentry/transaction_event.rb +80 -0
  60. data/lib/sentry/transport/configuration.rb +98 -0
  61. data/lib/sentry/transport/dummy_transport.rb +21 -0
  62. data/lib/sentry/transport/http_transport.rb +206 -0
  63. data/lib/sentry/transport/spotlight_transport.rb +50 -0
  64. data/lib/sentry/transport.rb +225 -0
  65. data/lib/sentry/utils/argument_checking_helper.rb +19 -0
  66. data/lib/sentry/utils/custom_inspection.rb +14 -0
  67. data/lib/sentry/utils/encoding_helper.rb +22 -0
  68. data/lib/sentry/utils/exception_cause_chain.rb +20 -0
  69. data/lib/sentry/utils/logging_helper.rb +26 -0
  70. data/lib/sentry/utils/real_ip.rb +84 -0
  71. data/lib/sentry/utils/request_id.rb +18 -0
  72. data/lib/sentry/version.rb +5 -0
  73. data/lib/sentry-ruby.rb +580 -0
  74. data/sentry-ruby-core.gemspec +23 -0
  75. data/sentry-ruby.gemspec +24 -0
  76. metadata +75 -16
@@ -0,0 +1,580 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "English"
4
+ require "forwardable"
5
+ require "time"
6
+
7
+ require "sentry/version"
8
+ require "sentry/exceptions"
9
+ require "sentry/core_ext/object/deep_dup"
10
+ require "sentry/utils/argument_checking_helper"
11
+ require "sentry/utils/encoding_helper"
12
+ require "sentry/utils/logging_helper"
13
+ require "sentry/configuration"
14
+ require "sentry/logger"
15
+ require "sentry/event"
16
+ require "sentry/error_event"
17
+ require "sentry/transaction_event"
18
+ require "sentry/check_in_event"
19
+ require "sentry/span"
20
+ require "sentry/transaction"
21
+ require "sentry/hub"
22
+ require "sentry/background_worker"
23
+ require "sentry/session_flusher"
24
+ require "sentry/backpressure_monitor"
25
+ require "sentry/cron/monitor_check_ins"
26
+
27
+ [
28
+ "sentry/rake",
29
+ "sentry/rack",
30
+ ].each do |lib|
31
+ begin
32
+ require lib
33
+ rescue LoadError
34
+ end
35
+ end
36
+
37
+ module Sentry
38
+ META = { "name" => "sentry.ruby", "version" => Sentry::VERSION }.freeze
39
+
40
+ CAPTURED_SIGNATURE = :@__sentry_captured
41
+
42
+ LOGGER_PROGNAME = "sentry".freeze
43
+
44
+ SENTRY_TRACE_HEADER_NAME = "sentry-trace".freeze
45
+
46
+ BAGGAGE_HEADER_NAME = "baggage".freeze
47
+
48
+ THREAD_LOCAL = :sentry_hub
49
+
50
+ class << self
51
+ # @!visibility private
52
+ def exception_locals_tp
53
+ @exception_locals_tp ||= TracePoint.new(:raise) do |tp|
54
+ exception = tp.raised_exception
55
+
56
+ # don't collect locals again if the exception is re-raised
57
+ next if exception.instance_variable_get(:@sentry_locals)
58
+ next unless tp.binding
59
+
60
+ locals = tp.binding.local_variables.each_with_object({}) do |local, result|
61
+ result[local] = tp.binding.local_variable_get(local)
62
+ end
63
+
64
+ exception.instance_variable_set(:@sentry_locals, locals)
65
+ end
66
+ end
67
+
68
+ # @!attribute [rw] background_worker
69
+ # @return [BackgroundWorker]
70
+ attr_accessor :background_worker
71
+
72
+ # @!attribute [r] session_flusher
73
+ # @return [SessionFlusher, nil]
74
+ attr_reader :session_flusher
75
+
76
+ # @!attribute [r] backpressure_monitor
77
+ # @return [BackpressureMonitor, nil]
78
+ attr_reader :backpressure_monitor
79
+
80
+ ##### Patch Registration #####
81
+
82
+ # @!visibility private
83
+ def register_patch(key, patch = nil, target = nil, &block)
84
+ if patch && block
85
+ raise ArgumentError.new("Please provide either a patch and its target OR a block, but not both")
86
+ end
87
+
88
+ if block
89
+ registered_patches[key] = block
90
+ else
91
+ registered_patches[key] = proc do
92
+ target.send(:prepend, patch) unless target.ancestors.include?(patch)
93
+ end
94
+ end
95
+ end
96
+
97
+ # @!visibility private
98
+ def apply_patches(config)
99
+ registered_patches.each do |key, patch|
100
+ patch.call(config) if config.enabled_patches.include?(key)
101
+ end
102
+ end
103
+
104
+ # @!visibility private
105
+ def registered_patches
106
+ @registered_patches ||= {}
107
+ end
108
+
109
+ ##### Integrations #####
110
+
111
+ # Returns a hash that contains all the integrations that have been registered to the main SDK.
112
+ #
113
+ # @return [Hash{String=>Hash}]
114
+ def integrations
115
+ @integrations ||= {}
116
+ end
117
+
118
+ # Registers the SDK integration with its name and version.
119
+ #
120
+ # @param name [String] name of the integration
121
+ # @param version [String] version of the integration
122
+ def register_integration(name, version)
123
+ if initialized?
124
+ logger.warn(LOGGER_PROGNAME) do
125
+ <<~MSG
126
+ Integration '#{name}' is loaded after the SDK is initialized, which can cause unexpected behavior. Please make sure all integrations are loaded before SDK initialization.
127
+ MSG
128
+ end
129
+ end
130
+
131
+ meta = { name: "sentry.ruby.#{name}", version: version }.freeze
132
+ integrations[name.to_s] = meta
133
+ end
134
+
135
+ ##### Method Delegation #####
136
+
137
+ extend Forwardable
138
+
139
+ # @!macro [new] configuration
140
+ # The Configuration object that's used for configuring the client and its transport.
141
+ # @return [Configuration]
142
+ # @!macro [new] send_event
143
+ # Sends the event to Sentry.
144
+ # @param event [Event] the event to be sent.
145
+ # @param hint [Hash] the hint data that'll be passed to `before_send` callback.
146
+ # @return [Event]
147
+
148
+ # @!method configuration
149
+ # @!macro configuration
150
+ def configuration
151
+ return unless initialized?
152
+ get_current_client.configuration
153
+ end
154
+
155
+ # @!method send_event
156
+ # @!macro send_event
157
+ def send_event(*args)
158
+ return unless initialized?
159
+ get_current_client.send_event(*args)
160
+ end
161
+
162
+ # @!macro [new] set_extras
163
+ # Updates the scope's extras attribute by merging with the old value.
164
+ # @param extras [Hash]
165
+ # @return [Hash]
166
+ # @!macro [new] set_user
167
+ # Sets the scope's user attribute.
168
+ # @param user [Hash]
169
+ # @return [Hash]
170
+ # @!macro [new] set_context
171
+ # Adds a new key-value pair to current contexts.
172
+ # @param key [String, Symbol]
173
+ # @param value [Object]
174
+ # @return [Hash]
175
+ # @!macro [new] set_tags
176
+ # Updates the scope's tags attribute by merging with the old value.
177
+ # @param tags [Hash]
178
+ # @return [Hash]
179
+
180
+ # @!method set_tags
181
+ # @!macro set_tags
182
+ def set_tags(*args)
183
+ return unless initialized?
184
+ get_current_scope.set_tags(*args)
185
+ end
186
+
187
+ # @!method set_extras
188
+ # @!macro set_extras
189
+ def set_extras(*args)
190
+ return unless initialized?
191
+ get_current_scope.set_extras(*args)
192
+ end
193
+
194
+ # @!method set_user
195
+ # @!macro set_user
196
+ def set_user(*args)
197
+ return unless initialized?
198
+ get_current_scope.set_user(*args)
199
+ end
200
+
201
+ # @!method set_context
202
+ # @!macro set_context
203
+ def set_context(*args)
204
+ return unless initialized?
205
+ get_current_scope.set_context(*args)
206
+ end
207
+
208
+ ##### Main APIs #####
209
+
210
+ # Initializes the SDK with given configuration.
211
+ #
212
+ # @yieldparam config [Configuration]
213
+ # @return [void]
214
+ def init(&block)
215
+ config = Configuration.new
216
+ yield(config) if block_given?
217
+ config.detect_release
218
+ apply_patches(config)
219
+ client = Client.new(config)
220
+ scope = Scope.new(max_breadcrumbs: config.max_breadcrumbs)
221
+ hub = Hub.new(client, scope)
222
+ Thread.current.thread_variable_set(THREAD_LOCAL, hub)
223
+ @main_hub = hub
224
+ @background_worker = Sentry::BackgroundWorker.new(config)
225
+ @session_flusher = config.auto_session_tracking ? Sentry::SessionFlusher.new(config, client) : nil
226
+ @backpressure_monitor = config.enable_backpressure_handling ? Sentry::BackpressureMonitor.new(config, client) : nil
227
+ exception_locals_tp.enable if config.include_local_variables
228
+ at_exit { close }
229
+ end
230
+
231
+ # Flushes pending events and cleans up SDK state.
232
+ # SDK will stop sending events and all top-level APIs will be no-ops after this.
233
+ #
234
+ # @return [void]
235
+ def close
236
+ if @session_flusher
237
+ @session_flusher.flush
238
+ @session_flusher.kill
239
+ @session_flusher = nil
240
+ end
241
+
242
+ if @backpressure_monitor
243
+ @backpressure_monitor.kill
244
+ @backpressure_monitor = nil
245
+ end
246
+
247
+ if client = get_current_client
248
+ client.transport.flush
249
+
250
+ if client.configuration.include_local_variables
251
+ exception_locals_tp.disable
252
+ end
253
+ end
254
+
255
+ @background_worker.shutdown
256
+
257
+ @main_hub = nil
258
+ Thread.current.thread_variable_set(THREAD_LOCAL, nil)
259
+ end
260
+
261
+ # Returns true if the SDK is initialized.
262
+ #
263
+ # @return [Boolean]
264
+ def initialized?
265
+ !!get_main_hub
266
+ end
267
+
268
+ # Returns an uri for security policy reporting that's generated from the given DSN
269
+ # (To learn more about security policy reporting: https://docs.sentry.io/product/security-policy-reporting/)
270
+ #
271
+ # It returns nil if
272
+ # - The SDK is not initialized yet.
273
+ # - The DSN is not provided or is invalid.
274
+ #
275
+ # @return [String, nil]
276
+ def csp_report_uri
277
+ return unless initialized?
278
+ configuration.csp_report_uri
279
+ end
280
+
281
+ # Returns the main thread's active hub.
282
+ #
283
+ # @return [Hub]
284
+ def get_main_hub
285
+ @main_hub
286
+ end
287
+
288
+ # Takes an instance of Sentry::Breadcrumb and stores it to the current active scope.
289
+ #
290
+ # @return [Breadcrumb, nil]
291
+ def add_breadcrumb(breadcrumb, **options)
292
+ return unless initialized?
293
+ get_current_hub.add_breadcrumb(breadcrumb, **options)
294
+ end
295
+
296
+ # Returns the current active hub.
297
+ # If the current thread doesn't have an active hub, it will clone the main thread's active hub,
298
+ # stores it in the current thread, and then returns it.
299
+ #
300
+ # @return [Hub]
301
+ def get_current_hub
302
+ # we need to assign a hub to the current thread if it doesn't have one yet
303
+ #
304
+ # ideally, we should do this proactively whenever a new thread is created
305
+ # but it's impossible for the SDK to keep track every new thread
306
+ # so we need to use this rather passive way to make sure the app doesn't crash
307
+ Thread.current.thread_variable_get(THREAD_LOCAL) || clone_hub_to_current_thread
308
+ end
309
+
310
+ # Returns the current active client.
311
+ # @return [Client, nil]
312
+ def get_current_client
313
+ return unless initialized?
314
+ get_current_hub.current_client
315
+ end
316
+
317
+ # Returns the current active scope.
318
+ #
319
+ # @return [Scope, nil]
320
+ def get_current_scope
321
+ return unless initialized?
322
+ get_current_hub.current_scope
323
+ end
324
+
325
+ # Clones the main thread's active hub and stores it to the current thread.
326
+ #
327
+ # @return [void]
328
+ def clone_hub_to_current_thread
329
+ return unless initialized?
330
+ Thread.current.thread_variable_set(THREAD_LOCAL, get_main_hub.clone)
331
+ end
332
+
333
+ # Takes a block and yields the current active scope.
334
+ #
335
+ # @example
336
+ # Sentry.configure_scope do |scope|
337
+ # scope.set_tags(foo: "bar")
338
+ # end
339
+ #
340
+ # Sentry.capture_message("test message") # this event will have tags { foo: "bar" }
341
+ #
342
+ # @yieldparam scope [Scope]
343
+ # @return [void]
344
+ def configure_scope(&block)
345
+ return unless initialized?
346
+ get_current_hub.configure_scope(&block)
347
+ end
348
+
349
+ # Takes a block and yields a temporary scope.
350
+ # The temporary scope will inherit all the attributes from the current active scope and replace it to be the active
351
+ # scope inside the block.
352
+ #
353
+ # @example
354
+ # Sentry.configure_scope do |scope|
355
+ # scope.set_tags(foo: "bar")
356
+ # end
357
+ #
358
+ # Sentry.capture_message("test message") # this event will have tags { foo: "bar" }
359
+ #
360
+ # Sentry.with_scope do |temp_scope|
361
+ # temp_scope.set_tags(foo: "baz")
362
+ # Sentry.capture_message("test message 2") # this event will have tags { foo: "baz" }
363
+ # end
364
+ #
365
+ # Sentry.capture_message("test message 3") # this event will have tags { foo: "bar" }
366
+ #
367
+ # @yieldparam scope [Scope]
368
+ # @return [void]
369
+ def with_scope(&block)
370
+ return yield unless initialized?
371
+ get_current_hub.with_scope(&block)
372
+ end
373
+
374
+ # Wrap a given block with session tracking.
375
+ # Aggregate sessions in minutely buckets will be recorded
376
+ # around this block and flushed every minute.
377
+ #
378
+ # @example
379
+ # Sentry.with_session_tracking do
380
+ # a = 1 + 1 # new session recorded with :exited status
381
+ # end
382
+ #
383
+ # Sentry.with_session_tracking do
384
+ # 1 / 0
385
+ # rescue => e
386
+ # Sentry.capture_exception(e) # new session recorded with :errored status
387
+ # end
388
+ # @return [void]
389
+ def with_session_tracking(&block)
390
+ return yield unless initialized?
391
+ get_current_hub.with_session_tracking(&block)
392
+ end
393
+
394
+ # Takes an exception and reports it to Sentry via the currently active hub.
395
+ #
396
+ # @yieldparam scope [Scope]
397
+ # @return [Event, nil]
398
+ def capture_exception(exception, **options, &block)
399
+ return unless initialized?
400
+ get_current_hub.capture_exception(exception, **options, &block)
401
+ end
402
+
403
+ # Takes a block and evaluates it. If the block raised an exception, it reports the exception to Sentry and re-raises it.
404
+ # If the block ran without exception, it returns the evaluation result.
405
+ #
406
+ # @example
407
+ # Sentry.with_exception_captured do
408
+ # 1/1 #=> 1 will be returned
409
+ # end
410
+ #
411
+ # Sentry.with_exception_captured do
412
+ # 1/0 #=> ZeroDivisionError will be reported and re-raised
413
+ # end
414
+ #
415
+ def with_exception_captured(**options, &block)
416
+ yield
417
+ rescue Exception => e
418
+ capture_exception(e, **options)
419
+ raise
420
+ end
421
+
422
+ # Takes a message string and reports it to Sentry via the currently active hub.
423
+ #
424
+ # @yieldparam scope [Scope]
425
+ # @return [Event, nil]
426
+ def capture_message(message, **options, &block)
427
+ return unless initialized?
428
+ get_current_hub.capture_message(message, **options, &block)
429
+ end
430
+
431
+ # Takes an instance of Sentry::Event and dispatches it to the currently active hub.
432
+ #
433
+ # @return [Event, nil]
434
+ def capture_event(event)
435
+ return unless initialized?
436
+ get_current_hub.capture_event(event)
437
+ end
438
+
439
+ # Captures a check-in and sends it to Sentry via the currently active hub.
440
+ #
441
+ # @param slug [String] identifier of this monitor
442
+ # @param status [Symbol] status of this check-in, one of {CheckInEvent::VALID_STATUSES}
443
+ #
444
+ # @param [Hash] options extra check-in options
445
+ # @option options [String] check_in_id for updating the status of an existing monitor
446
+ # @option options [Integer] duration seconds elapsed since this monitor started
447
+ # @option options [Cron::MonitorConfig] monitor_config configuration for this monitor
448
+ #
449
+ # @return [String, nil] The {CheckInEvent#check_in_id} to use for later updates on the same slug
450
+ def capture_check_in(slug, status, **options)
451
+ return unless initialized?
452
+ get_current_hub.capture_check_in(slug, status, **options)
453
+ end
454
+
455
+ # Takes or initializes a new Sentry::Transaction and makes a sampling decision for it.
456
+ #
457
+ # @return [Transaction, nil]
458
+ def start_transaction(**options)
459
+ return unless initialized?
460
+ get_current_hub.start_transaction(**options)
461
+ end
462
+
463
+ # Records the block's execution as a child of the current span.
464
+ # If the current scope doesn't have a span, the block would still be executed but the yield param will be nil.
465
+ # @param attributes [Hash] attributes for the child span.
466
+ # @yieldparam child_span [Span, nil]
467
+ # @return yield result
468
+ #
469
+ # @example
470
+ # Sentry.with_child_span(op: "my operation") do |child_span|
471
+ # child_span.set_data(operation_data)
472
+ # child_span.set_description(operation_detail)
473
+ # # result will be returned
474
+ # end
475
+ #
476
+ def with_child_span(**attributes, &block)
477
+ return yield(nil) unless Sentry.initialized?
478
+ get_current_hub.with_child_span(**attributes, &block)
479
+ end
480
+
481
+ # Returns the id of the lastly reported Sentry::Event.
482
+ #
483
+ # @return [String, nil]
484
+ def last_event_id
485
+ return unless initialized?
486
+ get_current_hub.last_event_id
487
+ end
488
+
489
+ # Checks if the exception object has been captured by the SDK.
490
+ #
491
+ # @return [Boolean]
492
+ def exception_captured?(exc)
493
+ return false unless initialized?
494
+ !!exc.instance_variable_get(CAPTURED_SIGNATURE)
495
+ end
496
+
497
+ # Add a global event processor [Proc].
498
+ # These run before scope event processors.
499
+ #
500
+ # @yieldparam event [Event]
501
+ # @yieldparam hint [Hash, nil]
502
+ # @return [void]
503
+ #
504
+ # @example
505
+ # Sentry.add_global_event_processor do |event, hint|
506
+ # event.tags = { foo: 42 }
507
+ # event
508
+ # end
509
+ #
510
+ def add_global_event_processor(&block)
511
+ Scope.add_global_event_processor(&block)
512
+ end
513
+
514
+ # Returns the traceparent (sentry-trace) header for distributed tracing.
515
+ # Can be either from the currently active span or the propagation context.
516
+ #
517
+ # @return [String, nil]
518
+ def get_traceparent
519
+ return nil unless initialized?
520
+ get_current_hub.get_traceparent
521
+ end
522
+
523
+ # Returns the baggage header for distributed tracing.
524
+ # Can be either from the currently active span or the propagation context.
525
+ #
526
+ # @return [String, nil]
527
+ def get_baggage
528
+ return nil unless initialized?
529
+ get_current_hub.get_baggage
530
+ end
531
+
532
+ # Returns the a Hash containing sentry-trace and baggage.
533
+ # Can be either from the currently active span or the propagation context.
534
+ #
535
+ # @return [Hash, nil]
536
+ def get_trace_propagation_headers
537
+ return nil unless initialized?
538
+ get_current_hub.get_trace_propagation_headers
539
+ end
540
+
541
+ # Continue an incoming trace from a rack env like hash.
542
+ #
543
+ # @param env [Hash]
544
+ # @return [Transaction, nil]
545
+ def continue_trace(env, **options)
546
+ return nil unless initialized?
547
+ get_current_hub.continue_trace(env, **options)
548
+ end
549
+
550
+ ##### Helpers #####
551
+
552
+ # @!visibility private
553
+ def sys_command(command)
554
+ result = `#{command} 2>&1` rescue nil
555
+ return if result.nil? || result.empty? || ($CHILD_STATUS && $CHILD_STATUS.exitstatus != 0)
556
+
557
+ result.strip
558
+ end
559
+
560
+ # @!visibility private
561
+ def logger
562
+ configuration.logger
563
+ end
564
+
565
+ # @!visibility private
566
+ def sdk_meta
567
+ META
568
+ end
569
+
570
+ # @!visibility private
571
+ def utc_now
572
+ Time.now.utc
573
+ end
574
+ end
575
+ end
576
+
577
+ # patches
578
+ require "sentry/net/http"
579
+ require "sentry/redis"
580
+ require "sentry/puma"
@@ -0,0 +1,23 @@
1
+ require_relative "lib/sentry/version"
2
+
3
+ Gem::Specification.new do |spec|
4
+ spec.name = "sentry-ruby-core"
5
+ spec.version = Sentry::VERSION
6
+ spec.authors = ["Sentry Team"]
7
+ spec.description = spec.summary = "A gem that provides a client interface for the Sentry error logger"
8
+ spec.email = "accounts@sentry.io"
9
+ spec.license = 'MIT'
10
+ spec.homepage = "https://github.com/getsentry/sentry-ruby"
11
+
12
+ spec.platform = Gem::Platform::RUBY
13
+ spec.required_ruby_version = '>= 2.4'
14
+ spec.extra_rdoc_files = ["README.md", "LICENSE.txt"]
15
+ spec.files = `git ls-files | grep -Ev '^(spec|benchmarks|examples)'`.split("\n")
16
+
17
+ spec.metadata["homepage_uri"] = spec.homepage
18
+ spec.metadata["source_code_uri"] = spec.homepage
19
+ spec.metadata["changelog_uri"] = "#{spec.homepage}/blob/master/CHANGELOG.md"
20
+
21
+ spec.add_dependency "sentry-ruby", Sentry::VERSION
22
+ spec.add_dependency "concurrent-ruby"
23
+ end
@@ -0,0 +1,24 @@
1
+ require_relative "lib/sentry/version"
2
+
3
+ Gem::Specification.new do |spec|
4
+ spec.name = "sentry-ruby"
5
+ spec.version = Sentry::VERSION
6
+ spec.authors = ["Sentry Team"]
7
+ spec.description = spec.summary = "A gem that provides a client interface for the Sentry error logger"
8
+ spec.email = "accounts@sentry.io"
9
+ spec.license = 'MIT'
10
+ spec.homepage = "https://github.com/getsentry/sentry-ruby"
11
+
12
+ spec.platform = Gem::Platform::RUBY
13
+ spec.required_ruby_version = '>= 2.4'
14
+ spec.extra_rdoc_files = ["README.md", "LICENSE.txt"]
15
+ spec.files = `git ls-files | grep -Ev '^(spec|benchmarks|examples)'`.split("\n")
16
+
17
+ spec.metadata["homepage_uri"] = spec.homepage
18
+ spec.metadata["source_code_uri"] = spec.homepage
19
+ spec.metadata["changelog_uri"] = "#{spec.homepage}/blob/master/CHANGELOG.md"
20
+
21
+ spec.require_paths = ["lib"]
22
+
23
+ spec.add_dependency "concurrent-ruby", '~> 1.0', '>= 1.0.2'
24
+ end