sentry-ruby 5.4.2 → 5.16.1

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.
Files changed (47) hide show
  1. checksums.yaml +4 -4
  2. data/.rspec +0 -1
  3. data/Gemfile +13 -14
  4. data/README.md +11 -8
  5. data/Rakefile +8 -1
  6. data/lib/sentry/background_worker.rb +8 -1
  7. data/lib/sentry/backpressure_monitor.rb +75 -0
  8. data/lib/sentry/backtrace.rb +1 -1
  9. data/lib/sentry/baggage.rb +70 -0
  10. data/lib/sentry/breadcrumb.rb +8 -2
  11. data/lib/sentry/check_in_event.rb +60 -0
  12. data/lib/sentry/client.rb +77 -19
  13. data/lib/sentry/configuration.rb +177 -29
  14. data/lib/sentry/cron/configuration.rb +23 -0
  15. data/lib/sentry/cron/monitor_check_ins.rb +75 -0
  16. data/lib/sentry/cron/monitor_config.rb +53 -0
  17. data/lib/sentry/cron/monitor_schedule.rb +42 -0
  18. data/lib/sentry/envelope.rb +2 -5
  19. data/lib/sentry/event.rb +7 -29
  20. data/lib/sentry/hub.rb +100 -4
  21. data/lib/sentry/integrable.rb +6 -0
  22. data/lib/sentry/interfaces/request.rb +6 -16
  23. data/lib/sentry/interfaces/single_exception.rb +13 -3
  24. data/lib/sentry/net/http.rb +37 -46
  25. data/lib/sentry/profiler.rb +233 -0
  26. data/lib/sentry/propagation_context.rb +134 -0
  27. data/lib/sentry/puma.rb +32 -0
  28. data/lib/sentry/rack/capture_exceptions.rb +4 -5
  29. data/lib/sentry/rake.rb +1 -14
  30. data/lib/sentry/redis.rb +41 -23
  31. data/lib/sentry/release_detector.rb +1 -1
  32. data/lib/sentry/scope.rb +81 -16
  33. data/lib/sentry/session.rb +5 -7
  34. data/lib/sentry/span.rb +57 -10
  35. data/lib/sentry/test_helper.rb +19 -11
  36. data/lib/sentry/transaction.rb +183 -30
  37. data/lib/sentry/transaction_event.rb +51 -0
  38. data/lib/sentry/transport/configuration.rb +74 -1
  39. data/lib/sentry/transport/http_transport.rb +68 -37
  40. data/lib/sentry/transport/spotlight_transport.rb +50 -0
  41. data/lib/sentry/transport.rb +39 -24
  42. data/lib/sentry/utils/argument_checking_helper.rb +9 -3
  43. data/lib/sentry/utils/encoding_helper.rb +22 -0
  44. data/lib/sentry/version.rb +1 -1
  45. data/lib/sentry-ruby.rb +116 -41
  46. metadata +14 -3
  47. data/CODE_OF_CONDUCT.md +0 -74
data/lib/sentry/span.rb CHANGED
@@ -4,6 +4,43 @@ require "securerandom"
4
4
 
5
5
  module Sentry
6
6
  class Span
