sentry-ruby 5.13.0 → 5.19.0
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 +4 -4
- data/Gemfile +4 -18
- data/README.md +20 -10
- data/Rakefile +1 -1
- data/bin/console +1 -0
- data/lib/sentry/attachment.rb +42 -0
- data/lib/sentry/background_worker.rb +9 -2
- data/lib/sentry/backpressure_monitor.rb +45 -0
- data/lib/sentry/backtrace.rb +7 -3
- data/lib/sentry/check_in_event.rb +1 -1
- data/lib/sentry/client.rb +69 -16
- data/lib/sentry/configuration.rb +57 -14
- data/lib/sentry/cron/configuration.rb +23 -0
- data/lib/sentry/cron/monitor_check_ins.rb +40 -26
- data/lib/sentry/cron/monitor_schedule.rb +1 -1
- data/lib/sentry/dsn.rb +1 -1
- data/lib/sentry/envelope.rb +18 -1
- data/lib/sentry/error_event.rb +2 -2
- data/lib/sentry/event.rb +13 -39
- data/lib/sentry/faraday.rb +77 -0
- data/lib/sentry/graphql.rb +9 -0
- data/lib/sentry/hub.rb +17 -4
- data/lib/sentry/integrable.rb +4 -0
- data/lib/sentry/interface.rb +1 -0
- data/lib/sentry/interfaces/exception.rb +5 -3
- data/lib/sentry/interfaces/mechanism.rb +20 -0
- data/lib/sentry/interfaces/request.rb +2 -2
- data/lib/sentry/interfaces/single_exception.rb +7 -4
- data/lib/sentry/interfaces/stacktrace_builder.rb +8 -0
- data/lib/sentry/metrics/aggregator.rb +248 -0
- data/lib/sentry/metrics/configuration.rb +47 -0
- data/lib/sentry/metrics/counter_metric.rb +25 -0
- data/lib/sentry/metrics/distribution_metric.rb +25 -0
- data/lib/sentry/metrics/gauge_metric.rb +35 -0
- data/lib/sentry/metrics/local_aggregator.rb +53 -0
- data/lib/sentry/metrics/metric.rb +19 -0
- data/lib/sentry/metrics/set_metric.rb +28 -0
- data/lib/sentry/metrics/timing.rb +43 -0
- data/lib/sentry/metrics.rb +56 -0
- data/lib/sentry/net/http.rb +22 -39
- data/lib/sentry/propagation_context.rb +9 -8
- data/lib/sentry/puma.rb +1 -1
- data/lib/sentry/rack/capture_exceptions.rb +14 -2
- data/lib/sentry/rake.rb +3 -14
- data/lib/sentry/redis.rb +2 -1
- data/lib/sentry/release_detector.rb +1 -1
- data/lib/sentry/scope.rb +47 -37
- data/lib/sentry/session.rb +2 -2
- data/lib/sentry/session_flusher.rb +6 -38
- data/lib/sentry/span.rb +40 -5
- data/lib/sentry/test_helper.rb +2 -1
- data/lib/sentry/threaded_periodic_worker.rb +39 -0
- data/lib/sentry/transaction.rb +25 -16
- data/lib/sentry/transaction_event.rb +5 -0
- data/lib/sentry/transport/configuration.rb +73 -1
- data/lib/sentry/transport/http_transport.rb +68 -37
- data/lib/sentry/transport/spotlight_transport.rb +50 -0
- data/lib/sentry/transport.rb +32 -37
- data/lib/sentry/utils/argument_checking_helper.rb +6 -0
- data/lib/sentry/utils/http_tracing.rb +41 -0
- data/lib/sentry/utils/logging_helper.rb +0 -4
- data/lib/sentry/utils/real_ip.rb +1 -1
- data/lib/sentry/utils/request_id.rb +1 -1
- data/lib/sentry/version.rb +1 -1
- data/lib/sentry-ruby.rb +57 -24
- data/sentry-ruby.gemspec +12 -5
- metadata +42 -7
@@ -50,14 +50,15 @@ module Sentry
|
|
50
50
|
if sentry_trace_data
|
51
51
|
@trace_id, @parent_span_id, @parent_sampled = sentry_trace_data
|
52
52
|
|
53
|
-
@baggage =
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
53
|
+
@baggage =
|
54
|
+
if baggage_header && !baggage_header.empty?
|
55
|
+
Baggage.from_incoming_header(baggage_header)
|
56
|
+
else
|
57
|
+
# If there's an incoming sentry-trace but no incoming baggage header,
|
58
|
+
# for instance in traces coming from older SDKs,
|
59
|
+
# baggage will be empty and frozen and won't be populated as head SDK.
|
60
|
+
Baggage.new({})
|
61
|
+
end
|
61
62
|
|
62
63
|
@baggage.freeze!
|
63
64
|
@incoming_trace = true
|
data/lib/sentry/puma.rb
CHANGED
@@ -4,6 +4,8 @@ module Sentry
|
|
4
4
|
module Rack
|
5
5
|
class CaptureExceptions
|
6
6
|
ERROR_EVENT_ID_KEY = "sentry.error_event_id"
|
7
|
+
MECHANISM_TYPE = "rack"
|
8
|
+
SPAN_ORIGIN = "auto.http.rack"
|
7
9
|
|
8
10
|
def initialize(app)
|
9
11
|
@app = app
|
@@ -56,13 +58,19 @@ module Sentry
|
|
56
58
|
end
|
57
59
|
|
58
60
|
def capture_exception(exception, env)
|
59
|
-
Sentry.capture_exception(exception).tap do |event|
|
61
|
+
Sentry.capture_exception(exception, hint: { mechanism: mechanism }).tap do |event|
|
60
62
|
env[ERROR_EVENT_ID_KEY] = event.event_id if event
|
61
63
|
end
|
62
64
|
end
|
63
65
|
|
64
66
|
def start_transaction(env, scope)
|
65
|
-
options = {
|
67
|
+
options = {
|
68
|
+
name: scope.transaction_name,
|
69
|
+
source: scope.transaction_source,
|
70
|
+
op: transaction_op,
|
71
|
+
origin: SPAN_ORIGIN
|
72
|
+
}
|
73
|
+
|
66
74
|
transaction = Sentry.continue_trace(env, **options)
|
67
75
|
Sentry.start_transaction(transaction: transaction, custom_sampling_context: { env: env }, **options)
|
68
76
|
end
|
@@ -74,6 +82,10 @@ module Sentry
|
|
74
82
|
transaction.set_http_status(status_code)
|
75
83
|
transaction.finish
|
76
84
|
end
|
85
|
+
|
86
|
+
def mechanism
|
87
|
+
Sentry::Mechanism.new(type: MECHANISM_TYPE, handled: false)
|
88
|
+
end
|
77
89
|
end
|
78
90
|
end
|
79
91
|
end
|
data/lib/sentry/rake.rb
CHANGED
@@ -8,7 +8,9 @@ module Sentry
|
|
8
8
|
module Application
|
9
9
|
# @api private
|
10
10
|
def display_error_message(ex)
|
11
|
-
Sentry.
|
11
|
+
mechanism = Sentry::Mechanism.new(type: 'rake', handled: false)
|
12
|
+
|
13
|
+
Sentry.capture_exception(ex, hint: { mechanism: mechanism }) do |scope|
|
12
14
|
task_name = top_level_tasks.join(' ')
|
13
15
|
scope.set_transaction_name(task_name, source: :task)
|
14
16
|
scope.set_tag("rake_task", task_name)
|
@@ -17,15 +19,6 @@ module Sentry
|
|
17
19
|
super
|
18
20
|
end
|
19
21
|
end
|
20
|
-
|
21
|
-
module Task
|
22
|
-
# @api private
|
23
|
-
def execute(args=nil)
|
24
|
-
return super unless Sentry.initialized? && Sentry.get_current_hub
|
25
|
-
|
26
|
-
super
|
27
|
-
end
|
28
|
-
end
|
29
22
|
end
|
30
23
|
end
|
31
24
|
|
@@ -34,8 +27,4 @@ module Rake
|
|
34
27
|
class Application
|
35
28
|
prepend(Sentry::Rake::Application)
|
36
29
|
end
|
37
|
-
|
38
|
-
class Task
|
39
|
-
prepend(Sentry::Rake::Task)
|
40
|
-
end
|
41
30
|
end
|
data/lib/sentry/redis.rb
CHANGED
@@ -4,6 +4,7 @@ module Sentry
|
|
4
4
|
# @api private
|
5
5
|
class Redis
|
6
6
|
OP_NAME = "db.redis"
|
7
|
+
SPAN_ORIGIN = "auto.db.redis"
|
7
8
|
LOGGER_NAME = :redis_logger
|
8
9
|
|
9
10
|
def initialize(commands, host, port, db)
|
@@ -13,7 +14,7 @@ module Sentry
|
|
13
14
|
def instrument
|
14
15
|
return yield unless Sentry.initialized?
|
15
16
|
|
16
|
-
Sentry.with_child_span(op: OP_NAME, start_timestamp: Sentry.utc_now.to_f) do |span|
|
17
|
+
Sentry.with_child_span(op: OP_NAME, start_timestamp: Sentry.utc_now.to_f, origin: SPAN_ORIGIN) do |span|
|
17
18
|
yield.tap do
|
18
19
|
record_breadcrumb
|
19
20
|
|
data/lib/sentry/scope.rb
CHANGED
@@ -2,6 +2,7 @@
|
|
2
2
|
|
3
3
|
require "sentry/breadcrumb_buffer"
|
4
4
|
require "sentry/propagation_context"
|
5
|
+
require "sentry/attachment"
|
5
6
|
require "etc"
|
6
7
|
|
7
8
|
module Sentry
|
@@ -9,8 +10,8 @@ module Sentry
|
|
9
10
|
include ArgumentCheckingHelper
|
10
11
|
|
11
12
|
ATTRIBUTES = [
|
12
|
-
:
|
13
|
-
:
|
13
|
+
:transaction_name,
|
14
|
+
:transaction_source,
|
14
15
|
:contexts,
|
15
16
|
:extra,
|
16
17
|
:tags,
|
@@ -22,6 +23,7 @@ module Sentry
|
|
22
23
|
:rack_env,
|
23
24
|
:span,
|
24
25
|
:session,
|
26
|
+
:attachments,
|
25
27
|
:propagation_context
|
26
28
|
]
|
27
29
|
|
@@ -44,12 +46,19 @@ module Sentry
|
|
44
46
|
# @param hint [Hash] the hint data that'll be passed to event processors.
|
45
47
|
# @return [Event]
|
46
48
|
def apply_to_event(event, hint = nil)
|
47
|
-
event.
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
49
|
+
unless event.is_a?(CheckInEvent)
|
50
|
+
event.tags = tags.merge(event.tags)
|
51
|
+
event.user = user.merge(event.user)
|
52
|
+
event.extra = extra.merge(event.extra)
|
53
|
+
event.contexts = contexts.merge(event.contexts)
|
54
|
+
event.transaction = transaction_name if transaction_name
|
55
|
+
event.transaction_info = { source: transaction_source } if transaction_source
|
56
|
+
event.fingerprint = fingerprint
|
57
|
+
event.level = level
|
58
|
+
event.breadcrumbs = breadcrumbs
|
59
|
+
event.rack_env = rack_env if rack_env
|
60
|
+
event.attachments = attachments
|
61
|
+
end
|
53
62
|
|
54
63
|
if span
|
55
64
|
event.contexts[:trace] ||= span.get_trace_context
|
@@ -58,11 +67,6 @@ module Sentry
|
|
58
67
|
event.dynamic_sampling_context ||= propagation_context.get_dynamic_sampling_context
|
59
68
|
end
|
60
69
|
|
61
|
-
event.fingerprint = fingerprint
|
62
|
-
event.level = level
|
63
|
-
event.breadcrumbs = breadcrumbs
|
64
|
-
event.rack_env = rack_env if rack_env
|
65
|
-
|
66
70
|
all_event_processors = self.class.global_event_processors + @event_processors
|
67
71
|
|
68
72
|
unless all_event_processors.empty?
|
@@ -95,12 +99,13 @@ module Sentry
|
|
95
99
|
copy.extra = extra.deep_dup
|
96
100
|
copy.tags = tags.deep_dup
|
97
101
|
copy.user = user.deep_dup
|
98
|
-
copy.
|
99
|
-
copy.
|
102
|
+
copy.transaction_name = transaction_name.dup
|
103
|
+
copy.transaction_source = transaction_source.dup
|
100
104
|
copy.fingerprint = fingerprint.deep_dup
|
101
105
|
copy.span = span.deep_dup
|
102
106
|
copy.session = session.deep_dup
|
103
107
|
copy.propagation_context = propagation_context.deep_dup
|
108
|
+
copy.attachments = attachments.dup
|
104
109
|
copy
|
105
110
|
end
|
106
111
|
|
@@ -113,11 +118,12 @@ module Sentry
|
|
113
118
|
self.extra = scope.extra
|
114
119
|
self.tags = scope.tags
|
115
120
|
self.user = scope.user
|
116
|
-
self.
|
117
|
-
self.
|
121
|
+
self.transaction_name = scope.transaction_name
|
122
|
+
self.transaction_source = scope.transaction_source
|
118
123
|
self.fingerprint = scope.fingerprint
|
119
124
|
self.span = scope.span
|
120
125
|
self.propagation_context = scope.propagation_context
|
126
|
+
self.attachments = scope.attachments
|
121
127
|
end
|
122
128
|
|
123
129
|
# Updates the scope's data from the given options.
|
@@ -127,14 +133,17 @@ module Sentry
|
|
127
133
|
# @param user [Hash]
|
128
134
|
# @param level [String, Symbol]
|
129
135
|
# @param fingerprint [Array]
|
130
|
-
# @
|
136
|
+
# @param attachments [Array<Attachment>]
|
137
|
+
# @return [Array]
|
131
138
|
def update_from_options(
|
132
139
|
contexts: nil,
|
133
140
|
extra: nil,
|
134
141
|
tags: nil,
|
135
142
|
user: nil,
|
136
143
|
level: nil,
|
137
|
-
fingerprint: nil
|
144
|
+
fingerprint: nil,
|
145
|
+
attachments: nil,
|
146
|
+
**options
|
138
147
|
)
|
139
148
|
self.contexts.merge!(contexts) if contexts
|
140
149
|
self.extra.merge!(extra) if extra
|
@@ -142,6 +151,9 @@ module Sentry
|
|
142
151
|
self.user = user if user
|
143
152
|
self.level = level if level
|
144
153
|
self.fingerprint = fingerprint if fingerprint
|
154
|
+
|
155
|
+
# Returns unsupported option keys so we can notify users.
|
156
|
+
options.keys
|
145
157
|
end
|
146
158
|
|
147
159
|
# Sets the scope's rack_env attribute.
|
@@ -226,8 +238,8 @@ module Sentry
|
|
226
238
|
# @param transaction_name [String]
|
227
239
|
# @return [void]
|
228
240
|
def set_transaction_name(transaction_name, source: :custom)
|
229
|
-
@
|
230
|
-
@
|
241
|
+
@transaction_name = transaction_name
|
242
|
+
@transaction_source = source
|
231
243
|
end
|
232
244
|
|
233
245
|
# Sets the currently active session on the scope.
|
@@ -237,18 +249,10 @@ module Sentry
|
|
237
249
|
@session = session
|
238
250
|
end
|
239
251
|
|
240
|
-
#
|
241
|
-
#
|
242
|
-
|
243
|
-
|
244
|
-
@transaction_names.last
|
245
|
-
end
|
246
|
-
|
247
|
-
# Returns current transaction source.
|
248
|
-
# The "transaction" here does not refer to `Transaction` objects.
|
249
|
-
# @return [String, nil]
|
250
|
-
def transaction_source
|
251
|
-
@transaction_sources.last
|
252
|
+
# These are high cardinality and thus bad.
|
253
|
+
# @return [Boolean]
|
254
|
+
def transaction_source_low_quality?
|
255
|
+
transaction_source == :url
|
252
256
|
end
|
253
257
|
|
254
258
|
# Returns the associated Transaction object.
|
@@ -286,6 +290,12 @@ module Sentry
|
|
286
290
|
@propagation_context = PropagationContext.new(self, env)
|
287
291
|
end
|
288
292
|
|
293
|
+
# Add a new attachment to the scope.
|
294
|
+
def add_attachment(**opts)
|
295
|
+
attachments << (attachment = Attachment.new(**opts))
|
296
|
+
attachment
|
297
|
+
end
|
298
|
+
|
289
299
|
protected
|
290
300
|
|
291
301
|
# for duplicating scopes internally
|
@@ -294,18 +304,19 @@ module Sentry
|
|
294
304
|
private
|
295
305
|
|
296
306
|
def set_default_value
|
297
|
-
@contexts = { :
|
307
|
+
@contexts = { os: self.class.os_context, runtime: self.class.runtime_context }
|
298
308
|
@extra = {}
|
299
309
|
@tags = {}
|
300
310
|
@user = {}
|
301
311
|
@level = :error
|
302
312
|
@fingerprint = []
|
303
|
-
@
|
304
|
-
@
|
313
|
+
@transaction_name = nil
|
314
|
+
@transaction_source = nil
|
305
315
|
@event_processors = []
|
306
316
|
@rack_env = {}
|
307
317
|
@span = nil
|
308
318
|
@session = nil
|
319
|
+
@attachments = []
|
309
320
|
generate_propagation_context
|
310
321
|
set_new_breadcrumb_buffer
|
311
322
|
end
|
@@ -354,6 +365,5 @@ module Sentry
|
|
354
365
|
global_event_processors << block
|
355
366
|
end
|
356
367
|
end
|
357
|
-
|
358
368
|
end
|
359
369
|
end
|
data/lib/sentry/session.rb
CHANGED
@@ -5,8 +5,8 @@ module Sentry
|
|
5
5
|
attr_reader :started, :status, :aggregation_key
|
6
6
|
|
7
7
|
# TODO-neel add :crashed after adding handled mechanism
|
8
|
-
STATUSES = %i
|
9
|
-
AGGREGATE_STATUSES = %i
|
8
|
+
STATUSES = %i[ok errored exited]
|
9
|
+
AGGREGATE_STATUSES = %i[errored exited]
|
10
10
|
|
11
11
|
def initialize
|
12
12
|
@started = Sentry.utc_now
|
@@ -1,58 +1,38 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
module Sentry
|
4
|
-
class SessionFlusher
|
5
|
-
include LoggingHelper
|
6
|
-
|
4
|
+
class SessionFlusher < ThreadedPeriodicWorker
|
7
5
|
FLUSH_INTERVAL = 60
|
8
6
|
|
9
7
|
def initialize(configuration, client)
|
10
|
-
|
11
|
-
@exited = false
|
8
|
+
super(configuration.logger, FLUSH_INTERVAL)
|
12
9
|
@client = client
|
13
10
|
@pending_aggregates = {}
|
14
11
|
@release = configuration.release
|
15
12
|
@environment = configuration.environment
|
16
|
-
@logger = configuration.logger
|
17
13
|
|
18
14
|
log_debug("[Sessions] Sessions won't be captured without a valid release") unless @release
|
19
15
|
end
|
20
16
|
|
21
17
|
def flush
|
22
18
|
return if @pending_aggregates.empty?
|
23
|
-
envelope = pending_envelope
|
24
|
-
|
25
|
-
Sentry.background_worker.perform do
|
26
|
-
@client.transport.send_envelope(envelope)
|
27
|
-
end
|
28
19
|
|
20
|
+
@client.capture_envelope(pending_envelope)
|
29
21
|
@pending_aggregates = {}
|
30
22
|
end
|
31
23
|
|
24
|
+
alias_method :run, :flush
|
25
|
+
|
32
26
|
def add_session(session)
|
33
|
-
return if @exited
|
34
27
|
return unless @release
|
35
28
|
|
36
|
-
|
37
|
-
ensure_thread
|
38
|
-
rescue ThreadError
|
39
|
-
log_debug("Session flusher thread creation failed")
|
40
|
-
@exited = true
|
41
|
-
return
|
42
|
-
end
|
29
|
+
return unless ensure_thread
|
43
30
|
|
44
31
|
return unless Session::AGGREGATE_STATUSES.include?(session.status)
|
45
32
|
@pending_aggregates[session.aggregation_key] ||= init_aggregates(session.aggregation_key)
|
46
33
|
@pending_aggregates[session.aggregation_key][session.status] += 1
|
47
34
|
end
|
48
35
|
|
49
|
-
def kill
|
50
|
-
log_debug("Killing session flusher")
|
51
|
-
|
52
|
-
@exited = true
|
53
|
-
@thread&.kill
|
54
|
-
end
|
55
|
-
|
56
36
|
private
|
57
37
|
|
58
38
|
def init_aggregates(aggregation_key)
|
@@ -74,17 +54,5 @@ module Sentry
|
|
74
54
|
def attrs
|
75
55
|
{ release: @release, environment: @environment }
|
76
56
|
end
|
77
|
-
|
78
|
-
def ensure_thread
|
79
|
-
return if @thread&.alive?
|
80
|
-
|
81
|
-
@thread = Thread.new do
|
82
|
-
loop do
|
83
|
-
sleep(FLUSH_INTERVAL)
|
84
|
-
flush
|
85
|
-
end
|
86
|
-
end
|
87
|
-
end
|
88
|
-
|
89
57
|
end
|
90
58
|
end
|
data/lib/sentry/span.rb
CHANGED
@@ -1,10 +1,10 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require "securerandom"
|
4
|
+
require "sentry/metrics/local_aggregator"
|
4
5
|
|
5
6
|
module Sentry
|
6
7
|
class Span
|
7
|
-
|
8
8
|
# We will try to be consistent with OpenTelemetry on this front going forward.
|
9
9
|
# https://develop.sentry.dev/sdk/performance/span-data-conventions/
|
10
10
|
module DataConventions
|
@@ -39,6 +39,11 @@ module Sentry
|
|
39
39
|
# Recommended: If different than server.port.
|
40
40
|
# Example: 16456
|
41
41
|
SERVER_SOCKET_PORT = "server.socket.port"
|
42
|
+
|
43
|
+
FILEPATH = "code.filepath"
|
44
|
+
LINENO = "code.lineno"
|
45
|
+
FUNCTION = "code.function"
|
46
|
+
NAMESPACE = "code.namespace"
|
42
47
|
end
|
43
48
|
|
44
49
|
STATUS_MAP = {
|
@@ -55,6 +60,8 @@ module Sentry
|
|
55
60
|
504 => "deadline_exceeded"
|
56
61
|
}
|
57
62
|
|
63
|
+
DEFAULT_SPAN_ORIGIN = "manual"
|
64
|
+
|
58
65
|
# An uuid that can be used to identify a trace.
|
59
66
|
# @return [String]
|
60
67
|
attr_reader :trace_id
|
@@ -88,6 +95,9 @@ module Sentry
|
|
88
95
|
# Span data
|
89
96
|
# @return [Hash]
|
90
97
|
attr_reader :data
|
98
|
+
# Span origin that tracks what kind of instrumentation created a span
|
99
|
+
# @return [String]
|
100
|
+
attr_reader :origin
|
91
101
|
|
92
102
|
# The SpanRecorder the current span belongs to.
|
93
103
|
# SpanRecorder holds all spans under the same Transaction object (including the Transaction itself).
|
@@ -109,7 +119,8 @@ module Sentry
|
|
109
119
|
parent_span_id: nil,
|
110
120
|
sampled: nil,
|
111
121
|
start_timestamp: nil,
|
112
|
-
timestamp: nil
|
122
|
+
timestamp: nil,
|
123
|
+
origin: nil
|
113
124
|
)
|
114
125
|
@trace_id = trace_id || SecureRandom.uuid.delete("-")
|
115
126
|
@span_id = span_id || SecureRandom.uuid.delete("-").slice(0, 16)
|
@@ -123,6 +134,7 @@ module Sentry
|
|
123
134
|
@status = status
|
124
135
|
@data = {}
|
125
136
|
@tags = {}
|
137
|
+
@origin = origin || DEFAULT_SPAN_ORIGIN
|
126
138
|
end
|
127
139
|
|
128
140
|
# Finishes the span by adding a timestamp.
|
@@ -150,7 +162,7 @@ module Sentry
|
|
150
162
|
|
151
163
|
# @return [Hash]
|
152
164
|
def to_hash
|
153
|
-
{
|
165
|
+
hash = {
|
154
166
|
trace_id: @trace_id,
|
155
167
|
span_id: @span_id,
|
156
168
|
parent_span_id: @parent_span_id,
|
@@ -160,8 +172,14 @@ module Sentry
|
|
160
172
|
op: @op,
|
161
173
|
status: @status,
|
162
174
|
tags: @tags,
|
163
|
-
data: @data
|
175
|
+
data: @data,
|
176
|
+
origin: @origin
|
164
177
|
}
|
178
|
+
|
179
|
+
summary = metrics_summary
|
180
|
+
hash[:_metrics_summary] = summary if summary
|
181
|
+
|
182
|
+
hash
|
165
183
|
end
|
166
184
|
|
167
185
|
# Returns the span's context that can be used to embed in an Event.
|
@@ -173,7 +191,9 @@ module Sentry
|
|
173
191
|
parent_span_id: @parent_span_id,
|
174
192
|
description: @description,
|
175
193
|
op: @op,
|
176
|
-
status: @status
|
194
|
+
status: @status,
|
195
|
+
origin: @origin,
|
196
|
+
data: @data
|
177
197
|
}
|
178
198
|
end
|
179
199
|
|
@@ -269,5 +289,20 @@ module Sentry
|
|
269
289
|
def set_tag(key, value)
|
270
290
|
@tags[key] = value
|
271
291
|
end
|
292
|
+
|
293
|
+
# Sets the origin of the span.
|
294
|
+
# @param origin [String]
|
295
|
+
def set_origin(origin)
|
296
|
+
@origin = origin
|
297
|
+
end
|
298
|
+
|
299
|
+
# Collects gauge metrics on the span for metric summaries.
|
300
|
+
def metrics_local_aggregator
|
301
|
+
@metrics_local_aggregator ||= Sentry::Metrics::LocalAggregator.new
|
302
|
+
end
|
303
|
+
|
304
|
+
def metrics_summary
|
305
|
+
@metrics_local_aggregator&.to_hash
|
306
|
+
end
|
272
307
|
end
|
273
308
|
end
|
data/lib/sentry/test_helper.rb
CHANGED
@@ -20,7 +20,7 @@ module Sentry
|
|
20
20
|
# set transport to DummyTransport, so we can easily intercept the captured events
|
21
21
|
dummy_config.transport.transport_class = Sentry::DummyTransport
|
22
22
|
# make sure SDK allows sending under the current environment
|
23
|
-
dummy_config.enabled_environments
|
23
|
+
dummy_config.enabled_environments += [dummy_config.environment] unless dummy_config.enabled_environments.include?(dummy_config.environment)
|
24
24
|
# disble async event sending
|
25
25
|
dummy_config.background_worker_threads = 0
|
26
26
|
|
@@ -50,6 +50,7 @@ module Sentry
|
|
50
50
|
if Sentry.get_current_hub.instance_variable_get(:@stack).size > 1
|
51
51
|
Sentry.get_current_hub.pop_scope
|
52
52
|
end
|
53
|
+
Sentry::Scope.global_event_processors.clear
|
53
54
|
end
|
54
55
|
|
55
56
|
# @return [Transport]
|
@@ -0,0 +1,39 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Sentry
|
4
|
+
class ThreadedPeriodicWorker
|
5
|
+
include LoggingHelper
|
6
|
+
|
7
|
+
def initialize(logger, internal)
|
8
|
+
@thread = nil
|
9
|
+
@exited = false
|
10
|
+
@interval = internal
|
11
|
+
@logger = logger
|
12
|
+
end
|
13
|
+
|
14
|
+
def ensure_thread
|
15
|
+
return false if @exited
|
16
|
+
return true if @thread&.alive?
|
17
|
+
|
18
|
+
@thread = Thread.new do
|
19
|
+
loop do
|
20
|
+
sleep(@interval)
|
21
|
+
run
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
true
|
26
|
+
rescue ThreadError
|
27
|
+
log_debug("[#{self.class.name}] thread creation failed")
|
28
|
+
@exited = true
|
29
|
+
false
|
30
|
+
end
|
31
|
+
|
32
|
+
def kill
|
33
|
+
log_debug("[#{self.class.name}] thread killed")
|
34
|
+
|
35
|
+
@exited = true
|
36
|
+
@thread&.kill
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
data/lib/sentry/transaction.rb
CHANGED
@@ -13,7 +13,7 @@ module Sentry
|
|
13
13
|
MESSAGE_PREFIX = "[Tracing]"
|
14
14
|
|
15
15
|
# https://develop.sentry.dev/sdk/event-payloads/transaction/#transaction-annotations
|
16
|
-
SOURCES = %i
|
16
|
+
SOURCES = %i[custom url route view component task]
|
17
17
|
|
18
18
|
include LoggingHelper
|
19
19
|
|
@@ -110,14 +110,15 @@ module Sentry
|
|
110
110
|
|
111
111
|
trace_id, parent_span_id, parent_sampled = sentry_trace_data
|
112
112
|
|
113
|
-
baggage =
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
113
|
+
baggage =
|
114
|
+
if baggage && !baggage.empty?
|
115
|
+
Baggage.from_incoming_header(baggage)
|
116
|
+
else
|
117
|
+
# If there's an incoming sentry-trace but no incoming baggage header,
|
118
|
+
# for instance in traces coming from older SDKs,
|
119
|
+
# baggage will be empty and frozen and won't be populated as head SDK.
|
120
|
+
Baggage.new({})
|
121
|
+
end
|
121
122
|
|
122
123
|
baggage.freeze!
|
123
124
|
|
@@ -218,7 +219,12 @@ module Sentry
|
|
218
219
|
if sample_rate == true
|
219
220
|
@sampled = true
|
220
221
|
else
|
221
|
-
|
222
|
+
if Sentry.backpressure_monitor
|
223
|
+
factor = Sentry.backpressure_monitor.downsample_factor
|
224
|
+
@effective_sample_rate /= 2**factor
|
225
|
+
end
|
226
|
+
|
227
|
+
@sampled = Random.rand < @effective_sample_rate
|
222
228
|
end
|
223
229
|
|
224
230
|
if @sampled
|
@@ -257,7 +263,10 @@ module Sentry
|
|
257
263
|
event = hub.current_client.event_from_transaction(self)
|
258
264
|
hub.capture_event(event)
|
259
265
|
else
|
260
|
-
|
266
|
+
is_backpressure = Sentry.backpressure_monitor&.downsample_factor&.positive?
|
267
|
+
reason = is_backpressure ? :backpressure : :sample_rate
|
268
|
+
hub.current_client.transport.record_lost_event(reason, 'transaction')
|
269
|
+
hub.current_client.transport.record_lost_event(reason, 'span')
|
261
270
|
end
|
262
271
|
end
|
263
272
|
|
@@ -294,6 +303,11 @@ module Sentry
|
|
294
303
|
profiler.start
|
295
304
|
end
|
296
305
|
|
306
|
+
# These are high cardinality and thus bad
|
307
|
+
def source_low_quality?
|
308
|
+
source == :url
|
309
|
+
end
|
310
|
+
|
297
311
|
protected
|
298
312
|
|
299
313
|
def init_span_recorder(limit = 1000)
|
@@ -329,11 +343,6 @@ module Sentry
|
|
329
343
|
@baggage = Baggage.new(items, mutable: false)
|
330
344
|
end
|
331
345
|
|
332
|
-
# These are high cardinality and thus bad
|
333
|
-
def source_low_quality?
|
334
|
-
source == :url
|
335
|
-
end
|
336
|
-
|
337
346
|
class SpanRecorder
|
338
347
|
attr_reader :max_length, :spans
|
339
348
|
|