sentry-ruby-core 5.18.2 → 5.20.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 +1 -0
- data/lib/sentry/attachment.rb +40 -0
- data/lib/sentry/backtrace.rb +1 -3
- data/lib/sentry/baggage.rb +6 -6
- data/lib/sentry/breadcrumb/sentry_logger.rb +6 -6
- data/lib/sentry/check_in_event.rb +4 -4
- data/lib/sentry/client.rb +9 -9
- data/lib/sentry/configuration.rb +30 -18
- data/lib/sentry/core_ext/object/deep_dup.rb +1 -1
- data/lib/sentry/cron/monitor_check_ins.rb +1 -1
- data/lib/sentry/cron/monitor_config.rb +1 -1
- data/lib/sentry/dsn.rb +3 -3
- data/lib/sentry/envelope.rb +8 -8
- data/lib/sentry/event.rb +11 -7
- data/lib/sentry/faraday.rb +77 -0
- data/lib/sentry/graphql.rb +1 -1
- data/lib/sentry/hub.rb +8 -1
- data/lib/sentry/interfaces/mechanism.rb +1 -1
- data/lib/sentry/interfaces/request.rb +5 -5
- data/lib/sentry/interfaces/single_exception.rb +1 -1
- data/lib/sentry/interfaces/stacktrace.rb +3 -1
- data/lib/sentry/interfaces/stacktrace_builder.rb +15 -2
- data/lib/sentry/logger.rb +1 -1
- data/lib/sentry/metrics/aggregator.rb +12 -12
- data/lib/sentry/metrics/set_metric.rb +2 -2
- data/lib/sentry/metrics.rb +15 -15
- data/lib/sentry/net/http.rb +16 -38
- data/lib/sentry/profiler.rb +19 -20
- data/lib/sentry/propagation_context.rb +1 -1
- data/lib/sentry/rack/capture_exceptions.rb +1 -1
- data/lib/sentry/rack.rb +2 -2
- data/lib/sentry/rake.rb +2 -2
- data/lib/sentry/release_detector.rb +4 -4
- data/lib/sentry/scope.rb +15 -0
- data/lib/sentry/session_flusher.rb +1 -1
- data/lib/sentry/span.rb +8 -1
- data/lib/sentry/test_helper.rb +1 -1
- data/lib/sentry/transaction.rb +2 -2
- data/lib/sentry/transaction_event.rb +1 -1
- data/lib/sentry/transport/http_transport.rb +12 -12
- data/lib/sentry/transport.rb +10 -4
- data/lib/sentry/utils/env_helper.rb +21 -0
- data/lib/sentry/utils/http_tracing.rb +41 -0
- data/lib/sentry/utils/real_ip.rb +1 -1
- data/lib/sentry/version.rb +1 -1
- data/lib/sentry-ruby.rb +9 -1
- data/sentry-ruby.gemspec +1 -1
- metadata +9 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 58924eaaabcd9af00039a761dc76db3fdbfdad597ac5ec274cf5b09121706ffe
|
4
|
+
data.tar.gz: 931128e011f2b359bb00ff3a55e6924dc06cd083fb8944c278a2bac6186af767
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: b1a1aa47dcc33056a50e76faaee84a299093441a7994b9f377135a1a172a40f4c581a31ed553873c8ac960eff88d61303c22b98c07772590f36bedd4711b28be
|
7
|
+
data.tar.gz: 86ebfa52b4ddadeb7307985c4312b9ada2c0180be8ff65e2cf3af3eae3b6416403269642fdb4f502baa2f56ebd4e3f63b681e9e47de8b483db460d6f232d43ee
|
data/Gemfile
CHANGED
@@ -0,0 +1,40 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Sentry
|
4
|
+
class Attachment
|
5
|
+
PathNotFoundError = Class.new(StandardError)
|
6
|
+
|
7
|
+
attr_reader :bytes, :filename, :path, :content_type
|
8
|
+
|
9
|
+
def initialize(bytes: nil, filename: nil, content_type: nil, path: nil)
|
10
|
+
@bytes = bytes
|
11
|
+
@filename = filename || infer_filename(path)
|
12
|
+
@path = path
|
13
|
+
@content_type = content_type
|
14
|
+
end
|
15
|
+
|
16
|
+
def to_envelope_headers
|
17
|
+
{ type: "attachment", filename: filename, content_type: content_type, length: payload.bytesize }
|
18
|
+
end
|
19
|
+
|
20
|
+
def payload
|
21
|
+
@payload ||= if bytes
|
22
|
+
bytes
|
23
|
+
else
|
24
|
+
File.binread(path)
|
25
|
+
end
|
26
|
+
rescue Errno::ENOENT
|
27
|
+
raise PathNotFoundError, "Failed to read attachment file, file not found: #{path}"
|
28
|
+
end
|
29
|
+
|
30
|
+
private
|
31
|
+
|
32
|
+
def infer_filename(path)
|
33
|
+
if path
|
34
|
+
File.basename(path)
|
35
|
+
else
|
36
|
+
raise ArgumentError, "filename or path is required"
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
data/lib/sentry/backtrace.rb
CHANGED
@@ -80,8 +80,6 @@ module Sentry
|
|
80
80
|
end
|
81
81
|
end
|
82
82
|
|
83
|
-
APP_DIRS_PATTERN = /(bin|exe|app|config|lib|test|spec)/.freeze
|
84
|
-
|
85
83
|
# holder for an Array of Backtrace::Line instances
|
86
84
|
attr_reader :lines
|
87
85
|
|
@@ -91,7 +89,7 @@ module Sentry
|
|
91
89
|
ruby_lines = backtrace_cleanup_callback.call(ruby_lines) if backtrace_cleanup_callback
|
92
90
|
|
93
91
|
in_app_pattern ||= begin
|
94
|
-
Regexp.new("^(#{project_root}/)?#{app_dirs_pattern
|
92
|
+
Regexp.new("^(#{project_root}/)?#{app_dirs_pattern}")
|
95
93
|
end
|
96
94
|
|
97
95
|
lines = ruby_lines.to_a.map do |unparsed_line|
|
data/lib/sentry/baggage.rb
CHANGED
@@ -1,11 +1,11 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require
|
3
|
+
require "cgi"
|
4
4
|
|
5
5
|
module Sentry
|
6
6
|
# A {https://www.w3.org/TR/baggage W3C Baggage Header} implementation.
|
7
7
|
class Baggage
|
8
|
-
SENTRY_PREFIX =
|
8
|
+
SENTRY_PREFIX = "sentry-"
|
9
9
|
SENTRY_PREFIX_REGEX = /^sentry-/.freeze
|
10
10
|
|
11
11
|
# @return [Hash]
|
@@ -30,14 +30,14 @@ module Sentry
|
|
30
30
|
items = {}
|
31
31
|
mutable = true
|
32
32
|
|
33
|
-
header.split(
|
33
|
+
header.split(",").each do |item|
|
34
34
|
item = item.strip
|
35
|
-
key, val = item.split(
|
35
|
+
key, val = item.split("=")
|
36
36
|
|
37
37
|
next unless key && val
|
38
38
|
next unless key =~ SENTRY_PREFIX_REGEX
|
39
39
|
|
40
|
-
baggage_key = key.split(
|
40
|
+
baggage_key = key.split("-")[1]
|
41
41
|
next unless baggage_key
|
42
42
|
|
43
43
|
items[CGI.unescape(baggage_key)] = CGI.unescape(val)
|
@@ -64,7 +64,7 @@ module Sentry
|
|
64
64
|
# @return [String]
|
65
65
|
def serialize
|
66
66
|
items = @items.map { |k, v| "#{SENTRY_PREFIX}#{CGI.escape(k)}=#{CGI.escape(v)}" }
|
67
|
-
items.join(
|
67
|
+
items.join(",")
|
68
68
|
end
|
69
69
|
end
|
70
70
|
end
|
@@ -1,16 +1,16 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require
|
3
|
+
require "logger"
|
4
4
|
|
5
5
|
module Sentry
|
6
6
|
class Breadcrumb
|
7
7
|
module SentryLogger
|
8
8
|
LEVELS = {
|
9
|
-
::Logger::DEBUG =>
|
10
|
-
::Logger::INFO =>
|
11
|
-
::Logger::WARN =>
|
12
|
-
::Logger::ERROR =>
|
13
|
-
::Logger::FATAL =>
|
9
|
+
::Logger::DEBUG => "debug",
|
10
|
+
::Logger::INFO => "info",
|
11
|
+
::Logger::WARN => "warn",
|
12
|
+
::Logger::ERROR => "error",
|
13
|
+
::Logger::FATAL => "fatal"
|
14
14
|
}.freeze
|
15
15
|
|
16
16
|
def add(*args, &block)
|
@@ -1,11 +1,11 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require
|
4
|
-
require
|
3
|
+
require "securerandom"
|
4
|
+
require "sentry/cron/monitor_config"
|
5
5
|
|
6
6
|
module Sentry
|
7
7
|
class CheckInEvent < Event
|
8
|
-
TYPE =
|
8
|
+
TYPE = "check_in"
|
9
9
|
|
10
10
|
# uuid to identify this check-in.
|
11
11
|
# @return [String]
|
@@ -43,7 +43,7 @@ module Sentry
|
|
43
43
|
self.status = status
|
44
44
|
self.duration = duration
|
45
45
|
self.monitor_config = monitor_config
|
46
|
-
self.check_in_id = check_in_id || SecureRandom.uuid.delete(
|
46
|
+
self.check_in_id = check_in_id || SecureRandom.uuid.delete("-")
|
47
47
|
end
|
48
48
|
|
49
49
|
# @return [Hash]
|
data/lib/sentry/client.rb
CHANGED
@@ -30,7 +30,7 @@ module Sentry
|
|
30
30
|
else
|
31
31
|
@transport =
|
32
32
|
case configuration.dsn&.scheme
|
33
|
-
when
|
33
|
+
when "http", "https"
|
34
34
|
HTTPTransport.new(configuration)
|
35
35
|
else
|
36
36
|
DummyTransport.new(configuration)
|
@@ -49,7 +49,7 @@ module Sentry
|
|
49
49
|
return unless configuration.sending_allowed?
|
50
50
|
|
51
51
|
if event.is_a?(ErrorEvent) && !configuration.sample_allowed?
|
52
|
-
transport.record_lost_event(:sample_rate,
|
52
|
+
transport.record_lost_event(:sample_rate, "error")
|
53
53
|
return
|
54
54
|
end
|
55
55
|
|
@@ -64,11 +64,11 @@ module Sentry
|
|
64
64
|
if event.nil?
|
65
65
|
log_debug("Discarded event because one of the event processors returned nil")
|
66
66
|
transport.record_lost_event(:event_processor, data_category)
|
67
|
-
transport.record_lost_event(:event_processor,
|
67
|
+
transport.record_lost_event(:event_processor, "span", num: spans_before + 1) if is_transaction
|
68
68
|
return
|
69
69
|
elsif is_transaction
|
70
70
|
spans_delta = spans_before - event.spans.size
|
71
|
-
transport.record_lost_event(:event_processor,
|
71
|
+
transport.record_lost_event(:event_processor, "span", num: spans_delta) if spans_delta > 0
|
72
72
|
end
|
73
73
|
|
74
74
|
if async_block = configuration.async
|
@@ -76,7 +76,7 @@ module Sentry
|
|
76
76
|
elsif configuration.background_worker_threads != 0 && hint.fetch(:background, true)
|
77
77
|
unless dispatch_background_event(event, hint)
|
78
78
|
transport.record_lost_event(:queue_overflow, data_category)
|
79
|
-
transport.record_lost_event(:queue_overflow,
|
79
|
+
transport.record_lost_event(:queue_overflow, "span", num: spans_before + 1) if is_transaction
|
80
80
|
end
|
81
81
|
else
|
82
82
|
send_event(event, hint)
|
@@ -195,13 +195,13 @@ module Sentry
|
|
195
195
|
|
196
196
|
if event.nil?
|
197
197
|
log_debug("Discarded event because before_send_transaction returned nil")
|
198
|
-
transport.record_lost_event(:before_send,
|
199
|
-
transport.record_lost_event(:before_send,
|
198
|
+
transport.record_lost_event(:before_send, "transaction")
|
199
|
+
transport.record_lost_event(:before_send, "span", num: spans_before + 1)
|
200
200
|
return
|
201
201
|
else
|
202
202
|
spans_after = event.is_a?(TransactionEvent) ? event.spans.size : 0
|
203
203
|
spans_delta = spans_before - spans_after
|
204
|
-
transport.record_lost_event(:before_send,
|
204
|
+
transport.record_lost_event(:before_send, "span", num: spans_delta) if spans_delta > 0
|
205
205
|
end
|
206
206
|
end
|
207
207
|
|
@@ -212,7 +212,7 @@ module Sentry
|
|
212
212
|
rescue => e
|
213
213
|
log_error("Event sending failed", e, debug: configuration.debug)
|
214
214
|
transport.record_lost_event(:network_error, data_category)
|
215
|
-
transport.record_lost_event(:network_error,
|
215
|
+
transport.record_lost_event(:network_error, "span", num: spans_before + 1) if event.is_a?(TransactionEvent)
|
216
216
|
raise
|
217
217
|
end
|
218
218
|
|
data/lib/sentry/configuration.rb
CHANGED
@@ -4,6 +4,7 @@ require "concurrent/utility/processor_counter"
|
|
4
4
|
|
5
5
|
require "sentry/utils/exception_cause_chain"
|
6
6
|
require 'sentry/utils/custom_inspection'
|
7
|
+
require 'sentry/utils/env_helper'
|
7
8
|
require "sentry/dsn"
|
8
9
|
require "sentry/release_detector"
|
9
10
|
require "sentry/transport/configuration"
|
@@ -22,6 +23,8 @@ module Sentry
|
|
22
23
|
# have an `engines` dir at the root of your project, you may want
|
23
24
|
# to set this to something like /(app|config|engines|lib)/
|
24
25
|
#
|
26
|
+
# The default is value is /(bin|exe|app|config|lib|test|spec)/
|
27
|
+
#
|
25
28
|
# @return [Regexp, nil]
|
26
29
|
attr_accessor :app_dirs_pattern
|
27
30
|
|
@@ -187,6 +190,11 @@ module Sentry
|
|
187
190
|
# @return [String]
|
188
191
|
attr_accessor :project_root
|
189
192
|
|
193
|
+
# Whether to strip the load path while constructing the backtrace frame filename.
|
194
|
+
# Defaults to true.
|
195
|
+
# @return [Boolean]
|
196
|
+
attr_accessor :strip_backtrace_load_path
|
197
|
+
|
190
198
|
# Insert sentry-trace to outgoing requests' headers
|
191
199
|
# @return [Boolean]
|
192
200
|
attr_accessor :propagate_traces
|
@@ -302,18 +310,18 @@ module Sentry
|
|
302
310
|
# But they are mostly considered as noise and should be ignored by default
|
303
311
|
# Please see https://github.com/getsentry/sentry-ruby/pull/2026 for more information
|
304
312
|
PUMA_IGNORE_DEFAULT = [
|
305
|
-
|
306
|
-
|
307
|
-
|
313
|
+
"Puma::MiniSSL::SSLError",
|
314
|
+
"Puma::HttpParserError",
|
315
|
+
"Puma::HttpParserError501"
|
308
316
|
].freeze
|
309
317
|
|
310
318
|
# Most of these errors generate 4XX responses. In general, Sentry clients
|
311
319
|
# only automatically report 5xx responses.
|
312
320
|
IGNORE_DEFAULT = [
|
313
|
-
|
314
|
-
|
315
|
-
|
316
|
-
|
321
|
+
"Mongoid::Errors::DocumentNotFound",
|
322
|
+
"Rack::QueryParser::InvalidParameterError",
|
323
|
+
"Rack::QueryParser::ParameterTypeError",
|
324
|
+
"Sinatra::NotFound"
|
317
325
|
].freeze
|
318
326
|
|
319
327
|
RACK_ENV_WHITELIST_DEFAULT = %w[
|
@@ -335,6 +343,8 @@ module Sentry
|
|
335
343
|
|
336
344
|
DEFAULT_PATCHES = %i[redis puma http].freeze
|
337
345
|
|
346
|
+
APP_DIRS_PATTERN = /(bin|exe|app|config|lib|test|spec)/.freeze
|
347
|
+
|
338
348
|
class << self
|
339
349
|
# Post initialization callbacks are called at the end of initialization process
|
340
350
|
# allowing extending the configuration of sentry-ruby by multiple extensions
|
@@ -349,11 +359,12 @@ module Sentry
|
|
349
359
|
end
|
350
360
|
|
351
361
|
def initialize
|
352
|
-
self.app_dirs_pattern =
|
353
|
-
self.debug =
|
362
|
+
self.app_dirs_pattern = APP_DIRS_PATTERN
|
363
|
+
self.debug = Sentry::Utils::EnvHelper.env_to_bool(ENV["SENTRY_DEBUG"])
|
354
364
|
self.background_worker_threads = (processor_count / 2.0).ceil
|
355
365
|
self.background_worker_max_queue = BackgroundWorker::DEFAULT_MAX_QUEUE
|
356
366
|
self.backtrace_cleanup_callback = nil
|
367
|
+
self.strip_backtrace_load_path = true
|
357
368
|
self.max_breadcrumbs = BreadcrumbBuffer::DEFAULT_SIZE
|
358
369
|
self.breadcrumbs_logger = []
|
359
370
|
self.context_lines = 3
|
@@ -377,7 +388,10 @@ module Sentry
|
|
377
388
|
self.enable_backpressure_handling = false
|
378
389
|
self.trusted_proxies = []
|
379
390
|
self.dsn = ENV['SENTRY_DSN']
|
380
|
-
|
391
|
+
|
392
|
+
spotlight_env = ENV['SENTRY_SPOTLIGHT']
|
393
|
+
spotlight_bool = Sentry::Utils::EnvHelper.env_to_bool(spotlight_env, strict: true)
|
394
|
+
self.spotlight = spotlight_bool.nil? ? (spotlight_env || false) : spotlight_bool
|
381
395
|
self.server_name = server_name_from_env
|
382
396
|
self.instrumenter = :sentry
|
383
397
|
self.trace_propagation_targets = [PROPAGATION_TARGETS_MATCH_ALL]
|
@@ -555,7 +569,8 @@ module Sentry
|
|
555
569
|
app_dirs_pattern: @app_dirs_pattern,
|
556
570
|
linecache: @linecache,
|
557
571
|
context_lines: @context_lines,
|
558
|
-
backtrace_cleanup_callback: @backtrace_cleanup_callback
|
572
|
+
backtrace_cleanup_callback: @backtrace_cleanup_callback,
|
573
|
+
strip_backtrace_load_path: @strip_backtrace_load_path
|
559
574
|
)
|
560
575
|
end
|
561
576
|
|
@@ -632,12 +647,12 @@ module Sentry
|
|
632
647
|
end
|
633
648
|
|
634
649
|
def environment_from_env
|
635
|
-
ENV[
|
650
|
+
ENV["SENTRY_CURRENT_ENV"] || ENV["SENTRY_ENVIRONMENT"] || ENV["RAILS_ENV"] || ENV["RACK_ENV"] || "development"
|
636
651
|
end
|
637
652
|
|
638
653
|
def server_name_from_env
|
639
654
|
if running_on_heroku?
|
640
|
-
ENV[
|
655
|
+
ENV["DYNO"]
|
641
656
|
else
|
642
657
|
# Try to resolve the hostname to an FQDN, but fall back to whatever
|
643
658
|
# the load name is.
|
@@ -656,11 +671,8 @@ module Sentry
|
|
656
671
|
end
|
657
672
|
|
658
673
|
def processor_count
|
659
|
-
if Concurrent.respond_to?(:
|
660
|
-
|
661
|
-
else
|
662
|
-
Concurrent.processor_count
|
663
|
-
end
|
674
|
+
available_processor_count = Concurrent.available_processor_count if Concurrent.respond_to?(:available_processor_count)
|
675
|
+
available_processor_count || Concurrent.processor_count
|
664
676
|
end
|
665
677
|
end
|
666
678
|
end
|
data/lib/sentry/dsn.rb
CHANGED
@@ -4,7 +4,7 @@ require "uri"
|
|
4
4
|
|
5
5
|
module Sentry
|
6
6
|
class DSN
|
7
|
-
PORT_MAP = {
|
7
|
+
PORT_MAP = { "http" => 80, "https" => 443 }.freeze
|
8
8
|
REQUIRED_ATTRIBUTES = %w[host path public_key project_id].freeze
|
9
9
|
|
10
10
|
attr_reader :scheme, :secret_key, :port, *REQUIRED_ATTRIBUTES
|
@@ -13,7 +13,7 @@ module Sentry
|
|
13
13
|
@raw_value = dsn_string
|
14
14
|
|
15
15
|
uri = URI.parse(dsn_string)
|
16
|
-
uri_path = uri.path.split(
|
16
|
+
uri_path = uri.path.split("/")
|
17
17
|
|
18
18
|
if uri.user
|
19
19
|
# DSN-style string
|
@@ -25,7 +25,7 @@ module Sentry
|
|
25
25
|
@scheme = uri.scheme
|
26
26
|
@host = uri.host
|
27
27
|
@port = uri.port if uri.port
|
28
|
-
@path = uri_path.join(
|
28
|
+
@path = uri_path.join("/")
|
29
29
|
end
|
30
30
|
|
31
31
|
def valid?
|
data/lib/sentry/envelope.rb
CHANGED
@@ -15,19 +15,19 @@ module Sentry
|
|
15
15
|
end
|
16
16
|
|
17
17
|
def type
|
18
|
-
@headers[:type] ||
|
18
|
+
@headers[:type] || "event"
|
19
19
|
end
|
20
20
|
|
21
21
|
# rate limits and client reports use the data_category rather than envelope item type
|
22
22
|
def self.data_category(type)
|
23
23
|
case type
|
24
|
-
when
|
25
|
-
when
|
26
|
-
when
|
27
|
-
when
|
28
|
-
when
|
29
|
-
when
|
30
|
-
else
|
24
|
+
when "session", "attachment", "transaction", "profile", "span" then type
|
25
|
+
when "sessions" then "session"
|
26
|
+
when "check_in" then "monitor"
|
27
|
+
when "statsd", "metric_meta" then "metric_bucket"
|
28
|
+
when "event" then "error"
|
29
|
+
when "client_report" then "internal"
|
30
|
+
else "default"
|
31
31
|
end
|
32
32
|
end
|
33
33
|
|
data/lib/sentry/event.rb
CHANGED
@@ -1,12 +1,12 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require
|
4
|
-
require
|
5
|
-
require
|
6
|
-
require
|
7
|
-
require
|
8
|
-
require
|
9
|
-
require
|
3
|
+
require "socket"
|
4
|
+
require "securerandom"
|
5
|
+
require "sentry/interface"
|
6
|
+
require "sentry/backtrace"
|
7
|
+
require "sentry/utils/real_ip"
|
8
|
+
require "sentry/utils/request_id"
|
9
|
+
require "sentry/utils/custom_inspection"
|
10
10
|
|
11
11
|
module Sentry
|
12
12
|
# This is an abstract class that defines the shared attributes of an event.
|
@@ -42,6 +42,9 @@ module Sentry
|
|
42
42
|
# @return [Hash, nil]
|
43
43
|
attr_accessor :dynamic_sampling_context
|
44
44
|
|
45
|
+
# @return [Array<Attachment>]
|
46
|
+
attr_accessor :attachments
|
47
|
+
|
45
48
|
# @param configuration [Configuration]
|
46
49
|
# @param integration_meta [Hash, nil]
|
47
50
|
# @param message [String, nil]
|
@@ -57,6 +60,7 @@ module Sentry
|
|
57
60
|
@extra = {}
|
58
61
|
@contexts = {}
|
59
62
|
@tags = {}
|
63
|
+
@attachments = []
|
60
64
|
|
61
65
|
@fingerprint = []
|
62
66
|
@dynamic_sampling_context = nil
|
@@ -0,0 +1,77 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Sentry
|
4
|
+
module Faraday
|
5
|
+
OP_NAME = "http.client"
|
6
|
+
|
7
|
+
module Connection
|
8
|
+
# Since there's no way to preconfigure Faraday connections and add our instrumentation
|
9
|
+
# by default, we need to extend the connection constructor and do it there
|
10
|
+
#
|
11
|
+
# @see https://lostisland.github.io/faraday/#/customization/index?id=configuration
|
12
|
+
def initialize(url = nil, options = nil)
|
13
|
+
super
|
14
|
+
|
15
|
+
# Ensure that we attach instrumentation only if the adapter is not net/http
|
16
|
+
# because if is is, then the net/http instrumentation will take care of it
|
17
|
+
if builder.adapter.name != "Faraday::Adapter::NetHttp"
|
18
|
+
# Make sure that it's going to be the first middleware so that it can capture
|
19
|
+
# the entire request processing involving other middlewares
|
20
|
+
builder.insert(0, ::Faraday::Request::Instrumentation, name: OP_NAME, instrumenter: Instrumenter.new)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
class Instrumenter
|
26
|
+
SPAN_ORIGIN = "auto.http.faraday"
|
27
|
+
BREADCRUMB_CATEGORY = "http"
|
28
|
+
|
29
|
+
include Utils::HttpTracing
|
30
|
+
|
31
|
+
def instrument(op_name, env, &block)
|
32
|
+
return block.call unless Sentry.initialized?
|
33
|
+
|
34
|
+
Sentry.with_child_span(op: op_name, start_timestamp: Sentry.utc_now.to_f, origin: SPAN_ORIGIN) do |sentry_span|
|
35
|
+
request_info = extract_request_info(env)
|
36
|
+
|
37
|
+
if propagate_trace?(request_info[:url])
|
38
|
+
set_propagation_headers(env[:request_headers])
|
39
|
+
end
|
40
|
+
|
41
|
+
res = block.call
|
42
|
+
response_status = res.status
|
43
|
+
|
44
|
+
if record_sentry_breadcrumb?
|
45
|
+
record_sentry_breadcrumb(request_info, response_status)
|
46
|
+
end
|
47
|
+
|
48
|
+
if sentry_span
|
49
|
+
set_span_info(sentry_span, request_info, response_status)
|
50
|
+
end
|
51
|
+
|
52
|
+
res
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
private
|
57
|
+
|
58
|
+
def extract_request_info(env)
|
59
|
+
url = env[:url].scheme + "://" + env[:url].host + env[:url].path
|
60
|
+
result = { method: env[:method].to_s.upcase, url: url }
|
61
|
+
|
62
|
+
if Sentry.configuration.send_default_pii
|
63
|
+
result[:query] = env[:url].query
|
64
|
+
result[:body] = env[:body]
|
65
|
+
end
|
66
|
+
|
67
|
+
result
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
Sentry.register_patch(:faraday) do
|
74
|
+
if defined?(::Faraday)
|
75
|
+
::Faraday::Connection.prepend(Sentry::Faraday::Connection)
|
76
|
+
end
|
77
|
+
end
|
data/lib/sentry/graphql.rb
CHANGED
@@ -4,6 +4,6 @@ Sentry.register_patch(:graphql) do |config|
|
|
4
4
|
if defined?(::GraphQL::Schema) && defined?(::GraphQL::Tracing::SentryTrace) && ::GraphQL::Schema.respond_to?(:trace_with)
|
5
5
|
::GraphQL::Schema.trace_with(::GraphQL::Tracing::SentryTrace, set_transaction_name: true)
|
6
6
|
else
|
7
|
-
config.logger.warn(Sentry::LOGGER_PROGNAME) {
|
7
|
+
config.logger.warn(Sentry::LOGGER_PROGNAME) { "You tried to enable the GraphQL integration but no GraphQL gem was detected. Make sure you have the `graphql` gem (>= 2.2.6) in your Gemfile." }
|
8
8
|
end
|
9
9
|
end
|
data/lib/sentry/hub.rb
CHANGED
@@ -73,7 +73,13 @@ module Sentry
|
|
73
73
|
end
|
74
74
|
|
75
75
|
def pop_scope
|
76
|
-
@stack.
|
76
|
+
if @stack.size > 1
|
77
|
+
@stack.pop
|
78
|
+
else
|
79
|
+
# We never want to enter a situation where we have no scope and no client
|
80
|
+
client = current_client
|
81
|
+
@stack = [Layer.new(client, Scope.new)]
|
82
|
+
end
|
77
83
|
end
|
78
84
|
|
79
85
|
def start_transaction(transaction: nil, custom_sampling_context: {}, instrumenter: :sentry, **options)
|
@@ -214,6 +220,7 @@ module Sentry
|
|
214
220
|
end
|
215
221
|
|
216
222
|
def add_breadcrumb(breadcrumb, hint: {})
|
223
|
+
return unless current_client
|
217
224
|
return unless configuration.enabled_in_current_env?
|
218
225
|
|
219
226
|
if before_breadcrumb = current_client.configuration.before_breadcrumb
|
@@ -59,7 +59,7 @@ module Sentry
|
|
59
59
|
self.query_string = request.query_string
|
60
60
|
end
|
61
61
|
|
62
|
-
self.url = request.scheme && request.url.split(
|
62
|
+
self.url = request.scheme && request.url.split("?").first
|
63
63
|
self.method = request.request_method
|
64
64
|
|
65
65
|
self.headers = filter_and_format_headers(env, send_default_pii)
|
@@ -85,14 +85,14 @@ module Sentry
|
|
85
85
|
env.each_with_object({}) do |(key, value), memo|
|
86
86
|
begin
|
87
87
|
key = key.to_s # rack env can contain symbols
|
88
|
-
next memo[
|
88
|
+
next memo["X-Request-Id"] ||= Utils::RequestId.read_from(env) if Utils::RequestId::REQUEST_ID_HEADERS.include?(key)
|
89
89
|
next if is_server_protocol?(key, value, env["SERVER_PROTOCOL"])
|
90
90
|
next if is_skippable_header?(key)
|
91
91
|
next if key == "HTTP_AUTHORIZATION" && !send_default_pii
|
92
92
|
|
93
93
|
# Rack stores headers as HTTP_WHAT_EVER, we need What-Ever
|
94
94
|
key = key.sub(/^HTTP_/, "")
|
95
|
-
key = key.split(
|
95
|
+
key = key.split("_").map(&:capitalize).join("-")
|
96
96
|
|
97
97
|
memo[key] = Utils::EncodingHelper.encode_to_utf_8(value.to_s)
|
98
98
|
rescue StandardError => e
|
@@ -108,7 +108,7 @@ module Sentry
|
|
108
108
|
def is_skippable_header?(key)
|
109
109
|
key.upcase != key || # lower-case envs aren't real http headers
|
110
110
|
key == "HTTP_COOKIE" || # Cookies don't go here, they go somewhere else
|
111
|
-
!(key.start_with?(
|
111
|
+
!(key.start_with?("HTTP_") || CONTENT_HEADERS.include?(key))
|
112
112
|
end
|
113
113
|
|
114
114
|
# In versions < 3, Rack adds in an incorrect HTTP_VERSION key, which causes downstream
|
@@ -120,7 +120,7 @@ module Sentry
|
|
120
120
|
rack_version = Gem::Version.new(::Rack.release)
|
121
121
|
return false if rack_version >= Gem::Version.new("3.0")
|
122
122
|
|
123
|
-
key ==
|
123
|
+
key == "HTTP_VERSION" && value == protocol_version
|
124
124
|
end
|
125
125
|
|
126
126
|
def filter_and_format_env(env, rack_env_whitelist)
|
@@ -26,7 +26,7 @@ module Sentry
|
|
26
26
|
|
27
27
|
@value = Utils::EncodingHelper.encode_to_utf_8(exception_message.byteslice(0..Event::MAX_MESSAGE_SIZE_IN_BYTES))
|
28
28
|
|
29
|
-
@module = exception.class.to_s.split(
|
29
|
+
@module = exception.class.to_s.split("::")[0...-1].join("::")
|
30
30
|
@thread_id = Thread.current.object_id
|
31
31
|
@stacktrace = stacktrace
|
32
32
|
@mechanism = mechanism
|