sentry-ruby 4.1.2 → 4.1.5
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/README.md +9 -7
- metadata +21 -57
- data/.craft.yml +0 -19
- data/.gitignore +0 -11
- data/.rspec +0 -3
- data/.travis.yml +0 -6
- data/CHANGELOG.md +0 -102
- data/CODE_OF_CONDUCT.md +0 -74
- data/Gemfile +0 -16
- data/Rakefile +0 -8
- data/bin/console +0 -14
- data/bin/setup +0 -8
- data/lib/sentry-ruby.rb +0 -152
- data/lib/sentry/background_worker.rb +0 -37
- data/lib/sentry/backtrace.rb +0 -128
- data/lib/sentry/benchmarks/benchmark_transport.rb +0 -14
- data/lib/sentry/breadcrumb.rb +0 -25
- data/lib/sentry/breadcrumb/sentry_logger.rb +0 -87
- data/lib/sentry/breadcrumb_buffer.rb +0 -47
- data/lib/sentry/client.rb +0 -90
- data/lib/sentry/configuration.rb +0 -399
- data/lib/sentry/core_ext/object/deep_dup.rb +0 -57
- data/lib/sentry/core_ext/object/duplicable.rb +0 -153
- data/lib/sentry/dsn.rb +0 -48
- data/lib/sentry/event.rb +0 -177
- data/lib/sentry/hub.rb +0 -137
- data/lib/sentry/integrable.rb +0 -24
- data/lib/sentry/interface.rb +0 -22
- data/lib/sentry/interfaces/exception.rb +0 -11
- data/lib/sentry/interfaces/request.rb +0 -74
- data/lib/sentry/interfaces/single_exception.rb +0 -14
- data/lib/sentry/interfaces/stacktrace.rb +0 -57
- data/lib/sentry/linecache.rb +0 -44
- data/lib/sentry/logger.rb +0 -20
- data/lib/sentry/rack.rb +0 -5
- data/lib/sentry/rack/capture_exceptions.rb +0 -62
- data/lib/sentry/rack/deprecations.rb +0 -19
- data/lib/sentry/rack/interface.rb +0 -22
- data/lib/sentry/rake.rb +0 -17
- data/lib/sentry/scope.rb +0 -214
- data/lib/sentry/span.rb +0 -132
- data/lib/sentry/transaction.rb +0 -157
- data/lib/sentry/transaction_event.rb +0 -29
- data/lib/sentry/transport.rb +0 -88
- data/lib/sentry/transport/configuration.rb +0 -21
- data/lib/sentry/transport/dummy_transport.rb +0 -14
- data/lib/sentry/transport/http_transport.rb +0 -62
- data/lib/sentry/utils/exception_cause_chain.rb +0 -20
- data/lib/sentry/utils/real_ip.rb +0 -70
- data/lib/sentry/utils/request_id.rb +0 -16
- data/lib/sentry/version.rb +0 -3
- data/sentry-ruby.gemspec +0 -27
data/lib/sentry/span.rb
DELETED
@@ -1,132 +0,0 @@
|
|
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
|
data/lib/sentry/transaction.rb
DELETED
@@ -1,157 +0,0 @@
|
|
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
|
@@ -1,29 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Sentry
|
4
|
-
class TransactionEvent < Event
|
5
|
-
ATTRIBUTES = %i(
|
6
|
-
event_id level timestamp start_timestamp
|
7
|
-
release environment server_name modules
|
8
|
-
user tags contexts extra
|
9
|
-
transaction platform sdk type
|
10
|
-
)
|
11
|
-
|
12
|
-
attr_accessor(*ATTRIBUTES)
|
13
|
-
attr_accessor :spans
|
14
|
-
|
15
|
-
def start_timestamp=(time)
|
16
|
-
@start_timestamp = time.is_a?(Time) ? time.to_f : time
|
17
|
-
end
|
18
|
-
|
19
|
-
def type
|
20
|
-
"transaction"
|
21
|
-
end
|
22
|
-
|
23
|
-
def to_hash
|
24
|
-
data = super
|
25
|
-
data[:spans] = @spans.map(&:to_hash) if @spans
|
26
|
-
data
|
27
|
-
end
|
28
|
-
end
|
29
|
-
end
|
data/lib/sentry/transport.rb
DELETED
@@ -1,88 +0,0 @@
|
|
1
|
-
require "json"
|
2
|
-
require "base64"
|
3
|
-
|
4
|
-
module Sentry
|
5
|
-
class Transport
|
6
|
-
PROTOCOL_VERSION = '5'
|
7
|
-
USER_AGENT = "sentry-ruby/#{Sentry::VERSION}"
|
8
|
-
|
9
|
-
attr_accessor :configuration
|
10
|
-
|
11
|
-
def initialize(configuration)
|
12
|
-
@configuration = configuration
|
13
|
-
@transport_configuration = configuration.transport
|
14
|
-
@dsn = configuration.dsn
|
15
|
-
end
|
16
|
-
|
17
|
-
def send_data(data, options = {})
|
18
|
-
raise NotImplementedError
|
19
|
-
end
|
20
|
-
|
21
|
-
def send_event(event)
|
22
|
-
unless configuration.sending_allowed?
|
23
|
-
configuration.logger.debug(LOGGER_PROGNAME) { "Event not sent: #{configuration.error_messages}" }
|
24
|
-
return
|
25
|
-
end
|
26
|
-
|
27
|
-
encoded_data = prepare_encoded_event(event)
|
28
|
-
|
29
|
-
return nil unless encoded_data
|
30
|
-
|
31
|
-
send_data(encoded_data)
|
32
|
-
|
33
|
-
event
|
34
|
-
rescue => e
|
35
|
-
failed_for_exception(e, event)
|
36
|
-
nil
|
37
|
-
end
|
38
|
-
|
39
|
-
def generate_auth_header
|
40
|
-
now = Sentry.utc_now.to_i
|
41
|
-
fields = {
|
42
|
-
'sentry_version' => PROTOCOL_VERSION,
|
43
|
-
'sentry_client' => USER_AGENT,
|
44
|
-
'sentry_timestamp' => now,
|
45
|
-
'sentry_key' => @dsn.public_key
|
46
|
-
}
|
47
|
-
fields['sentry_secret'] = @dsn.secret_key if @dsn.secret_key
|
48
|
-
'Sentry ' + fields.map { |key, value| "#{key}=#{value}" }.join(', ')
|
49
|
-
end
|
50
|
-
|
51
|
-
def encode(event_hash)
|
52
|
-
event_id = event_hash[:event_id] || event_hash['event_id']
|
53
|
-
event_type = event_hash[:type] || event_hash['type']
|
54
|
-
|
55
|
-
envelope = <<~ENVELOPE
|
56
|
-
{"event_id":"#{event_id}","dsn":"#{configuration.dsn.to_s}","sdk":#{Sentry.sdk_meta.to_json},"sent_at":"#{Sentry.utc_now.iso8601}"}
|
57
|
-
{"type":"#{event_type}","content_type":"application/json"}
|
58
|
-
#{JSON.generate(event_hash)}
|
59
|
-
ENVELOPE
|
60
|
-
|
61
|
-
envelope
|
62
|
-
end
|
63
|
-
|
64
|
-
private
|
65
|
-
|
66
|
-
def prepare_encoded_event(event)
|
67
|
-
# Convert to hash
|
68
|
-
event_hash = event.to_hash
|
69
|
-
|
70
|
-
event_id = event_hash[:event_id] || event_hash["event_id"]
|
71
|
-
event_type = event_hash[:type] || event_hash["type"]
|
72
|
-
configuration.logger.info(LOGGER_PROGNAME) { "Sending #{event_type} #{event_id} to Sentry" }
|
73
|
-
encode(event_hash)
|
74
|
-
end
|
75
|
-
|
76
|
-
def failed_for_exception(e, event)
|
77
|
-
configuration.logger.warn(LOGGER_PROGNAME) { "Unable to record event with remote Sentry server (#{e.class} - #{e.message}):\n#{e.backtrace[0..10].join("\n")}" }
|
78
|
-
log_not_sending(event)
|
79
|
-
end
|
80
|
-
|
81
|
-
def log_not_sending(event)
|
82
|
-
configuration.logger.warn(LOGGER_PROGNAME) { "Failed to submit event. Unreported Event: #{Event.get_log_message(event.to_hash)}" }
|
83
|
-
end
|
84
|
-
end
|
85
|
-
end
|
86
|
-
|
87
|
-
require "sentry/transport/dummy_transport"
|
88
|
-
require "sentry/transport/http_transport"
|
@@ -1,21 +0,0 @@
|
|
1
|
-
module Sentry
|
2
|
-
class Transport
|
3
|
-
class Configuration
|
4
|
-
attr_accessor :timeout, :open_timeout, :proxy, :ssl, :ssl_ca_file, :ssl_verification, :http_adapter, :faraday_builder, :transport_class
|
5
|
-
|
6
|
-
def initialize
|
7
|
-
@ssl_verification = true
|
8
|
-
@open_timeout = 1
|
9
|
-
@timeout = 2
|
10
|
-
end
|
11
|
-
|
12
|
-
def transport_class=(klass)
|
13
|
-
unless klass.is_a?(Class)
|
14
|
-
raise Sentry::Error.new("config.transport.transport_class must a class. got: #{klass.class}")
|
15
|
-
end
|
16
|
-
|
17
|
-
@transport_class = klass
|
18
|
-
end
|
19
|
-
end
|
20
|
-
end
|
21
|
-
end
|
@@ -1,62 +0,0 @@
|
|
1
|
-
require 'faraday'
|
2
|
-
|
3
|
-
module Sentry
|
4
|
-
class HTTPTransport < Transport
|
5
|
-
CONTENT_TYPE = 'application/json'
|
6
|
-
attr_reader :conn, :adapter
|
7
|
-
|
8
|
-
def initialize(*args)
|
9
|
-
super
|
10
|
-
@adapter = @transport_configuration.http_adapter || Faraday.default_adapter
|
11
|
-
@conn = set_conn
|
12
|
-
@endpoint = @dsn.envelope_endpoint
|
13
|
-
end
|
14
|
-
|
15
|
-
def send_data(data)
|
16
|
-
conn.post @endpoint do |req|
|
17
|
-
req.headers['Content-Type'] = CONTENT_TYPE
|
18
|
-
req.headers['X-Sentry-Auth'] = generate_auth_header
|
19
|
-
req.body = data
|
20
|
-
end
|
21
|
-
rescue Faraday::Error => e
|
22
|
-
error_info = e.message
|
23
|
-
|
24
|
-
if e.response
|
25
|
-
error_info += "\nbody: #{e.response[:body]}"
|
26
|
-
error_info += " Error in headers is: #{e.response[:headers]['x-sentry-error']}" if e.response[:headers]['x-sentry-error']
|
27
|
-
end
|
28
|
-
|
29
|
-
raise Sentry::Error, error_info
|
30
|
-
end
|
31
|
-
|
32
|
-
private
|
33
|
-
|
34
|
-
def set_conn
|
35
|
-
server = @dsn.server
|
36
|
-
|
37
|
-
configuration.logger.debug(LOGGER_PROGNAME) { "Sentry HTTP Transport connecting to #{server}" }
|
38
|
-
|
39
|
-
Faraday.new(server, :ssl => ssl_configuration, :proxy => @transport_configuration.proxy) do |builder|
|
40
|
-
@transport_configuration.faraday_builder&.call(builder)
|
41
|
-
builder.response :raise_error
|
42
|
-
builder.options.merge! faraday_opts
|
43
|
-
builder.headers[:user_agent] = "sentry-ruby/#{Sentry::VERSION}"
|
44
|
-
builder.adapter(*adapter)
|
45
|
-
end
|
46
|
-
end
|
47
|
-
|
48
|
-
# TODO: deprecate and replace where possible w/Faraday Builder
|
49
|
-
def faraday_opts
|
50
|
-
[:timeout, :open_timeout].each_with_object({}) do |opt, memo|
|
51
|
-
memo[opt] = @transport_configuration.public_send(opt) if @transport_configuration.public_send(opt)
|
52
|
-
end
|
53
|
-
end
|
54
|
-
|
55
|
-
def ssl_configuration
|
56
|
-
(@transport_configuration.ssl || {}).merge(
|
57
|
-
:verify => @transport_configuration.ssl_verification,
|
58
|
-
:ca_file => @transport_configuration.ssl_ca_file
|
59
|
-
)
|
60
|
-
end
|
61
|
-
end
|
62
|
-
end
|