7
+
8
+ # We will try to be consistent with OpenTelemetry on this front going forward.
9
+ # https://develop.sentry.dev/sdk/performance/span-data-conventions/
10
+ module DataConventions
11
+ URL = "url"
12
+ HTTP_STATUS_CODE = "http.response.status_code"
13
+ HTTP_QUERY = "http.query"
14
+ HTTP_METHOD = "http.request.method"
15
+
16
+ # An identifier for the database management system (DBMS) product being used.
17
+ # Example: postgresql
18
+ DB_SYSTEM = "db.system"
19
+
20
+ # The name of the database being accessed.
21
+ # For commands that switch the database, this should be set to the target database
22
+ # (even if the command fails).
23
+ # Example: myDatabase
24
+ DB_NAME = "db.name"
25
+
26
+ # Name of the database host.
27
+ # Example: example.com
28
+ SERVER_ADDRESS = "server.address"
29
+
30
+ # Logical server port number
31
+ # Example: 80; 8080; 443
32
+ SERVER_PORT = "server.port"
33
+
34
+ # Physical server IP address or Unix socket address.
35
+ # Example: 10.5.3.2
36
+ SERVER_SOCKET_ADDRESS = "server.socket.address"
37
+
38
+ # Physical server port.
39
+ # Recommended: If different than server.port.
40
+ # Example: 16456
41
+ SERVER_SOCKET_PORT = "server.socket.port"
42
+ end
43
+
7
44
  STATUS_MAP = {
8
45
  400 => "invalid_argument",
9
46
  401 => "unauthenticated",
@@ -60,25 +97,28 @@ module Sentry
60
97
  # The Transaction object the Span belongs to.
61
98
  # Every span needs to be attached to a Transaction and their child spans will also inherit the same transaction.
62
99
  # @return [Transaction]
63
- attr_accessor :transaction
100
+ attr_reader :transaction
64
101
 
65
102
  def initialize(
103
+ transaction:,
66
104
  description: nil,
67
105
  op: nil,
68
106
  status: nil,
69
107
  trace_id: nil,
108
+ span_id: nil,
70
109
  parent_span_id: nil,
71
110
  sampled: nil,
72
111
  start_timestamp: nil,
73
112
  timestamp: nil
74
113
  )
75
114
  @trace_id = trace_id || SecureRandom.uuid.delete("-")
76
- @span_id = SecureRandom.hex(8)
115
+ @span_id = span_id || SecureRandom.uuid.delete("-").slice(0, 16)
77
116
  @parent_span_id = parent_span_id
78
117
  @sampled = sampled
79
118
  @start_timestamp = start_timestamp || Sentry.utc_now.to_f
80
119
  @timestamp = timestamp
81
120
  @description = description
121
+ @transaction = transaction
82
122
  @op = op
83
123
  @status = status
84
124
  @data = {}
@@ -87,11 +127,8 @@ module Sentry
87
127
 
88
128
  # Finishes the span by adding a timestamp.
89
129
  # @return [self]
90
- def finish
91
- # already finished
92
- return if @timestamp
93
-
94
- @timestamp = Sentry.utc_now.to_f
130
+ def finish(end_timestamp: nil)
131
+ @timestamp = end_timestamp || @timestamp || Sentry.utc_now.to_f
95
132
  self
96
133
  end
97
134
 
@@ -104,6 +141,13 @@ module Sentry
104
141
  "#{@trace_id}-#{@span_id}-#{sampled_flag}"
105
142
  end
106
143
 
144
+ # Generates a W3C Baggage header string for distributed tracing
145
+ # from the incoming baggage stored on the transaction.
146
+ # @return [String, nil]
147
+ def to_baggage
148
+ transaction.get_baggage&.serialize
149
+ end
150
+
107
151
  # @return [Hash]
108
152
  def to_hash
109
153
  {
@@ -136,9 +180,8 @@ module Sentry
136
180
  # Starts a child span with given attributes.
137
181
  # @param attributes [Hash] the attributes for the child span.
138
182
  def start_child(**attributes)
139
- attributes = attributes.dup.merge(trace_id: @trace_id, parent_span_id: @span_id, sampled: @sampled)
183
+ attributes = attributes.dup.merge(transaction: @transaction, trace_id: @trace_id, parent_span_id: @span_id, sampled: @sampled)
140
184
  new_span = Span.new(**attributes)
141
- new_span.transaction = transaction
142
185
  new_span.span_recorder = span_recorder
143
186
 
144
187
  if span_recorder
@@ -163,6 +206,10 @@ module Sentry
163
206
  yield(child_span)
164
207
 
165
208
  child_span.finish
209
+ rescue
210
+ child_span.set_http_status(500)
211
+ child_span.finish
212
+ raise
166
213
  end
167
214
 
168
215
  def deep_dup
@@ -198,7 +245,7 @@ module Sentry
198
245
  # @param status_code [String] example: "500".
199
246
  def set_http_status(status_code)
200
247
  status_code = status_code.to_i
201
- set_data("status_code", status_code)
248
+ set_data(DataConventions::HTTP_STATUS_CODE, status_code)
202
249
 
203
250
  status =
204
251
  if status_code >= 200 && status_code < 299
@@ -14,22 +14,27 @@ module Sentry
14
14
  # @return [void]
15
15
  def setup_sentry_test(&block)
16
16
  raise "please make sure the SDK is initialized for testing" unless Sentry.initialized?
17
- copied_config = Sentry.configuration.dup
17
+ dummy_config = Sentry.configuration.dup
18
18
  # configure dummy DSN, so the events will not be sent to the actual service
19
- copied_config.dsn = DUMMY_DSN
19
+ dummy_config.dsn = DUMMY_DSN
20
20
  # set transport to DummyTransport, so we can easily intercept the captured events
21
- copied_config.transport.transport_class = Sentry::DummyTransport
21
+ dummy_config.transport.transport_class = Sentry::DummyTransport
22
22
  # make sure SDK allows sending under the current environment
23
- copied_config.enabled_environments << copied_config.environment unless copied_config.enabled_environments.include?(copied_config.environment)
23
+ dummy_config.enabled_environments << dummy_config.environment unless dummy_config.enabled_environments.include?(dummy_config.environment)
24
24
  # disble async event sending
25
- copied_config.background_worker_threads = 0
25
+ dummy_config.background_worker_threads = 0
26
26
 
27
27
  # user can overwrite some of the configs, with a few exceptions like:
28
- # - capture_exception_frame_locals
28
+ # - include_local_variables
29
29
  # - auto_session_tracking
30
- block&.call(copied_config)
30
+ block&.call(dummy_config)
31
31
 
32
- test_client = Sentry::Client.new(copied_config)
32
+ # the base layer's client should already use the dummy config so nothing will be sent by accident
33
+ base_client = Sentry::Client.new(dummy_config)
34
+ Sentry.get_current_hub.bind_client(base_client)
35
+ # create a new layer so mutations made to the testing scope or configuration could be simply popped later
36
+ Sentry.get_current_hub.push_scope
37
+ test_client = Sentry::Client.new(dummy_config.dup)
33
38
  Sentry.get_current_hub.bind_client(test_client)
34
39
  end
35
40
 
@@ -39,8 +44,12 @@ module Sentry
39
44
  def teardown_sentry_test
40
45
  return unless Sentry.initialized?
41
46
 
42
- sentry_transport.events = []
43
- sentry_transport.envelopes = []
47
+ # pop testing layer created by `setup_sentry_test`
48
+ # but keep the base layer to avoid nil-pointer errors
49
+ # TODO: find a way to notify users if they somehow popped the test layer before calling this method
50
+ if Sentry.get_current_hub.instance_variable_get(:@stack).size > 1
51
+ Sentry.get_current_hub.pop_scope
52
+ end
44
53
  end
45
54
 
46
55
  # @return [Transport]
@@ -73,4 +82,3 @@ module Sentry
73
82
  end
74
83
  end
75
84
  end
76
-
@@ -1,27 +1,44 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require "sentry/baggage"
4
+ require "sentry/profiler"
5
+ require "sentry/propagation_context"
6
+
3
7
  module Sentry
4
8
  class Transaction < Span
5
- SENTRY_TRACE_REGEXP = Regexp.new(
6
- "^[ \t]*" + # whitespace
7
- "([0-9a-f]{32})?" + # trace_id
8
- "-?([0-9a-f]{16})?" + # span_id
9
- "-?([01])?" + # sampled
10
- "[ \t]*$" # whitespace
11
- )
9
+ # @deprecated Use Sentry::PropagationContext::SENTRY_TRACE_REGEXP instead.
10
+ SENTRY_TRACE_REGEXP = PropagationContext::SENTRY_TRACE_REGEXP
11
+
12
12
  UNLABELD_NAME = "<unlabeled transaction>".freeze
13
13
  MESSAGE_PREFIX = "[Tracing]"
14
14
 
15
+ # https://develop.sentry.dev/sdk/event-payloads/transaction/#transaction-annotations
16
+ SOURCES = %i(custom url route view component task)
17
+
15
18
  include LoggingHelper
16
19
 
17
20
  # The name of the transaction.
18
21
  # @return [String]
19
22
  attr_reader :name
20
23
 
24
+ # The source of the transaction name.
25
+ # @return [Symbol]
26
+ attr_reader :source
27
+
21
28
  # The sampling decision of the parent transaction, which will be considered when making the current transaction's sampling decision.
22
29
  # @return [String]
23
30
  attr_reader :parent_sampled
24
31
 
32
+ # The parsed incoming W3C baggage header.
33
+ # This is only for accessing the current baggage variable.
34
+ # Please use the #get_baggage method for interfacing outside this class.
35
+ # @return [Baggage, nil]
36
+ attr_reader :baggage
37
+
38
+ # The measurements added to the transaction.
39
+ # @return [Hash]
40
+ attr_reader :measurements
41
+
25
42
  # @deprecated Use Sentry.get_current_hub instead.
26
43
  attr_reader :hub
27
44
 
@@ -31,52 +48,106 @@ module Sentry
31
48
  # @deprecated Use Sentry.logger instead.
32
49
  attr_reader :logger
33
50
 
34
- def initialize(name: nil, parent_sampled: nil, hub:, **options)
35
- super(**options)
51
+ # The effective sample rate at which this transaction was sampled.
52
+ # @return [Float, nil]
53
+ attr_reader :effective_sample_rate
36
54
 
37
- @name = name
55
+ # Additional contexts stored directly on the transaction object.
56
+ # @return [Hash]
57
+ attr_reader :contexts
58
+
59
+ # The Profiler instance for this transaction.
60
+ # @return [Profiler]
61
+ attr_reader :profiler
62
+
63
+ def initialize(
64
+ hub:,
65
+ name: nil,
66
+ source: :custom,
67
+ parent_sampled: nil,
68
+ baggage: nil,
69
+ **options
70
+ )
71
+ super(transaction: self, **options)
72
+
73
+ set_name(name, source: source)
38
74
  @parent_sampled = parent_sampled
39
- @transaction = self
40
75
  @hub = hub
76
+ @baggage = baggage
41
77
  @configuration = hub.configuration # to be removed
42
78
  @tracing_enabled = hub.configuration.tracing_enabled?
43
79
  @traces_sampler = hub.configuration.traces_sampler
44
80
  @traces_sample_rate = hub.configuration.traces_sample_rate
45
81
  @logger = hub.configuration.logger
82
+ @release = hub.configuration.release
83
+ @environment = hub.configuration.environment
84
+ @dsn = hub.configuration.dsn
85
+ @effective_sample_rate = nil
86
+ @contexts = {}
87
+ @measurements = {}
88
+ @profiler = Profiler.new(@configuration)
46
89
  init_span_recorder
47
90
  end
48
91
 
92
+ # @deprecated use Sentry.continue_trace instead.
93
+ #
49
94
  # Initalizes a Transaction instance with a Sentry trace string from another transaction (usually from an external request).
50
95
  #
51
96
  # The original transaction will become the parent of the new Transaction instance. And they will share the same `trace_id`.
52
97
  #
53
98
  # The child transaction will also store the parent's sampling decision in its `parent_sampled` attribute.
54
99
  # @param sentry_trace [String] the trace string from the previous transaction.
100
+ # @param baggage [String, nil] the incoming baggage header string.
55
101
  # @param hub [Hub] the hub that'll be responsible for sending this transaction when it's finished.
56
102
  # @param options [Hash] the options you want to use to initialize a Transaction instance.
57
103
  # @return [Transaction, nil]
58
- def self.from_sentry_trace(sentry_trace, hub: Sentry.get_current_hub, **options)
104
+ def self.from_sentry_trace(sentry_trace, baggage: nil, hub: Sentry.get_current_hub, **options)
59
105
  return unless hub.configuration.tracing_enabled?
60
106
  return unless sentry_trace
61
107
 
62
- match = SENTRY_TRACE_REGEXP.match(sentry_trace)
63
- return if match.nil?
64
- trace_id, parent_span_id, sampled_flag = match[1..3]
65
-
66
- parent_sampled =
67
- if sampled_flag.nil?
68
- nil
69
- else
70
- sampled_flag != "0"
71
- end
108
+ sentry_trace_data = extract_sentry_trace(sentry_trace)
109
+ return unless sentry_trace_data
110
+
111
+ trace_id, parent_span_id, parent_sampled = sentry_trace_data
112
+
113
+ baggage = if baggage && !baggage.empty?
114
+ Baggage.from_incoming_header(baggage)
115
+ else
116
+ # If there's an incoming sentry-trace but no incoming baggage header,
117
+ # for instance in traces coming from older SDKs,
118
+ # baggage will be empty and frozen and won't be populated as head SDK.
119
+ Baggage.new({})
120
+ end
121
+
122
+ baggage.freeze!
123
+
124
+ new(
125
+ trace_id: trace_id,
126
+ parent_span_id: parent_span_id,
127
+ parent_sampled: parent_sampled,
128
+ hub: hub,
129
+ baggage: baggage,
130
+ **options
131
+ )
132
+ end
72
133
 
73
- new(trace_id: trace_id, parent_span_id: parent_span_id, parent_sampled: parent_sampled, hub: hub, **options)
134
+ # @deprecated Use Sentry::PropagationContext.extract_sentry_trace instead.
135
+ # @return [Array, nil]
136
+ def self.extract_sentry_trace(sentry_trace)
137
+ PropagationContext.extract_sentry_trace(sentry_trace)
74
138
  end
75
139
 
76
140
  # @return [Hash]
77
141
  def to_hash
78
142
  hash = super
79
- hash.merge!(name: @name, sampled: @sampled, parent_sampled: @parent_sampled)
143
+
144
+ hash.merge!(
145
+ name: @name,
146
+ source: @source,
147
+ sampled: @sampled,
148
+ parent_sampled: @parent_sampled
149
+ )
150
+
80
151
  hash
81
152
  end
82
153
 
@@ -94,6 +165,15 @@ module Sentry
94
165
  copy
95
166
  end
96
167
 
168
+ # Sets a custom measurement on the transaction.
169
+ # @param name [String] name of the measurement
170
+ # @param value [Float] value of the measurement
171
+ # @param unit [String] unit of the measurement
172
+ # @return [void]
173
+ def set_measurement(name, value, unit = "")
174
+ @measurements[name] = { value: value, unit: unit }
175
+ end
176
+
97
177
  # Sets initial sampling decision of the transaction.
98
178
  # @param sampling_context [Hash] a context Hash that'll be passed to `traces_sampler` (if provided).
99
179
  # @return [void]
@@ -103,7 +183,10 @@ module Sentry
103
183
  return
104
184
  end
105
185
 
106
- return unless @sampled.nil?
186
+ unless @sampled.nil?
187
+ @effective_sample_rate = @sampled ? 1.0 : 0.0
188
+ return
189
+ end
107
190
 
108
191
  sample_rate =
109
192
  if @traces_sampler.is_a?(Proc)
@@ -116,7 +199,11 @@ module Sentry
116
199
 
117
200
  transaction_description = generate_transaction_description
118
201
 
119
- unless [true, false].include?(sample_rate) || (sample_rate.is_a?(Numeric) && sample_rate >= 0.0 && sample_rate <= 1.0)
202
+ if [true, false].include?(sample_rate)
203
+ @effective_sample_rate = sample_rate ? 1.0 : 0.0
204
+ elsif sample_rate.is_a?(Numeric) && sample_rate >= 0.0 && sample_rate <= 1.0
205
+ @effective_sample_rate = sample_rate.to_f
206
+ else
120
207
  @sampled = false
121
208
  log_warn("#{MESSAGE_PREFIX} Discarding #{transaction_description} because of invalid sample_rate: #{sample_rate}")
122
209
  return
@@ -131,7 +218,12 @@ module Sentry
131
218
  if sample_rate == true
132
219
  @sampled = true
133
220
  else
134
- @sampled = Random.rand < sample_rate
221
+ if Sentry.backpressure_monitor
222
+ factor = Sentry.backpressure_monitor.downsample_factor
223
+ @effective_sample_rate /= 2**factor
224
+ end
225
+
226
+ @sampled = Random.rand < @effective_sample_rate
135
227
  end
136
228
 
137
229
  if @sampled
@@ -146,7 +238,7 @@ module Sentry
146
238
  # Finishes the transaction's recording and send it to Sentry.
147
239
  # @param hub [Hub] the hub that'll send this transaction. (Deprecated)
148
240
  # @return [TransactionEvent]
149
- def finish(hub: nil)
241
+ def finish(hub: nil, end_timestamp: nil)
150
242
  if hub
151
243
  log_warn(
152
244
  <<~MSG
@@ -158,20 +250,57 @@ module Sentry
158
250
 
159
251
  hub ||= @hub
160
252
 
161
- super() # Span#finish doesn't take arguments
253
+ super(end_timestamp: end_timestamp)
162
254
 
163
255
  if @name.nil?
164
256
  @name = UNLABELD_NAME
165
257
  end
166
258
 
259
+ @profiler.stop
260
+
167
261
  if @sampled
168
262
  event = hub.current_client.event_from_transaction(self)
169
263
  hub.capture_event(event)
170
264
  else
171
- hub.current_client.transport.record_lost_event(:sample_rate, 'transaction')
265
+ is_backpressure = Sentry.backpressure_monitor&.downsample_factor&.positive?
266
+ reason = is_backpressure ? :backpressure : :sample_rate
267
+ hub.current_client.transport.record_lost_event(reason, 'transaction')
172
268
  end
173
269
  end
174
270
 
271
+ # Get the existing frozen incoming baggage
272
+ # or populate one with sentry- items as the head SDK.
273
+ # @return [Baggage]
274
+ def get_baggage
275
+ populate_head_baggage if @baggage.nil? || @baggage.mutable
276
+ @baggage
277
+ end
278
+
279
+ # Set the transaction name directly.
280
+ # Considered internal api since it bypasses the usual scope logic.
281
+ # @param name [String]
282
+ # @param source [Symbol]
283
+ # @return [void]
284
+ def set_name(name, source: :custom)
285
+ @name = name
286
+ @source = SOURCES.include?(source) ? source.to_sym : :custom
287
+ end
288
+
289
+ # Set contexts directly on the transaction.
290
+ # @param key [String, Symbol]
291
+ # @param value [Object]
292
+ # @return [void]
293
+ def set_context(key, value)
294
+ @contexts[key] = value
295
+ end
296
+
297
+ # Start the profiler.
298
+ # @return [void]
299
+ def start_profiler!
300
+ profiler.set_initial_sample_decision(sampled)
301
+ profiler.start
302
+ end
303
+
175
304
  protected
176
305
 
177
306
  def init_span_recorder(limit = 1000)
@@ -188,6 +317,30 @@ module Sentry
188
317
  result
189
318
  end
190
319
 
320
+ def populate_head_baggage
321
+ items = {
322
+ "trace_id" => trace_id,
323
+ "sample_rate" => effective_sample_rate&.to_s,
324
+ "sampled" => sampled&.to_s,
325
+ "environment" => @environment,
326
+ "release" => @release,
327
+ "public_key" => @dsn&.public_key
328
+ }
329
+
330
+ items["transaction"] = name unless source_low_quality?
331
+
332
+ user = @hub.current_scope&.user
333
+ items["user_segment"] = user["segment"] if user && user["segment"]
334
+
335
+ items.compact!
336
+ @baggage = Baggage.new(items, mutable: false)
337
+ end
338
+
339
+ # These are high cardinality and thus bad
340
+ def source_low_quality?
341
+ source == :url
342
+ end
343
+
191
344
  class SpanRecorder
192
345
  attr_reader :max_length, :spans
193
346
 
@@ -8,9 +8,34 @@ module Sentry
8
8
  # @return [<Array[Span]>]
9
9
  attr_accessor :spans
10
10
 
11
+ # @return [Hash]
12
+ attr_accessor :measurements
13
+
11
14
  # @return [Float, nil]
12
15
  attr_reader :start_timestamp
13
16
 
17
+ # @return [Hash, nil]
18
+ attr_accessor :profile
19
+
20
+ def initialize(transaction:, **options)
21
+ super(**options)
22
+
23
+ self.transaction = transaction.name
24
+ self.transaction_info = { source: transaction.source }
25
+ self.contexts.merge!(transaction.contexts)
26
+ self.contexts.merge!(trace: transaction.get_trace_context)
27
+ self.timestamp = transaction.timestamp
28
+ self.start_timestamp = transaction.start_timestamp
29
+ self.tags = transaction.tags
30
+ self.dynamic_sampling_context = transaction.get_baggage.dynamic_sampling_context
31
+ self.measurements = transaction.measurements
32
+
33
+ finished_spans = transaction.span_recorder.spans.select { |span| span.timestamp && span != transaction }
34
+ self.spans = finished_spans.map(&:to_hash)
35
+
36
+ populate_profile(transaction)
37
+ end
38
+
14
39
  # Sets the event's start_timestamp.
15
40
  # @param time [Time, Float]
16
41
  # @return [void]
@@ -23,7 +48,33 @@ module Sentry
23
48
  data = super
24
49
  data[:spans] = @spans.map(&:to_hash) if @spans
25
50
  data[:start_timestamp] = @start_timestamp
51
+ data[:measurements] = @measurements
26
52
  data
27
53
  end
54
+
55
+ private
56
+
57
+ def populate_profile(transaction)
58
+ profile_hash = transaction.profiler.to_hash
59
+ return if profile_hash.empty?
60
+
61
+ profile_hash.merge!(
62
+ environment: environment,
63
+ release: release,
64
+ timestamp: Time.at(start_timestamp).iso8601,
65
+ device: { architecture: Scope.os_context[:machine] },
66
+ os: { name: Scope.os_context[:name], version: Scope.os_context[:version] },
67
+ runtime: Scope.runtime_context,
68
+ transaction: {
69
+ id: event_id,
70
+ name: transaction.name,
71
+ trace_id: transaction.trace_id,
72
+ # TODO-neel-profiler stubbed for now, see thread_id note in profiler.rb
73
+ active_thead_id: '0'
74
+ }
75
+ )
76
+
77
+ self.profile = profile_hash
78
+ end
28
79
  end
29
80
  end
@@ -3,7 +3,80 @@
3
3
  module Sentry
4
4
  class Transport
5
5
  class Configuration
6
- attr_accessor :timeout, :open_timeout, :proxy, :ssl, :ssl_ca_file, :ssl_verification, :encoding
6
+
7
+ # The timeout in seconds to open a connection to Sentry, in seconds.
8
+ # Default value is 2.
9
+ #
10
+ # @return [Integer]
11
+ attr_accessor :timeout
12
+
13
+ # The timeout in seconds to read data from Sentry, in seconds.
14
+ # Default value is 1.
15
+ #
16
+ # @return [Integer]
17
+ attr_accessor :open_timeout
18
+
19
+ # The proxy configuration to use to connect to Sentry.
20
+ # Accepts either a URI formatted string, URI, or a hash with the `uri`,
21
+ # `user`, and `password` keys.
22
+ #
23
+ # @example
24
+ # # setup proxy using a string:
25
+ # config.transport.proxy = "https://user:password@proxyhost:8080"
26
+ #
27
+ # # setup proxy using a URI:
28
+ # config.transport.proxy = URI("https://user:password@proxyhost:8080")
29
+ #
30
+ # # setup proxy using a hash:
31
+ # config.transport.proxy = {
32
+ # uri: URI("https://proxyhost:8080"),
33
+ # user: "user",
34
+ # password: "password"
35
+ # }
36
+ #
37
+ # If you're using the default transport (`Sentry::HTTPTransport`),
38
+ # proxy settings will also automatically be read from tne environment
39
+ # variables (`HTTP_PROXY`, `HTTPS_PROXY`, `NO_PROXY`).
40
+ #
41
+ # @return [String, URI, Hash, nil]
42
+ attr_accessor :proxy
43
+
44
+ # The SSL configuration to use to connect to Sentry.
45
+ # You can either pass a `Hash` containing `ca_file` and `verification` keys,
46
+ # or you can set those options directly on the `Sentry::HTTPTransport::Configuration` object:
47
+ #
48
+ # @example
49
+ # config.transport.ssl = {
50
+ # ca_file: "/path/to/ca_file",
51
+ # verification: true
52
+ # end
53
+ #
54
+ # @return [Hash, nil]
55
+ attr_accessor :ssl
56
+
57
+ # The path to the CA file to use to verify the SSL connection.
58
+ # Default value is `nil`.
59
+ #
60
+ # @return [String, nil]
61
+ attr_accessor :ssl_ca_file
62
+
63
+ # Whether to verify that the peer certificate is valid in SSL connections.
64
+ # Default value is `true`.
65
+ #
66
+ # @return [Boolean]
67
+ attr_accessor :ssl_verification
68
+
69
+ # The encoding to use to compress the request body.
70
+ # Default value is `Sentry::HTTPTransport::GZIP_ENCODING`.
71
+ #
72
+ # @return [String]
73
+ attr_accessor :encoding
74
+
75
+ # The class to use as a transport to connect to Sentry.
76
+ # If this option not set, it will return `nil`, and Sentry will use
77
+ # `Sentry::HTTPTransport` by default.
78
+ #
79
+ # @return [Class, nil]
7
80
  attr_reader :transport_class
8
81
 
9
82
  def initialize