sentry-ruby 0.1.3 → 4.1.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/CHANGELOG.md +69 -0
- data/Gemfile +6 -1
- data/README.md +88 -8
- data/Rakefile +3 -1
- data/lib/sentry-ruby.rb +38 -3
- data/lib/sentry/background_worker.rb +37 -0
- data/lib/sentry/benchmarks/benchmark_transport.rb +14 -0
- data/lib/sentry/breadcrumb.rb +7 -7
- data/lib/sentry/breadcrumb/sentry_logger.rb +10 -26
- data/lib/sentry/breadcrumb_buffer.rb +2 -5
- data/lib/sentry/client.rb +25 -7
- data/lib/sentry/configuration.rb +88 -87
- data/lib/sentry/dsn.rb +6 -3
- data/lib/sentry/event.rb +32 -26
- data/lib/sentry/hub.rb +13 -2
- data/lib/sentry/interfaces/request.rb +1 -31
- data/lib/sentry/rack.rb +2 -2
- data/lib/sentry/rack/{capture_exception.rb → capture_exceptions.rb} +20 -11
- data/lib/sentry/rack/interface.rb +22 -0
- data/lib/sentry/rake.rb +17 -0
- data/lib/sentry/scope.rb +27 -5
- data/lib/sentry/span.rb +132 -0
- data/lib/sentry/transaction.rb +157 -0
- data/lib/sentry/transaction_event.rb +29 -0
- data/lib/sentry/transport.rb +16 -24
- data/lib/sentry/transport/http_transport.rb +8 -8
- data/lib/sentry/utils/request_id.rb +16 -0
- data/lib/sentry/version.rb +1 -1
- data/sentry-ruby.gemspec +1 -0
- metadata +25 -4
- data/lib/sentry/transport/state.rb +0 -40
data/lib/sentry/hub.rb
CHANGED
@@ -67,6 +67,12 @@ module Sentry
|
|
67
67
|
@stack.pop
|
68
68
|
end
|
69
69
|
|
70
|
+
def start_transaction(transaction: nil, **options)
|
71
|
+
transaction ||= Transaction.new(**options)
|
72
|
+
transaction.set_initial_sample_desicion
|
73
|
+
transaction
|
74
|
+
end
|
75
|
+
|
70
76
|
def capture_exception(exception, **options, &block)
|
71
77
|
return unless current_client
|
72
78
|
|
@@ -74,12 +80,16 @@ module Sentry
|
|
74
80
|
|
75
81
|
return unless event
|
76
82
|
|
83
|
+
options[:hint] ||= {}
|
84
|
+
options[:hint] = options[:hint].merge(exception: exception)
|
77
85
|
capture_event(event, **options, &block)
|
78
86
|
end
|
79
87
|
|
80
88
|
def capture_message(message, **options, &block)
|
81
89
|
return unless current_client
|
82
90
|
|
91
|
+
options[:hint] ||= {}
|
92
|
+
options[:hint] = options[:hint].merge(message: message)
|
83
93
|
event = current_client.event_from_message(message)
|
84
94
|
capture_event(event, **options, &block)
|
85
95
|
end
|
@@ -87,6 +97,7 @@ module Sentry
|
|
87
97
|
def capture_event(event, **options, &block)
|
88
98
|
return unless current_client
|
89
99
|
|
100
|
+
hint = options.delete(:hint) || {}
|
90
101
|
scope = current_scope.dup
|
91
102
|
|
92
103
|
if block
|
@@ -97,9 +108,9 @@ module Sentry
|
|
97
108
|
scope.update_from_options(**options)
|
98
109
|
end
|
99
110
|
|
100
|
-
event = current_client.capture_event(event, scope)
|
111
|
+
event = current_client.capture_event(event, scope, hint)
|
101
112
|
|
102
|
-
@last_event_id = event.
|
113
|
+
@last_event_id = event.event_id
|
103
114
|
event
|
104
115
|
end
|
105
116
|
|
@@ -1,5 +1,3 @@
|
|
1
|
-
require 'rack'
|
2
|
-
|
3
1
|
module Sentry
|
4
2
|
class RequestInterface < Interface
|
5
3
|
REQUEST_ID_HEADERS = %w(action_dispatch.request_id HTTP_X_REQUEST_ID).freeze
|
@@ -18,36 +16,8 @@ module Sentry
|
|
18
16
|
self.cookies = nil
|
19
17
|
end
|
20
18
|
|
21
|
-
def from_rack(env_hash)
|
22
|
-
req = ::Rack::Request.new(env_hash)
|
23
|
-
|
24
|
-
if Sentry.configuration.send_default_pii
|
25
|
-
self.data = read_data_from(req)
|
26
|
-
self.cookies = req.cookies
|
27
|
-
else
|
28
|
-
# need to completely wipe out ip addresses
|
29
|
-
IP_HEADERS.each { |h| env_hash.delete(h) }
|
30
|
-
end
|
31
|
-
|
32
|
-
self.url = req.scheme && req.url.split('?').first
|
33
|
-
self.method = req.request_method
|
34
|
-
self.query_string = req.query_string
|
35
|
-
|
36
|
-
self.headers = format_headers_for_sentry(env_hash)
|
37
|
-
self.env = format_env_for_sentry(env_hash)
|
38
|
-
end
|
39
|
-
|
40
19
|
private
|
41
20
|
|
42
|
-
# Request ID based on ActionDispatch::RequestId
|
43
|
-
def read_request_id_from(env_hash)
|
44
|
-
REQUEST_ID_HEADERS.each do |key|
|
45
|
-
request_id = env_hash[key]
|
46
|
-
return request_id if request_id
|
47
|
-
end
|
48
|
-
nil
|
49
|
-
end
|
50
|
-
|
51
21
|
# See Sentry server default limits at
|
52
22
|
# https://github.com/getsentry/sentry/blob/master/src/sentry/conf/server.py
|
53
23
|
def read_data_from(request)
|
@@ -67,7 +37,7 @@ module Sentry
|
|
67
37
|
begin
|
68
38
|
key = key.to_s # rack env can contain symbols
|
69
39
|
value = value.to_s
|
70
|
-
next memo['X-Request-Id'] ||=
|
40
|
+
next memo['X-Request-Id'] ||= Utils::RequestId.read_from(env_hash) if Utils::RequestId::REQUEST_ID_HEADERS.include?(key)
|
71
41
|
next unless key.upcase == key # Non-upper case stuff isn't either
|
72
42
|
|
73
43
|
# Rack adds in an incorrect HTTP_VERSION key, which causes downstream
|
data/lib/sentry/rack.rb
CHANGED
@@ -1,45 +1,54 @@
|
|
1
1
|
module Sentry
|
2
2
|
module Rack
|
3
|
-
class
|
3
|
+
class CaptureExceptions
|
4
4
|
def initialize(app)
|
5
5
|
@app = app
|
6
6
|
end
|
7
7
|
|
8
8
|
def call(env)
|
9
|
-
|
10
|
-
|
11
|
-
#
|
12
|
-
Sentry.clone_hub_to_current_thread
|
13
|
-
|
14
|
-
# it's essential for multi-process servers (e.g. unicorn)
|
9
|
+
return @app.call(env) unless Sentry.initialized?
|
10
|
+
|
11
|
+
# make sure the current thread has a clean hub
|
12
|
+
Sentry.clone_hub_to_current_thread
|
13
|
+
|
15
14
|
Sentry.with_scope do |scope|
|
16
|
-
# there could be some breadcrumbs already stored in the top-level scope
|
17
|
-
# and for request information, we don't need those breadcrumbs
|
18
15
|
scope.clear_breadcrumbs
|
19
|
-
env['sentry.client'] = Sentry.get_current_client
|
20
|
-
|
21
16
|
scope.set_transaction_name(env["PATH_INFO"]) if env["PATH_INFO"]
|
22
17
|
scope.set_rack_env(env)
|
23
18
|
|
19
|
+
span = Sentry.start_transaction(name: scope.transaction_name, op: "rack.request")
|
20
|
+
scope.set_span(span)
|
21
|
+
|
24
22
|
begin
|
25
23
|
response = @app.call(env)
|
26
24
|
rescue Sentry::Error
|
25
|
+
finish_span(span, 500)
|
27
26
|
raise # Don't capture Sentry errors
|
28
27
|
rescue Exception => e
|
29
28
|
Sentry.capture_exception(e)
|
29
|
+
finish_span(span, 500)
|
30
30
|
raise
|
31
31
|
end
|
32
32
|
|
33
33
|
exception = collect_exception(env)
|
34
34
|
Sentry.capture_exception(exception) if exception
|
35
35
|
|
36
|
+
finish_span(span, response[0])
|
37
|
+
|
36
38
|
response
|
37
39
|
end
|
38
40
|
end
|
39
41
|
|
42
|
+
private
|
43
|
+
|
40
44
|
def collect_exception(env)
|
41
45
|
env['rack.exception'] || env['sinatra.error']
|
42
46
|
end
|
47
|
+
|
48
|
+
def finish_span(span, status_code)
|
49
|
+
span.set_http_status(status_code)
|
50
|
+
span.finish
|
51
|
+
end
|
43
52
|
end
|
44
53
|
end
|
45
54
|
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
module Sentry
|
2
|
+
class RequestInterface
|
3
|
+
def from_rack(env_hash)
|
4
|
+
req = ::Rack::Request.new(env_hash)
|
5
|
+
|
6
|
+
if Sentry.configuration.send_default_pii
|
7
|
+
self.data = read_data_from(req)
|
8
|
+
self.cookies = req.cookies
|
9
|
+
else
|
10
|
+
# need to completely wipe out ip addresses
|
11
|
+
IP_HEADERS.each { |h| env_hash.delete(h) }
|
12
|
+
end
|
13
|
+
|
14
|
+
self.url = req.scheme && req.url.split('?').first
|
15
|
+
self.method = req.request_method
|
16
|
+
self.query_string = req.query_string
|
17
|
+
|
18
|
+
self.headers = format_headers_for_sentry(env_hash)
|
19
|
+
self.env = format_env_for_sentry(env_hash)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
data/lib/sentry/rake.rb
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
require "rake"
|
2
|
+
require "rake/task"
|
3
|
+
|
4
|
+
module Rake
|
5
|
+
class Application
|
6
|
+
alias orig_display_error_messsage display_error_message
|
7
|
+
def display_error_message(ex)
|
8
|
+
Sentry.capture_exception(ex, hint: { background: false }) do |scope|
|
9
|
+
task_name = top_level_tasks.join(' ')
|
10
|
+
scope.set_transaction_name(task_name)
|
11
|
+
scope.set_tag("rake_task", task_name)
|
12
|
+
end if Sentry.initialized?
|
13
|
+
|
14
|
+
orig_display_error_messsage(ex)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
data/lib/sentry/scope.rb
CHANGED
@@ -3,7 +3,7 @@ require "etc"
|
|
3
3
|
|
4
4
|
module Sentry
|
5
5
|
class Scope
|
6
|
-
ATTRIBUTES = [:transaction_names, :contexts, :extra, :tags, :user, :level, :breadcrumbs, :fingerprint, :event_processors, :rack_env]
|
6
|
+
ATTRIBUTES = [:transaction_names, :contexts, :extra, :tags, :user, :level, :breadcrumbs, :fingerprint, :event_processors, :rack_env, :span]
|
7
7
|
|
8
8
|
attr_reader(*ATTRIBUTES)
|
9
9
|
|
@@ -15,20 +15,25 @@ module Sentry
|
|
15
15
|
set_default_value
|
16
16
|
end
|
17
17
|
|
18
|
-
def apply_to_event(event)
|
18
|
+
def apply_to_event(event, hint = nil)
|
19
19
|
event.tags = tags.merge(event.tags)
|
20
20
|
event.user = user.merge(event.user)
|
21
21
|
event.extra = extra.merge(event.extra)
|
22
22
|
event.contexts = contexts.merge(event.contexts)
|
23
|
+
|
24
|
+
if span
|
25
|
+
event.contexts[:trace] = span.get_trace_context
|
26
|
+
end
|
27
|
+
|
23
28
|
event.fingerprint = fingerprint
|
24
|
-
event.level
|
29
|
+
event.level = level
|
25
30
|
event.transaction = transaction_names.last
|
26
31
|
event.breadcrumbs = breadcrumbs
|
27
|
-
event.rack_env = rack_env
|
32
|
+
event.rack_env = rack_env if rack_env
|
28
33
|
|
29
34
|
unless @event_processors.empty?
|
30
35
|
@event_processors.each do |processor_block|
|
31
|
-
event = processor_block.call(event)
|
36
|
+
event = processor_block.call(event, hint)
|
32
37
|
end
|
33
38
|
end
|
34
39
|
|
@@ -52,6 +57,7 @@ module Sentry
|
|
52
57
|
copy.user = user.deep_dup
|
53
58
|
copy.transaction_names = transaction_names.deep_dup
|
54
59
|
copy.fingerprint = fingerprint.deep_dup
|
60
|
+
copy.span = span.deep_dup
|
55
61
|
copy
|
56
62
|
end
|
57
63
|
|
@@ -63,6 +69,7 @@ module Sentry
|
|
63
69
|
self.user = scope.user
|
64
70
|
self.transaction_names = scope.transaction_names
|
65
71
|
self.fingerprint = scope.fingerprint
|
72
|
+
self.span = scope.span
|
66
73
|
end
|
67
74
|
|
68
75
|
def update_from_options(
|
@@ -86,6 +93,11 @@ module Sentry
|
|
86
93
|
@rack_env = env
|
87
94
|
end
|
88
95
|
|
96
|
+
def set_span(span)
|
97
|
+
check_argument_type!(span, Span)
|
98
|
+
@span = span
|
99
|
+
end
|
100
|
+
|
89
101
|
def set_user(user_hash)
|
90
102
|
check_argument_type!(user_hash, Hash)
|
91
103
|
@user = user_hash
|
@@ -130,6 +142,15 @@ module Sentry
|
|
130
142
|
@transaction_names.last
|
131
143
|
end
|
132
144
|
|
145
|
+
def get_transaction
|
146
|
+
# transaction will always be the first in the span_recorder
|
147
|
+
span.span_recorder.spans.first if span
|
148
|
+
end
|
149
|
+
|
150
|
+
def get_span
|
151
|
+
span
|
152
|
+
end
|
153
|
+
|
133
154
|
def set_fingerprint(fingerprint)
|
134
155
|
check_argument_type!(fingerprint, Array)
|
135
156
|
|
@@ -164,6 +185,7 @@ module Sentry
|
|
164
185
|
@transaction_names = []
|
165
186
|
@event_processors = []
|
166
187
|
@rack_env = {}
|
188
|
+
@span = nil
|
167
189
|
end
|
168
190
|
|
169
191
|
class << self
|
data/lib/sentry/span.rb
ADDED
@@ -0,0 +1,132 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
require "securerandom"
|
3
|
+
|
4
|
+
module Sentry
|
5
|
+
class Span
|
6
|
+
STATUS_MAP = {
|
7
|
+
400 => "invalid_argument",
|
8
|
+
401 => "unauthenticated",
|
9
|
+
403 => "permission_denied",
|
10
|
+
404 => "not_found",
|
11
|
+
409 => "already_exists",
|
12
|
+
429 => "resource_exhausted",
|
13
|
+
499 => "cancelled",
|
14
|
+
500 => "internal_error",
|
15
|
+
501 => "unimplemented",
|
16
|
+
503 => "unavailable",
|
17
|
+
504 => "deadline_exceeded"
|
18
|
+
}
|
19
|
+
|
20
|
+
|
21
|
+
attr_reader :trace_id, :span_id, :parent_span_id, :sampled, :start_timestamp, :timestamp, :description, :op, :status, :tags, :data
|
22
|
+
attr_accessor :span_recorder
|
23
|
+
|
24
|
+
def initialize(description: nil, op: nil, status: nil, trace_id: nil, parent_span_id: nil, sampled: nil, start_timestamp: nil, timestamp: nil)
|
25
|
+
@trace_id = trace_id || SecureRandom.uuid.delete("-")
|
26
|
+
@span_id = SecureRandom.hex(8)
|
27
|
+
@parent_span_id = parent_span_id
|
28
|
+
@sampled = sampled
|
29
|
+
@start_timestamp = start_timestamp || Sentry.utc_now.to_f
|
30
|
+
@timestamp = timestamp
|
31
|
+
@description = description
|
32
|
+
@op = op
|
33
|
+
@status = status
|
34
|
+
@data = {}
|
35
|
+
@tags = {}
|
36
|
+
end
|
37
|
+
|
38
|
+
def finish
|
39
|
+
# already finished
|
40
|
+
return if @timestamp
|
41
|
+
|
42
|
+
@timestamp = Sentry.utc_now.to_f
|
43
|
+
self
|
44
|
+
end
|
45
|
+
|
46
|
+
def to_sentry_trace
|
47
|
+
sampled_flag = ""
|
48
|
+
sampled_flag = @sampled ? 1 : 0 unless @sampled.nil?
|
49
|
+
|
50
|
+
"#{@trace_id}-#{@span_id}-#{sampled_flag}"
|
51
|
+
end
|
52
|
+
|
53
|
+
def to_hash
|
54
|
+
{
|
55
|
+
trace_id: @trace_id,
|
56
|
+
span_id: @span_id,
|
57
|
+
parent_span_id: @parent_span_id,
|
58
|
+
start_timestamp: @start_timestamp,
|
59
|
+
timestamp: @timestamp,
|
60
|
+
description: @description,
|
61
|
+
op: @op,
|
62
|
+
status: @status,
|
63
|
+
tags: @tags,
|
64
|
+
data: @data
|
65
|
+
}
|
66
|
+
end
|
67
|
+
|
68
|
+
def get_trace_context
|
69
|
+
{
|
70
|
+
trace_id: @trace_id,
|
71
|
+
span_id: @span_id,
|
72
|
+
description: @description,
|
73
|
+
op: @op,
|
74
|
+
status: @status
|
75
|
+
}
|
76
|
+
end
|
77
|
+
|
78
|
+
def start_child(**options)
|
79
|
+
options = options.dup.merge(trace_id: @trace_id, parent_span_id: @span_id, sampled: @sampled)
|
80
|
+
Span.new(options)
|
81
|
+
end
|
82
|
+
|
83
|
+
def with_child_span(**options, &block)
|
84
|
+
child_span = start_child(**options)
|
85
|
+
|
86
|
+
yield(child_span)
|
87
|
+
|
88
|
+
child_span.finish
|
89
|
+
end
|
90
|
+
|
91
|
+
def deep_dup
|
92
|
+
dup
|
93
|
+
end
|
94
|
+
|
95
|
+
def set_op(op)
|
96
|
+
@op = op
|
97
|
+
end
|
98
|
+
|
99
|
+
def set_description(description)
|
100
|
+
@description = description
|
101
|
+
end
|
102
|
+
|
103
|
+
def set_status(status)
|
104
|
+
@status = status
|
105
|
+
end
|
106
|
+
|
107
|
+
def set_timestamp(timestamp)
|
108
|
+
@timestamp = timestamp
|
109
|
+
end
|
110
|
+
|
111
|
+
def set_http_status(status_code)
|
112
|
+
status_code = status_code.to_i
|
113
|
+
set_data("status_code", status_code)
|
114
|
+
|
115
|
+
status =
|
116
|
+
if status_code >= 200 && status_code < 299
|
117
|
+
"ok"
|
118
|
+
else
|
119
|
+
STATUS_MAP[status_code]
|
120
|
+
end
|
121
|
+
set_status(status)
|
122
|
+
end
|
123
|
+
|
124
|
+
def set_data(key, value)
|
125
|
+
@data[key] = value
|
126
|
+
end
|
127
|
+
|
128
|
+
def set_tag(key, value)
|
129
|
+
@tags[key] = value
|
130
|
+
end
|
131
|
+
end
|
132
|
+
end
|
@@ -0,0 +1,157 @@
|
|
1
|
+
module Sentry
|
2
|
+
class Transaction < Span
|
3
|
+
SENTRY_TRACE_REGEXP = Regexp.new(
|
4
|
+
"^[ \t]*" + # whitespace
|
5
|
+
"([0-9a-f]{32})?" + # trace_id
|
6
|
+
"-?([0-9a-f]{16})?" + # span_id
|
7
|
+
"-?([01])?" + # sampled
|
8
|
+
"[ \t]*$" # whitespace
|
9
|
+
)
|
10
|
+
UNLABELD_NAME = "<unlabeled transaction>".freeze
|
11
|
+
MESSAGE_PREFIX = "[Tracing]"
|
12
|
+
|
13
|
+
attr_reader :name, :parent_sampled
|
14
|
+
|
15
|
+
def initialize(name: nil, parent_sampled: nil, **options)
|
16
|
+
super(**options)
|
17
|
+
|
18
|
+
@name = name
|
19
|
+
@parent_sampled = parent_sampled
|
20
|
+
set_span_recorder
|
21
|
+
end
|
22
|
+
|
23
|
+
def set_span_recorder
|
24
|
+
@span_recorder = SpanRecorder.new(1000)
|
25
|
+
@span_recorder.add(self)
|
26
|
+
end
|
27
|
+
|
28
|
+
def self.from_sentry_trace(sentry_trace, **options)
|
29
|
+
return unless sentry_trace
|
30
|
+
|
31
|
+
match = SENTRY_TRACE_REGEXP.match(sentry_trace)
|
32
|
+
trace_id, parent_span_id, sampled_flag = match[1..3]
|
33
|
+
|
34
|
+
sampled = sampled_flag != "0"
|
35
|
+
|
36
|
+
new(trace_id: trace_id, parent_span_id: parent_span_id, parent_sampled: sampled, **options)
|
37
|
+
end
|
38
|
+
|
39
|
+
def to_hash
|
40
|
+
hash = super
|
41
|
+
hash.merge!(name: @name, sampled: @sampled, parent_sampled: @parent_sampled)
|
42
|
+
hash
|
43
|
+
end
|
44
|
+
|
45
|
+
def start_child(**options)
|
46
|
+
child_span = super
|
47
|
+
child_span.span_recorder = @span_recorder
|
48
|
+
|
49
|
+
if @sampled
|
50
|
+
@span_recorder.add(child_span)
|
51
|
+
end
|
52
|
+
|
53
|
+
child_span
|
54
|
+
end
|
55
|
+
|
56
|
+
def deep_dup
|
57
|
+
copy = super
|
58
|
+
copy.set_span_recorder
|
59
|
+
|
60
|
+
@span_recorder.spans.each do |span|
|
61
|
+
# span_recorder's first span is the current span, which should not be added to the copy's spans
|
62
|
+
next if span == self
|
63
|
+
copy.span_recorder.add(span.dup)
|
64
|
+
end
|
65
|
+
|
66
|
+
copy
|
67
|
+
end
|
68
|
+
|
69
|
+
def set_initial_sample_desicion(sampling_context = {})
|
70
|
+
unless Sentry.configuration.tracing_enabled?
|
71
|
+
@sampled = false
|
72
|
+
return
|
73
|
+
end
|
74
|
+
|
75
|
+
return unless @sampled.nil?
|
76
|
+
|
77
|
+
transaction_description = generate_transaction_description
|
78
|
+
|
79
|
+
logger = Sentry.configuration.logger
|
80
|
+
sample_rate = Sentry.configuration.traces_sample_rate
|
81
|
+
traces_sampler = Sentry.configuration.traces_sampler
|
82
|
+
|
83
|
+
if traces_sampler.is_a?(Proc)
|
84
|
+
sampling_context = sampling_context.merge(
|
85
|
+
parent_sampled: @parent_sampled,
|
86
|
+
transaction_context: self.to_hash
|
87
|
+
)
|
88
|
+
|
89
|
+
sample_rate = traces_sampler.call(sampling_context)
|
90
|
+
end
|
91
|
+
|
92
|
+
unless [true, false].include?(sample_rate) || (sample_rate.is_a?(Float) && sample_rate >= 0.0 && sample_rate <= 1.0)
|
93
|
+
@sampled = false
|
94
|
+
logger.warn("#{MESSAGE_PREFIX} Discarding #{transaction_description} because of invalid sample_rate: #{sample_rate}")
|
95
|
+
return
|
96
|
+
end
|
97
|
+
|
98
|
+
if sample_rate == 0.0 || sample_rate == false
|
99
|
+
@sampled = false
|
100
|
+
logger.debug("#{MESSAGE_PREFIX} Discarding #{transaction_description} because traces_sampler returned 0 or false")
|
101
|
+
return
|
102
|
+
end
|
103
|
+
|
104
|
+
if sample_rate == true
|
105
|
+
@sampled = true
|
106
|
+
else
|
107
|
+
@sampled = Random.rand < sample_rate
|
108
|
+
end
|
109
|
+
|
110
|
+
if @sampled
|
111
|
+
logger.debug("#{MESSAGE_PREFIX} Starting #{transaction_description}")
|
112
|
+
else
|
113
|
+
logger.debug(
|
114
|
+
"#{MESSAGE_PREFIX} Discarding #{transaction_description} because it's not included in the random sample (sampling rate = #{sample_rate})"
|
115
|
+
)
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
def finish(hub: nil)
|
120
|
+
super() # Span#finish doesn't take arguments
|
121
|
+
|
122
|
+
if @name.nil?
|
123
|
+
@name = UNLABELD_NAME
|
124
|
+
end
|
125
|
+
|
126
|
+
return unless @sampled
|
127
|
+
|
128
|
+
hub ||= Sentry.get_current_hub
|
129
|
+
event = hub.current_client.event_from_transaction(self)
|
130
|
+
hub.capture_event(event)
|
131
|
+
end
|
132
|
+
|
133
|
+
private
|
134
|
+
|
135
|
+
def generate_transaction_description
|
136
|
+
result = op.nil? ? "" : "<#{@op}> "
|
137
|
+
result += "transaction"
|
138
|
+
result += " <#{@name}>" if @name
|
139
|
+
result
|
140
|
+
end
|
141
|
+
|
142
|
+
class SpanRecorder
|
143
|
+
attr_reader :max_length, :spans
|
144
|
+
|
145
|
+
def initialize(max_length)
|
146
|
+
@max_length = max_length
|
147
|
+
@spans = []
|
148
|
+
end
|
149
|
+
|
150
|
+
def add(span)
|
151
|
+
if @spans.count < @max_length
|
152
|
+
@spans << span
|
153
|
+
end
|
154
|
+
end
|
155
|
+
end
|
156
|
+
end
|
157
|
+
end
|