sentry-ruby 5.16.1 → 5.21.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 +6 -0
- data/README.md +20 -10
- data/Rakefile +3 -1
- data/bin/console +2 -0
- data/lib/sentry/attachment.rb +40 -0
- data/lib/sentry/background_worker.rb +1 -1
- data/lib/sentry/backpressure_monitor.rb +2 -32
- data/lib/sentry/backtrace.rb +10 -8
- data/lib/sentry/baggage.rb +7 -7
- data/lib/sentry/breadcrumb/sentry_logger.rb +6 -6
- data/lib/sentry/check_in_event.rb +5 -5
- data/lib/sentry/client.rb +61 -11
- data/lib/sentry/configuration.rb +77 -31
- data/lib/sentry/core_ext/object/deep_dup.rb +1 -1
- data/lib/sentry/cron/monitor_check_ins.rb +3 -1
- data/lib/sentry/cron/monitor_config.rb +1 -1
- data/lib/sentry/cron/monitor_schedule.rb +1 -1
- data/lib/sentry/dsn.rb +4 -4
- data/lib/sentry/envelope/item.rb +88 -0
- data/lib/sentry/envelope.rb +2 -68
- data/lib/sentry/error_event.rb +2 -2
- data/lib/sentry/event.rb +20 -18
- data/lib/sentry/faraday.rb +77 -0
- data/lib/sentry/graphql.rb +9 -0
- data/lib/sentry/hub.rb +23 -3
- 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 +7 -7
- data/lib/sentry/interfaces/single_exception.rb +9 -7
- data/lib/sentry/interfaces/stacktrace.rb +3 -1
- data/lib/sentry/interfaces/stacktrace_builder.rb +23 -2
- data/lib/sentry/logger.rb +1 -1
- 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 +18 -39
- data/lib/sentry/profiler/helpers.rb +46 -0
- data/lib/sentry/profiler.rb +25 -56
- data/lib/sentry/propagation_context.rb +10 -9
- data/lib/sentry/puma.rb +1 -1
- data/lib/sentry/rack/capture_exceptions.rb +16 -4
- data/lib/sentry/rack.rb +2 -2
- data/lib/sentry/rake.rb +4 -2
- data/lib/sentry/redis.rb +2 -1
- data/lib/sentry/release_detector.rb +4 -4
- data/lib/sentry/scope.rb +36 -26
- data/lib/sentry/session.rb +2 -2
- data/lib/sentry/session_flusher.rb +7 -39
- data/lib/sentry/span.rb +46 -5
- data/lib/sentry/test_helper.rb +5 -2
- data/lib/sentry/threaded_periodic_worker.rb +39 -0
- data/lib/sentry/transaction.rb +19 -17
- data/lib/sentry/transaction_event.rb +6 -2
- data/lib/sentry/transport/configuration.rb +0 -1
- data/lib/sentry/transport/http_transport.rb +12 -12
- data/lib/sentry/transport.rb +18 -26
- data/lib/sentry/utils/argument_checking_helper.rb +6 -0
- data/lib/sentry/utils/env_helper.rb +21 -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 +2 -2
- data/lib/sentry/utils/request_id.rb +1 -1
- data/lib/sentry/vernier/output.rb +89 -0
- data/lib/sentry/vernier/profiler.rb +125 -0
- data/lib/sentry/version.rb +1 -1
- data/lib/sentry-ruby.rb +38 -6
- data/sentry-ruby-core.gemspec +3 -1
- data/sentry-ruby.gemspec +15 -6
- metadata +44 -7
data/lib/sentry/rake.rb
CHANGED
@@ -8,8 +8,10 @@ module Sentry
|
|
8
8
|
module Application
|
9
9
|
# @api private
|
10
10
|
def display_error_message(ex)
|
11
|
-
Sentry.
|
12
|
-
|
11
|
+
mechanism = Sentry::Mechanism.new(type: "rake", handled: false)
|
12
|
+
|
13
|
+
Sentry.capture_exception(ex, hint: { mechanism: mechanism }) do |scope|
|
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)
|
15
17
|
end if Sentry.initialized? && !Sentry.configuration.skip_rake_integration
|
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
|
|
@@ -13,12 +13,12 @@ module Sentry
|
|
13
13
|
|
14
14
|
def detect_release_from_heroku(running_on_heroku)
|
15
15
|
return unless running_on_heroku
|
16
|
-
ENV[
|
16
|
+
ENV["HEROKU_SLUG_COMMIT"]
|
17
17
|
end
|
18
18
|
|
19
19
|
def detect_release_from_capistrano(project_root)
|
20
|
-
revision_file = File.join(project_root,
|
21
|
-
revision_log = File.join(project_root,
|
20
|
+
revision_file = File.join(project_root, "REVISION")
|
21
|
+
revision_log = File.join(project_root, "..", "revisions.log")
|
22
22
|
|
23
23
|
if File.exist?(revision_file)
|
24
24
|
File.read(revision_file).strip
|
@@ -32,7 +32,7 @@ module Sentry
|
|
32
32
|
end
|
33
33
|
|
34
34
|
def detect_release_from_env
|
35
|
-
ENV[
|
35
|
+
ENV["SENTRY_RELEASE"]
|
36
36
|
end
|
37
37
|
end
|
38
38
|
end
|
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
|
|
@@ -55,10 +57,12 @@ module Sentry
|
|
55
57
|
event.level = level
|
56
58
|
event.breadcrumbs = breadcrumbs
|
57
59
|
event.rack_env = rack_env if rack_env
|
60
|
+
event.attachments = attachments
|
58
61
|
end
|
59
62
|
|
60
63
|
if span
|
61
64
|
event.contexts[:trace] ||= span.get_trace_context
|
65
|
+
event.dynamic_sampling_context ||= span.get_dynamic_sampling_context
|
62
66
|
else
|
63
67
|
event.contexts[:trace] ||= propagation_context.get_trace_context
|
64
68
|
event.dynamic_sampling_context ||= propagation_context.get_dynamic_sampling_context
|
@@ -96,12 +100,13 @@ module Sentry
|
|
96
100
|
copy.extra = extra.deep_dup
|
97
101
|
copy.tags = tags.deep_dup
|
98
102
|
copy.user = user.deep_dup
|
99
|
-
copy.
|
100
|
-
copy.
|
103
|
+
copy.transaction_name = transaction_name.dup
|
104
|
+
copy.transaction_source = transaction_source.dup
|
101
105
|
copy.fingerprint = fingerprint.deep_dup
|
102
106
|
copy.span = span.deep_dup
|
103
107
|
copy.session = session.deep_dup
|
104
108
|
copy.propagation_context = propagation_context.deep_dup
|
109
|
+
copy.attachments = attachments.dup
|
105
110
|
copy
|
106
111
|
end
|
107
112
|
|
@@ -114,11 +119,12 @@ module Sentry
|
|
114
119
|
self.extra = scope.extra
|
115
120
|
self.tags = scope.tags
|
116
121
|
self.user = scope.user
|
117
|
-
self.
|
118
|
-
self.
|
122
|
+
self.transaction_name = scope.transaction_name
|
123
|
+
self.transaction_source = scope.transaction_source
|
119
124
|
self.fingerprint = scope.fingerprint
|
120
125
|
self.span = scope.span
|
121
126
|
self.propagation_context = scope.propagation_context
|
127
|
+
self.attachments = scope.attachments
|
122
128
|
end
|
123
129
|
|
124
130
|
# Updates the scope's data from the given options.
|
@@ -128,14 +134,17 @@ module Sentry
|
|
128
134
|
# @param user [Hash]
|
129
135
|
# @param level [String, Symbol]
|
130
136
|
# @param fingerprint [Array]
|
131
|
-
# @
|
137
|
+
# @param attachments [Array<Attachment>]
|
138
|
+
# @return [Array]
|
132
139
|
def update_from_options(
|
133
140
|
contexts: nil,
|
134
141
|
extra: nil,
|
135
142
|
tags: nil,
|
136
143
|
user: nil,
|
137
144
|
level: nil,
|
138
|
-
fingerprint: nil
|
145
|
+
fingerprint: nil,
|
146
|
+
attachments: nil,
|
147
|
+
**options
|
139
148
|
)
|
140
149
|
self.contexts.merge!(contexts) if contexts
|
141
150
|
self.extra.merge!(extra) if extra
|
@@ -143,6 +152,9 @@ module Sentry
|
|
143
152
|
self.user = user if user
|
144
153
|
self.level = level if level
|
145
154
|
self.fingerprint = fingerprint if fingerprint
|
155
|
+
|
156
|
+
# Returns unsupported option keys so we can notify users.
|
157
|
+
options.keys
|
146
158
|
end
|
147
159
|
|
148
160
|
# Sets the scope's rack_env attribute.
|
@@ -227,8 +239,8 @@ module Sentry
|
|
227
239
|
# @param transaction_name [String]
|
228
240
|
# @return [void]
|
229
241
|
def set_transaction_name(transaction_name, source: :custom)
|
230
|
-
@
|
231
|
-
@
|
242
|
+
@transaction_name = transaction_name
|
243
|
+
@transaction_source = source
|
232
244
|
end
|
233
245
|
|
234
246
|
# Sets the currently active session on the scope.
|
@@ -238,18 +250,10 @@ module Sentry
|
|
238
250
|
@session = session
|
239
251
|
end
|
240
252
|
|
241
|
-
#
|
242
|
-
#
|
243
|
-
|
244
|
-
|
245
|
-
@transaction_names.last
|
246
|
-
end
|
247
|
-
|
248
|
-
# Returns current transaction source.
|
249
|
-
# The "transaction" here does not refer to `Transaction` objects.
|
250
|
-
# @return [String, nil]
|
251
|
-
def transaction_source
|
252
|
-
@transaction_sources.last
|
253
|
+
# These are high cardinality and thus bad.
|
254
|
+
# @return [Boolean]
|
255
|
+
def transaction_source_low_quality?
|
256
|
+
transaction_source == :url
|
253
257
|
end
|
254
258
|
|
255
259
|
# Returns the associated Transaction object.
|
@@ -287,6 +291,12 @@ module Sentry
|
|
287
291
|
@propagation_context = PropagationContext.new(self, env)
|
288
292
|
end
|
289
293
|
|
294
|
+
# Add a new attachment to the scope.
|
295
|
+
def add_attachment(**opts)
|
296
|
+
attachments << (attachment = Attachment.new(**opts))
|
297
|
+
attachment
|
298
|
+
end
|
299
|
+
|
290
300
|
protected
|
291
301
|
|
292
302
|
# for duplicating scopes internally
|
@@ -295,18 +305,19 @@ module Sentry
|
|
295
305
|
private
|
296
306
|
|
297
307
|
def set_default_value
|
298
|
-
@contexts = { :
|
308
|
+
@contexts = { os: self.class.os_context, runtime: self.class.runtime_context }
|
299
309
|
@extra = {}
|
300
310
|
@tags = {}
|
301
311
|
@user = {}
|
302
312
|
@level = :error
|
303
313
|
@fingerprint = []
|
304
|
-
@
|
305
|
-
@
|
314
|
+
@transaction_name = nil
|
315
|
+
@transaction_source = nil
|
306
316
|
@event_processors = []
|
307
317
|
@rack_env = {}
|
308
318
|
@span = nil
|
309
319
|
@session = nil
|
320
|
+
@attachments = []
|
310
321
|
generate_propagation_context
|
311
322
|
set_new_breadcrumb_buffer
|
312
323
|
end
|
@@ -355,6 +366,5 @@ module Sentry
|
|
355
366
|
global_event_processors << block
|
356
367
|
end
|
357
368
|
end
|
358
|
-
|
359
369
|
end
|
360
370
|
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)
|
@@ -64,7 +44,7 @@ module Sentry
|
|
64
44
|
def pending_envelope
|
65
45
|
envelope = Envelope.new
|
66
46
|
|
67
|
-
header = { type:
|
47
|
+
header = { type: "sessions" }
|
68
48
|
payload = { attrs: attrs, aggregates: @pending_aggregates.values }
|
69
49
|
|
70
50
|
envelope.add_item(header, payload)
|
@@ -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.
|
@@ -148,9 +160,15 @@ module Sentry
|
|
148
160
|
transaction.get_baggage&.serialize
|
149
161
|
end
|
150
162
|
|
163
|
+
# Returns the Dynamic Sampling Context from the transaction baggage.
|
164
|
+
# @return [Hash, nil]
|
165
|
+
def get_dynamic_sampling_context
|
166
|
+
transaction.get_baggage&.dynamic_sampling_context
|
167
|
+
end
|
168
|
+
|
151
169
|
# @return [Hash]
|
152
170
|
def to_hash
|
153
|
-
{
|
171
|
+
hash = {
|
154
172
|
trace_id: @trace_id,
|
155
173
|
span_id: @span_id,
|
156
174
|
parent_span_id: @parent_span_id,
|
@@ -160,8 +178,14 @@ module Sentry
|
|
160
178
|
op: @op,
|
161
179
|
status: @status,
|
162
180
|
tags: @tags,
|
163
|
-
data: @data
|
181
|
+
data: @data,
|
182
|
+
origin: @origin
|
164
183
|
}
|
184
|
+
|
185
|
+
summary = metrics_summary
|
186
|
+
hash[:_metrics_summary] = summary if summary
|
187
|
+
|
188
|
+
hash
|
165
189
|
end
|
166
190
|
|
167
191
|
# Returns the span's context that can be used to embed in an Event.
|
@@ -173,7 +197,9 @@ module Sentry
|
|
173
197
|
parent_span_id: @parent_span_id,
|
174
198
|
description: @description,
|
175
199
|
op: @op,
|
176
|
-
status: @status
|
200
|
+
status: @status,
|
201
|
+
origin: @origin,
|
202
|
+
data: @data
|
177
203
|
}
|
178
204
|
end
|
179
205
|
|
@@ -269,5 +295,20 @@ module Sentry
|
|
269
295
|
def set_tag(key, value)
|
270
296
|
@tags[key] = value
|
271
297
|
end
|
298
|
+
|
299
|
+
# Sets the origin of the span.
|
300
|
+
# @param origin [String]
|
301
|
+
def set_origin(origin)
|
302
|
+
@origin = origin
|
303
|
+
end
|
304
|
+
|
305
|
+
# Collects gauge metrics on the span for metric summaries.
|
306
|
+
def metrics_local_aggregator
|
307
|
+
@metrics_local_aggregator ||= Sentry::Metrics::LocalAggregator.new
|
308
|
+
end
|
309
|
+
|
310
|
+
def metrics_summary
|
311
|
+
@metrics_local_aggregator&.to_hash
|
312
|
+
end
|
272
313
|
end
|
273
314
|
end
|
data/lib/sentry/test_helper.rb
CHANGED
@@ -1,6 +1,8 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Sentry
|
2
4
|
module TestHelper
|
3
|
-
DUMMY_DSN =
|
5
|
+
DUMMY_DSN = "http://12345:67890@sentry.localdomain/sentry/42"
|
4
6
|
|
5
7
|
# Alters the existing SDK configuration with test-suitable options. Mainly:
|
6
8
|
# - Sets a dummy DSN instead of `nil` or an actual DSN.
|
@@ -20,7 +22,7 @@ module Sentry
|
|
20
22
|
# set transport to DummyTransport, so we can easily intercept the captured events
|
21
23
|
dummy_config.transport.transport_class = Sentry::DummyTransport
|
22
24
|
# make sure SDK allows sending under the current environment
|
23
|
-
dummy_config.enabled_environments
|
25
|
+
dummy_config.enabled_environments += [dummy_config.environment] unless dummy_config.enabled_environments.include?(dummy_config.environment)
|
24
26
|
# disble async event sending
|
25
27
|
dummy_config.background_worker_threads = 0
|
26
28
|
|
@@ -50,6 +52,7 @@ module Sentry
|
|
50
52
|
if Sentry.get_current_hub.instance_variable_get(:@stack).size > 1
|
51
53
|
Sentry.get_current_hub.pop_scope
|
52
54
|
end
|
55
|
+
Sentry::Scope.global_event_processors.clear
|
53
56
|
end
|
54
57
|
|
55
58
|
# @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
@@ -9,11 +9,11 @@ module Sentry
|
|
9
9
|
# @deprecated Use Sentry::PropagationContext::SENTRY_TRACE_REGEXP instead.
|
10
10
|
SENTRY_TRACE_REGEXP = PropagationContext::SENTRY_TRACE_REGEXP
|
11
11
|
|
12
|
-
UNLABELD_NAME = "<unlabeled transaction>"
|
12
|
+
UNLABELD_NAME = "<unlabeled transaction>"
|
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
|
|
@@ -85,7 +85,7 @@ module Sentry
|
|
85
85
|
@effective_sample_rate = nil
|
86
86
|
@contexts = {}
|
87
87
|
@measurements = {}
|
88
|
-
@profiler =
|
88
|
+
@profiler = @configuration.profiler_class.new(@configuration)
|
89
89
|
init_span_recorder
|
90
90
|
end
|
91
91
|
|
@@ -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
|
|
@@ -264,7 +265,8 @@ module Sentry
|
|
264
265
|
else
|
265
266
|
is_backpressure = Sentry.backpressure_monitor&.downsample_factor&.positive?
|
266
267
|
reason = is_backpressure ? :backpressure : :sample_rate
|
267
|
-
hub.current_client.transport.record_lost_event(reason,
|
268
|
+
hub.current_client.transport.record_lost_event(reason, "transaction")
|
269
|
+
hub.current_client.transport.record_lost_event(reason, "span")
|
268
270
|
end
|
269
271
|
end
|
270
272
|
|
@@ -301,6 +303,11 @@ module Sentry
|
|
301
303
|
profiler.start
|
302
304
|
end
|
303
305
|
|
306
|
+
# These are high cardinality and thus bad
|
307
|
+
def source_low_quality?
|
308
|
+
source == :url
|
309
|
+
end
|
310
|
+
|
304
311
|
protected
|
305
312
|
|
306
313
|
def init_span_recorder(limit = 1000)
|
@@ -336,11 +343,6 @@ module Sentry
|
|
336
343
|
@baggage = Baggage.new(items, mutable: false)
|
337
344
|
end
|
338
345
|
|
339
|
-
# These are high cardinality and thus bad
|
340
|
-
def source_low_quality?
|
341
|
-
source == :url
|
342
|
-
end
|
343
|
-
|
344
346
|
class SpanRecorder
|
345
347
|
attr_reader :max_length, :spans
|
346
348
|
|
@@ -17,6 +17,9 @@ module Sentry
|
|
17
17
|
# @return [Hash, nil]
|
18
18
|
attr_accessor :profile
|
19
19
|
|
20
|
+
# @return [Hash, nil]
|
21
|
+
attr_accessor :metrics_summary
|
22
|
+
|
20
23
|
def initialize(transaction:, **options)
|
21
24
|
super(**options)
|
22
25
|
|
@@ -29,6 +32,7 @@ module Sentry
|
|
29
32
|
self.tags = transaction.tags
|
30
33
|
self.dynamic_sampling_context = transaction.get_baggage.dynamic_sampling_context
|
31
34
|
self.measurements = transaction.measurements
|
35
|
+
self.metrics_summary = transaction.metrics_summary
|
32
36
|
|
33
37
|
finished_spans = transaction.span_recorder.spans.select { |span| span.timestamp && span != transaction }
|
34
38
|
self.spans = finished_spans.map(&:to_hash)
|
@@ -49,6 +53,7 @@ module Sentry
|
|
49
53
|
data[:spans] = @spans.map(&:to_hash) if @spans
|
50
54
|
data[:start_timestamp] = @start_timestamp
|
51
55
|
data[:measurements] = @measurements
|
56
|
+
data[:_metrics_summary] = @metrics_summary if @metrics_summary
|
52
57
|
data
|
53
58
|
end
|
54
59
|
|
@@ -69,8 +74,7 @@ module Sentry
|
|
69
74
|
id: event_id,
|
70
75
|
name: transaction.name,
|
71
76
|
trace_id: transaction.trace_id,
|
72
|
-
|
73
|
-
active_thead_id: '0'
|
77
|
+
active_thread_id: transaction.profiler.active_thread_id.to_s
|
74
78
|
}
|
75
79
|
)
|
76
80
|
|