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,248 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "sentry/transport"
4
+
5
+ module Sentry
6
+ class Client
7
+ include LoggingHelper
8
+
9
+ # The Transport object that'll send events for the client.
10
+ # @return [Transport]
11
+ attr_reader :transport
12
+
13
+ # The Transport object that'll send events for the client.
14
+ # @return [SpotlightTransport, nil]
15
+ attr_reader :spotlight_transport
16
+
17
+ # @!macro configuration
18
+ attr_reader :configuration
19
+
20
+ # @deprecated Use Sentry.logger to retrieve the current logger instead.
21
+ attr_reader :logger
22
+
23
+ # @param configuration [Configuration]
24
+ def initialize(configuration)
25
+ @configuration = configuration
26
+ @logger = configuration.logger
27
+
28
+ if transport_class = configuration.transport.transport_class
29
+ @transport = transport_class.new(configuration)
30
+ else
31
+ @transport =
32
+ case configuration.dsn&.scheme
33
+ when 'http', 'https'
34
+ HTTPTransport.new(configuration)
35
+ else
36
+ DummyTransport.new(configuration)
37
+ end
38
+ end
39
+
40
+ @spotlight_transport = SpotlightTransport.new(configuration) if configuration.spotlight
41
+ end
42
+
43
+ # Applies the given scope's data to the event and sends it to Sentry.
44
+ # @param event [Event] the event to be sent.
45
+ # @param scope [Scope] the scope with contextual data that'll be applied to the event before it's sent.
46
+ # @param hint [Hash] the hint data that'll be passed to `before_send` callback and the scope's event processors.
47
+ # @return [Event, nil]
48
+ def capture_event(event, scope, hint = {})
49
+ return unless configuration.sending_allowed?
50
+
51
+ if event.is_a?(ErrorEvent) && !configuration.sample_allowed?
52
+ transport.record_lost_event(:sample_rate, 'event')
53
+ return
54
+ end
55
+
56
+ event_type = event.is_a?(Event) ? event.type : event["type"]
57
+ event = scope.apply_to_event(event, hint)
58
+
59
+ if event.nil?
60
+ log_debug("Discarded event because one of the event processors returned nil")
61
+ transport.record_lost_event(:event_processor, event_type)
62
+ return
63
+ end
64
+
65
+ if async_block = configuration.async
66
+ dispatch_async_event(async_block, event, hint)
67
+ elsif configuration.background_worker_threads != 0 && hint.fetch(:background, true)
68
+ queued = dispatch_background_event(event, hint)
69
+ transport.record_lost_event(:queue_overflow, event_type) unless queued
70
+ else
71
+ send_event(event, hint)
72
+ end
73
+
74
+ event
75
+ rescue => e
76
+ log_error("Event capturing failed", e, debug: configuration.debug)
77
+ nil
78
+ end
79
+
80
+ # Initializes an Event object with the given exception. Returns `nil` if the exception's class is excluded from reporting.
81
+ # @param exception [Exception] the exception to be reported.
82
+ # @param hint [Hash] the hint data that'll be passed to `before_send` callback and the scope's event processors.
83
+ # @return [Event, nil]
84
+ def event_from_exception(exception, hint = {})
85
+ return unless @configuration.sending_allowed?
86
+
87
+ ignore_exclusions = hint.delete(:ignore_exclusions) { false }
88
+ return if !ignore_exclusions && !@configuration.exception_class_allowed?(exception)
89
+
90
+ integration_meta = Sentry.integrations[hint[:integration]]
91
+
92
+ ErrorEvent.new(configuration: configuration, integration_meta: integration_meta).tap do |event|
93
+ event.add_exception_interface(exception)
94
+ event.add_threads_interface(crashed: true)
95
+ event.level = :error
96
+ end
97
+ end
98
+
99
+ # Initializes an Event object with the given message.
100
+ # @param message [String] the message to be reported.
101
+ # @param hint [Hash] the hint data that'll be passed to `before_send` callback and the scope's event processors.
102
+ # @return [Event]
103
+ def event_from_message(message, hint = {}, backtrace: nil)
104
+ return unless @configuration.sending_allowed?
105
+
106
+ integration_meta = Sentry.integrations[hint[:integration]]
107
+ event = ErrorEvent.new(configuration: configuration, integration_meta: integration_meta, message: message)
108
+ event.add_threads_interface(backtrace: backtrace || caller)
109
+ event.level = :error
110
+ event
111
+ end
112
+
113
+ # Initializes a CheckInEvent object with the given options.
114
+ #
115
+ # @param slug [String] identifier of this monitor
116
+ # @param status [Symbol] status of this check-in, one of {CheckInEvent::VALID_STATUSES}
117
+ # @param hint [Hash] the hint data that'll be passed to `before_send` callback and the scope's event processors.
118
+ # @param duration [Integer, nil] seconds elapsed since this monitor started
119
+ # @param monitor_config [Cron::MonitorConfig, nil] configuration for this monitor
120
+ # @param check_in_id [String, nil] for updating the status of an existing monitor
121
+ #
122
+ # @return [Event]
123
+ def event_from_check_in(
124
+ slug,
125
+ status,
126
+ hint = {},
127
+ duration: nil,
128
+ monitor_config: nil,
129
+ check_in_id: nil
130
+ )
131
+ return unless configuration.sending_allowed?
132
+
133
+ CheckInEvent.new(
134
+ configuration: configuration,
135
+ integration_meta: Sentry.integrations[hint[:integration]],
136
+ slug: slug,
137
+ status: status,
138
+ duration: duration,
139
+ monitor_config: monitor_config,
140
+ check_in_id: check_in_id
141
+ )
142
+ end
143
+
144
+ # Initializes an Event object with the given Transaction object.
145
+ # @param transaction [Transaction] the transaction to be recorded.
146
+ # @return [TransactionEvent]
147
+ def event_from_transaction(transaction)
148
+ TransactionEvent.new(configuration: configuration, transaction: transaction)
149
+ end
150
+
151
+ # @!macro send_event
152
+ def send_event(event, hint = nil)
153
+ event_type = event.is_a?(Event) ? event.type : event["type"]
154
+
155
+ if event_type != TransactionEvent::TYPE && configuration.before_send
156
+ event = configuration.before_send.call(event, hint)
157
+
158
+ if event.nil?
159
+ log_debug("Discarded event because before_send returned nil")
160
+ transport.record_lost_event(:before_send, 'event')
161
+ return
162
+ end
163
+ end
164
+
165
+ if event_type == TransactionEvent::TYPE && configuration.before_send_transaction
166
+ event = configuration.before_send_transaction.call(event, hint)
167
+
168
+ if event.nil?
169
+ log_debug("Discarded event because before_send_transaction returned nil")
170
+ transport.record_lost_event(:before_send, 'transaction')
171
+ return
172
+ end
173
+ end
174
+
175
+ transport.send_event(event)
176
+ spotlight_transport&.send_event(event)
177
+
178
+ event
179
+ rescue => e
180
+ log_error("Event sending failed", e, debug: configuration.debug)
181
+ transport.record_lost_event(:network_error, event_type)
182
+ raise
183
+ end
184
+
185
+ # @deprecated use Sentry.get_traceparent instead.
186
+ #
187
+ # Generates a Sentry trace for distribted tracing from the given Span.
188
+ # Returns `nil` if `config.propagate_traces` is `false`.
189
+ # @param span [Span] the span to generate trace from.
190
+ # @return [String, nil]
191
+ def generate_sentry_trace(span)
192
+ return unless configuration.propagate_traces
193
+
194
+ trace = span.to_sentry_trace
195
+ log_debug("[Tracing] Adding #{SENTRY_TRACE_HEADER_NAME} header to outgoing request: #{trace}")
196
+ trace
197
+ end
198
+
199
+ # @deprecated Use Sentry.get_baggage instead.
200
+ #
201
+ # Generates a W3C Baggage header for distributed tracing from the given Span.
202
+ # Returns `nil` if `config.propagate_traces` is `false`.
203
+ # @param span [Span] the span to generate trace from.
204
+ # @return [String, nil]
205
+ def generate_baggage(span)
206
+ return unless configuration.propagate_traces
207
+
208
+ baggage = span.to_baggage
209
+
210
+ if baggage && !baggage.empty?
211
+ log_debug("[Tracing] Adding #{BAGGAGE_HEADER_NAME} header to outgoing request: #{baggage}")
212
+ end
213
+
214
+ baggage
215
+ end
216
+
217
+ private
218
+
219
+ def dispatch_background_event(event, hint)
220
+ Sentry.background_worker.perform do
221
+ send_event(event, hint)
222
+ end
223
+ end
224
+
225
+ def dispatch_async_event(async_block, event, hint)
226
+ # We have to convert to a JSON-like hash, because background job
227
+ # processors (esp ActiveJob) may not like weird types in the event hash
228
+
229
+ event_hash =
230
+ begin
231
+ event.to_json_compatible
232
+ rescue => e
233
+ log_error("Converting #{event.type} (#{event.event_id}) to JSON compatible hash failed", e, debug: configuration.debug)
234
+ return
235
+ end
236
+
237
+ if async_block.arity == 2
238
+ hint = JSON.parse(JSON.generate(hint))
239
+ async_block.call(event_hash, hint)
240
+ else
241
+ async_block.call(event_hash)
242
+ end
243
+ rescue => e
244
+ log_error("Async #{event_hash["type"]} sending failed", e, debug: configuration.debug)
245
+ send_event(event, hint)
246
+ end
247
+ end
248
+ end