sentry-ruby 5.10.0 → 5.26.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/.rspec +3 -1
- data/Gemfile +12 -13
- data/README.md +26 -11
- data/Rakefile +9 -11
- data/bin/console +2 -0
- data/lib/sentry/attachment.rb +40 -0
- data/lib/sentry/background_worker.rb +11 -5
- data/lib/sentry/backpressure_monitor.rb +45 -0
- data/lib/sentry/backtrace.rb +12 -9
- data/lib/sentry/baggage.rb +7 -7
- data/lib/sentry/breadcrumb/sentry_logger.rb +6 -6
- data/lib/sentry/breadcrumb.rb +13 -6
- data/lib/sentry/check_in_event.rb +61 -0
- data/lib/sentry/client.rb +214 -25
- data/lib/sentry/configuration.rb +221 -38
- data/lib/sentry/core_ext/object/deep_dup.rb +1 -1
- data/lib/sentry/cron/configuration.rb +23 -0
- data/lib/sentry/cron/monitor_check_ins.rb +77 -0
- data/lib/sentry/cron/monitor_config.rb +53 -0
- data/lib/sentry/cron/monitor_schedule.rb +42 -0
- 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 +28 -47
- data/lib/sentry/excon/middleware.rb +77 -0
- data/lib/sentry/excon.rb +10 -0
- data/lib/sentry/faraday.rb +77 -0
- data/lib/sentry/graphql.rb +9 -0
- data/lib/sentry/hub.rb +138 -6
- data/lib/sentry/integrable.rb +10 -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 +8 -8
- data/lib/sentry/interfaces/single_exception.rb +13 -9
- data/lib/sentry/interfaces/stacktrace.rb +3 -1
- data/lib/sentry/interfaces/stacktrace_builder.rb +23 -2
- data/lib/sentry/linecache.rb +3 -3
- data/lib/sentry/log_event.rb +206 -0
- data/lib/sentry/log_event_buffer.rb +75 -0
- 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 +51 -0
- data/lib/sentry/metrics.rb +56 -0
- data/lib/sentry/net/http.rb +27 -44
- data/lib/sentry/profiler/helpers.rb +46 -0
- data/lib/sentry/profiler.rb +41 -60
- data/lib/sentry/propagation_context.rb +135 -0
- data/lib/sentry/puma.rb +12 -5
- data/lib/sentry/rack/capture_exceptions.rb +17 -8
- data/lib/sentry/rack.rb +2 -2
- data/lib/sentry/rake.rb +4 -15
- data/lib/sentry/redis.rb +10 -4
- data/lib/sentry/release_detector.rb +5 -5
- data/lib/sentry/rspec.rb +91 -0
- data/lib/sentry/scope.rb +75 -39
- data/lib/sentry/session.rb +2 -2
- data/lib/sentry/session_flusher.rb +15 -43
- data/lib/sentry/span.rb +92 -8
- data/lib/sentry/std_lib_logger.rb +50 -0
- data/lib/sentry/structured_logger.rb +138 -0
- data/lib/sentry/test_helper.rb +42 -13
- data/lib/sentry/threaded_periodic_worker.rb +39 -0
- data/lib/sentry/transaction.rb +44 -43
- data/lib/sentry/transaction_event.rb +10 -6
- data/lib/sentry/transport/configuration.rb +73 -1
- data/lib/sentry/transport/http_transport.rb +71 -41
- data/lib/sentry/transport/spotlight_transport.rb +50 -0
- data/lib/sentry/transport.rb +53 -49
- data/lib/sentry/utils/argument_checking_helper.rb +12 -0
- data/lib/sentry/utils/env_helper.rb +21 -0
- data/lib/sentry/utils/http_tracing.rb +74 -0
- data/lib/sentry/utils/logging_helper.rb +10 -7
- data/lib/sentry/utils/real_ip.rb +2 -2
- data/lib/sentry/utils/request_id.rb +1 -1
- data/lib/sentry/utils/uuid.rb +13 -0
- data/lib/sentry/vernier/output.rb +89 -0
- data/lib/sentry/vernier/profiler.rb +132 -0
- data/lib/sentry/version.rb +1 -1
- data/lib/sentry-ruby.rb +206 -35
- data/sentry-ruby-core.gemspec +3 -1
- data/sentry-ruby.gemspec +15 -6
- metadata +61 -11
@@ -0,0 +1,88 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Sentry
|
4
|
+
# @api private
|
5
|
+
class Envelope::Item
|
6
|
+
STACKTRACE_FRAME_LIMIT_ON_OVERSIZED_PAYLOAD = 500
|
7
|
+
MAX_SERIALIZED_PAYLOAD_SIZE = 1024 * 1000
|
8
|
+
|
9
|
+
SIZE_LIMITS = Hash.new(MAX_SERIALIZED_PAYLOAD_SIZE).update(
|
10
|
+
"profile" => 1024 * 1000 * 50
|
11
|
+
)
|
12
|
+
|
13
|
+
attr_reader :size_limit, :headers, :payload, :type, :data_category
|
14
|
+
|
15
|
+
# rate limits and client reports use the data_category rather than envelope item type
|
16
|
+
def self.data_category(type)
|
17
|
+
case type
|
18
|
+
when "session", "attachment", "transaction", "profile", "span", "log" then type
|
19
|
+
when "sessions" then "session"
|
20
|
+
when "check_in" then "monitor"
|
21
|
+
when "statsd", "metric_meta" then "metric_bucket"
|
22
|
+
when "event" then "error"
|
23
|
+
when "client_report" then "internal"
|
24
|
+
else "default"
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def initialize(headers, payload)
|
29
|
+
@headers = headers
|
30
|
+
@payload = payload
|
31
|
+
@type = headers[:type] || "event"
|
32
|
+
@data_category = self.class.data_category(type)
|
33
|
+
@size_limit = SIZE_LIMITS[type]
|
34
|
+
end
|
35
|
+
|
36
|
+
def to_s
|
37
|
+
[JSON.generate(@headers), @payload.is_a?(String) ? @payload : JSON.generate(@payload)].join("\n")
|
38
|
+
end
|
39
|
+
|
40
|
+
def serialize
|
41
|
+
result = to_s
|
42
|
+
|
43
|
+
if result.bytesize > size_limit
|
44
|
+
remove_breadcrumbs!
|
45
|
+
result = to_s
|
46
|
+
end
|
47
|
+
|
48
|
+
if result.bytesize > size_limit
|
49
|
+
reduce_stacktrace!
|
50
|
+
result = to_s
|
51
|
+
end
|
52
|
+
|
53
|
+
[result, result.bytesize > size_limit]
|
54
|
+
end
|
55
|
+
|
56
|
+
def size_breakdown
|
57
|
+
payload.map do |key, value|
|
58
|
+
"#{key}: #{JSON.generate(value).bytesize}"
|
59
|
+
end.join(", ")
|
60
|
+
end
|
61
|
+
|
62
|
+
private
|
63
|
+
|
64
|
+
def remove_breadcrumbs!
|
65
|
+
if payload.key?(:breadcrumbs)
|
66
|
+
payload.delete(:breadcrumbs)
|
67
|
+
elsif payload.key?("breadcrumbs")
|
68
|
+
payload.delete("breadcrumbs")
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
def reduce_stacktrace!
|
73
|
+
if exceptions = payload.dig(:exception, :values) || payload.dig("exception", "values")
|
74
|
+
exceptions.each do |exception|
|
75
|
+
# in most cases there is only one exception (2 or 3 when have multiple causes), so we won't loop through this double condition much
|
76
|
+
traces = exception.dig(:stacktrace, :frames) || exception.dig("stacktrace", "frames")
|
77
|
+
|
78
|
+
if traces && traces.size > STACKTRACE_FRAME_LIMIT_ON_OVERSIZED_PAYLOAD
|
79
|
+
size_on_both_ends = STACKTRACE_FRAME_LIMIT_ON_OVERSIZED_PAYLOAD / 2
|
80
|
+
traces.replace(
|
81
|
+
traces[0..(size_on_both_ends - 1)] + traces[-size_on_both_ends..-1],
|
82
|
+
)
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
data/lib/sentry/envelope.rb
CHANGED
@@ -3,74 +3,6 @@
|
|
3
3
|
module Sentry
|
4
4
|
# @api private
|
5
5
|
class Envelope
|
6
|
-
class Item
|
7
|
-
STACKTRACE_FRAME_LIMIT_ON_OVERSIZED_PAYLOAD = 500
|
8
|
-
MAX_SERIALIZED_PAYLOAD_SIZE = 1024 * 200
|
9
|
-
|
10
|
-
attr_accessor :headers, :payload
|
11
|
-
|
12
|
-
def initialize(headers, payload)
|
13
|
-
@headers = headers
|
14
|
-
@payload = payload
|
15
|
-
end
|
16
|
-
|
17
|
-
def type
|
18
|
-
@headers[:type] || 'event'
|
19
|
-
end
|
20
|
-
|
21
|
-
def to_s
|
22
|
-
[JSON.generate(@headers), JSON.generate(@payload)].join("\n")
|
23
|
-
end
|
24
|
-
|
25
|
-
def serialize
|
26
|
-
result = to_s
|
27
|
-
|
28
|
-
if result.bytesize > MAX_SERIALIZED_PAYLOAD_SIZE
|
29
|
-
remove_breadcrumbs!
|
30
|
-
result = to_s
|
31
|
-
end
|
32
|
-
|
33
|
-
if result.bytesize > MAX_SERIALIZED_PAYLOAD_SIZE
|
34
|
-
reduce_stacktrace!
|
35
|
-
result = to_s
|
36
|
-
end
|
37
|
-
|
38
|
-
[result, result.bytesize > MAX_SERIALIZED_PAYLOAD_SIZE]
|
39
|
-
end
|
40
|
-
|
41
|
-
def size_breakdown
|
42
|
-
payload.map do |key, value|
|
43
|
-
"#{key}: #{JSON.generate(value).bytesize}"
|
44
|
-
end.join(", ")
|
45
|
-
end
|
46
|
-
|
47
|
-
private
|
48
|
-
|
49
|
-
def remove_breadcrumbs!
|
50
|
-
if payload.key?(:breadcrumbs)
|
51
|
-
payload.delete(:breadcrumbs)
|
52
|
-
elsif payload.key?("breadcrumbs")
|
53
|
-
payload.delete("breadcrumbs")
|
54
|
-
end
|
55
|
-
end
|
56
|
-
|
57
|
-
def reduce_stacktrace!
|
58
|
-
if exceptions = payload.dig(:exception, :values) || payload.dig("exception", "values")
|
59
|
-
exceptions.each do |exception|
|
60
|
-
# in most cases there is only one exception (2 or 3 when have multiple causes), so we won't loop through this double condition much
|
61
|
-
traces = exception.dig(:stacktrace, :frames) || exception.dig("stacktrace", "frames")
|
62
|
-
|
63
|
-
if traces && traces.size > STACKTRACE_FRAME_LIMIT_ON_OVERSIZED_PAYLOAD
|
64
|
-
size_on_both_ends = STACKTRACE_FRAME_LIMIT_ON_OVERSIZED_PAYLOAD / 2
|
65
|
-
traces.replace(
|
66
|
-
traces[0..(size_on_both_ends - 1)] + traces[-size_on_both_ends..-1],
|
67
|
-
)
|
68
|
-
end
|
69
|
-
end
|
70
|
-
end
|
71
|
-
end
|
72
|
-
end
|
73
|
-
|
74
6
|
attr_accessor :headers, :items
|
75
7
|
|
76
8
|
def initialize(headers = {})
|
@@ -91,3 +23,5 @@ module Sentry
|
|
91
23
|
end
|
92
24
|
end
|
93
25
|
end
|
26
|
+
|
27
|
+
require_relative "envelope/item"
|
data/lib/sentry/error_event.rb
CHANGED
@@ -27,12 +27,12 @@ module Sentry
|
|
27
27
|
end
|
28
28
|
|
29
29
|
# @!visibility private
|
30
|
-
def add_exception_interface(exception)
|
30
|
+
def add_exception_interface(exception, mechanism:)
|
31
31
|
if exception.respond_to?(:sentry_context)
|
32
32
|
@extra.merge!(exception.sentry_context)
|
33
33
|
end
|
34
34
|
|
35
|
-
@exception = Sentry::ExceptionInterface.build(exception: exception, stacktrace_builder: @stacktrace_builder)
|
35
|
+
@exception = Sentry::ExceptionInterface.build(exception: exception, stacktrace_builder: @stacktrace_builder, mechanism: mechanism)
|
36
36
|
end
|
37
37
|
end
|
38
38
|
end
|
data/lib/sentry/event.rb
CHANGED
@@ -1,12 +1,13 @@
|
|
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
|
+
require "sentry/utils/uuid"
|
10
11
|
|
11
12
|
module Sentry
|
12
13
|
# This is an abstract class that defines the shared attributes of an event.
|
@@ -14,16 +15,16 @@ module Sentry
|
|
14
15
|
class Event
|
15
16
|
TYPE = "event"
|
16
17
|
# These are readable attributes.
|
17
|
-
SERIALIZEABLE_ATTRIBUTES = %i
|
18
|
+
SERIALIZEABLE_ATTRIBUTES = %i[
|
18
19
|
event_id level timestamp
|
19
20
|
release environment server_name modules
|
20
21
|
message user tags contexts extra
|
21
22
|
fingerprint breadcrumbs transaction transaction_info
|
22
23
|
platform sdk type
|
23
|
-
|
24
|
+
]
|
24
25
|
|
25
26
|
# These are writable attributes.
|
26
|
-
WRITER_ATTRIBUTES = SERIALIZEABLE_ATTRIBUTES - %i
|
27
|
+
WRITER_ATTRIBUTES = SERIALIZEABLE_ATTRIBUTES - %i[type timestamp level]
|
27
28
|
|
28
29
|
MAX_MESSAGE_SIZE_IN_BYTES = 1024 * 8
|
29
30
|
|
@@ -37,12 +38,20 @@ module Sentry
|
|
37
38
|
# @return [RequestInterface]
|
38
39
|
attr_reader :request
|
39
40
|
|
41
|
+
# Dynamic Sampling Context (DSC) that gets attached
|
42
|
+
# as the trace envelope header in the transport.
|
43
|
+
# @return [Hash, nil]
|
44
|
+
attr_accessor :dynamic_sampling_context
|
45
|
+
|
46
|
+
# @return [Array<Attachment>]
|
47
|
+
attr_accessor :attachments
|
48
|
+
|
40
49
|
# @param configuration [Configuration]
|
41
50
|
# @param integration_meta [Hash, nil]
|
42
51
|
# @param message [String, nil]
|
43
52
|
def initialize(configuration:, integration_meta: nil, message: nil)
|
44
53
|
# Set some simple default values
|
45
|
-
@event_id =
|
54
|
+
@event_id = Utils.uuid
|
46
55
|
@timestamp = Sentry.utc_now.iso8601
|
47
56
|
@platform = :ruby
|
48
57
|
@type = self.class::TYPE
|
@@ -52,8 +61,10 @@ module Sentry
|
|
52
61
|
@extra = {}
|
53
62
|
@contexts = {}
|
54
63
|
@tags = {}
|
64
|
+
@attachments = []
|
55
65
|
|
56
66
|
@fingerprint = []
|
67
|
+
@dynamic_sampling_context = nil
|
57
68
|
|
58
69
|
# configuration data that's directly used by events
|
59
70
|
@server_name = configuration.server_name
|
@@ -70,34 +81,6 @@ module Sentry
|
|
70
81
|
@message = (message || "").byteslice(0..MAX_MESSAGE_SIZE_IN_BYTES)
|
71
82
|
end
|
72
83
|
|
73
|
-
class << self
|
74
|
-
# @!visibility private
|
75
|
-
def get_log_message(event_hash)
|
76
|
-
message = event_hash[:message] || event_hash['message']
|
77
|
-
|
78
|
-
return message unless message.nil? || message.empty?
|
79
|
-
|
80
|
-
message = get_message_from_exception(event_hash)
|
81
|
-
|
82
|
-
return message unless message.nil? || message.empty?
|
83
|
-
|
84
|
-
message = event_hash[:transaction] || event_hash["transaction"]
|
85
|
-
|
86
|
-
return message unless message.nil? || message.empty?
|
87
|
-
|
88
|
-
'<no message value>'
|
89
|
-
end
|
90
|
-
|
91
|
-
# @!visibility private
|
92
|
-
def get_message_from_exception(event_hash)
|
93
|
-
if exception = event_hash.dig(:exception, :values, 0)
|
94
|
-
"#{exception[:type]}: #{exception[:value]}"
|
95
|
-
elsif exception = event_hash.dig("exception", "values", 0)
|
96
|
-
"#{exception["type"]}: #{exception["value"]}"
|
97
|
-
end
|
98
|
-
end
|
99
|
-
end
|
100
|
-
|
101
84
|
# @deprecated This method will be removed in v5.0.0. Please just use Sentry.configuration
|
102
85
|
# @return [Configuration]
|
103
86
|
def configuration
|
@@ -126,9 +109,7 @@ module Sentry
|
|
126
109
|
unless request || env.empty?
|
127
110
|
add_request_interface(env)
|
128
111
|
|
129
|
-
if @send_default_pii
|
130
|
-
user[:ip_address] = calculate_real_ip_from_rack(env)
|
131
|
-
end
|
112
|
+
user[:ip_address] ||= calculate_real_ip_from_rack(env) if @send_default_pii
|
132
113
|
|
133
114
|
if request_id = Utils::RequestId.read_from(env)
|
134
115
|
tags[:request_id] = request_id
|
@@ -167,11 +148,11 @@ module Sentry
|
|
167
148
|
# REMOTE_ADDR to determine the Event IP, and must use other headers instead.
|
168
149
|
def calculate_real_ip_from_rack(env)
|
169
150
|
Utils::RealIp.new(
|
170
|
-
:
|
171
|
-
:
|
172
|
-
:
|
173
|
-
:
|
174
|
-
:
|
151
|
+
remote_addr: env["REMOTE_ADDR"],
|
152
|
+
client_ip: env["HTTP_CLIENT_IP"],
|
153
|
+
real_ip: env["HTTP_X_REAL_IP"],
|
154
|
+
forwarded_for: env["HTTP_X_FORWARDED_FOR"],
|
155
|
+
trusted_proxies: @trusted_proxies
|
175
156
|
).calculate_ip
|
176
157
|
end
|
177
158
|
end
|
@@ -0,0 +1,77 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Sentry
|
4
|
+
module Excon
|
5
|
+
OP_NAME = "http.client"
|
6
|
+
|
7
|
+
class Middleware < ::Excon::Middleware::Base
|
8
|
+
def initialize(stack)
|
9
|
+
super
|
10
|
+
@instrumenter = Instrumenter.new
|
11
|
+
end
|
12
|
+
|
13
|
+
def request_call(datum)
|
14
|
+
@instrumenter.start_transaction(datum)
|
15
|
+
@stack.request_call(datum)
|
16
|
+
end
|
17
|
+
|
18
|
+
def response_call(datum)
|
19
|
+
@instrumenter.finish_transaction(datum)
|
20
|
+
@stack.response_call(datum)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
class Instrumenter
|
25
|
+
SPAN_ORIGIN = "auto.http.excon"
|
26
|
+
BREADCRUMB_CATEGORY = "http"
|
27
|
+
|
28
|
+
include Utils::HttpTracing
|
29
|
+
|
30
|
+
def start_transaction(env)
|
31
|
+
return unless Sentry.initialized?
|
32
|
+
|
33
|
+
current_span = Sentry.get_current_scope&.span
|
34
|
+
@span = current_span&.start_child(op: OP_NAME, start_timestamp: Sentry.utc_now.to_f, origin: SPAN_ORIGIN)
|
35
|
+
|
36
|
+
request_info = extract_request_info(env)
|
37
|
+
|
38
|
+
if propagate_trace?(request_info[:url])
|
39
|
+
set_propagation_headers(env[:headers])
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
def finish_transaction(response)
|
44
|
+
return unless @span
|
45
|
+
|
46
|
+
response_status = response[:response][:status]
|
47
|
+
request_info = extract_request_info(response)
|
48
|
+
|
49
|
+
if record_sentry_breadcrumb?
|
50
|
+
record_sentry_breadcrumb(request_info, response_status)
|
51
|
+
end
|
52
|
+
|
53
|
+
set_span_info(@span, request_info, response_status)
|
54
|
+
ensure
|
55
|
+
@span&.finish
|
56
|
+
end
|
57
|
+
|
58
|
+
private
|
59
|
+
|
60
|
+
def extract_request_info(env)
|
61
|
+
url = env[:scheme] + "://" + env[:hostname] + env[:path]
|
62
|
+
result = { method: env[:method].to_s.upcase, url: url }
|
63
|
+
|
64
|
+
if Sentry.configuration.send_default_pii
|
65
|
+
result[:query] = env[:query]
|
66
|
+
|
67
|
+
# Handle excon 1.0.0+
|
68
|
+
result[:query] = build_nested_query(result[:query]) unless result[:query].is_a?(String)
|
69
|
+
|
70
|
+
result[:body] = env[:body]
|
71
|
+
end
|
72
|
+
|
73
|
+
result
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
data/lib/sentry/excon.rb
ADDED
@@ -0,0 +1,10 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
Sentry.register_patch(:excon) do
|
4
|
+
if defined?(::Excon)
|
5
|
+
require "sentry/excon/middleware"
|
6
|
+
if Excon.defaults[:middlewares]
|
7
|
+
Excon.defaults[:middlewares] << Sentry::Excon::Middleware unless Excon.defaults[:middlewares].include?(Sentry::Excon::Middleware)
|
8
|
+
end
|
9
|
+
end
|
10
|
+
end
|
@@ -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
|
@@ -0,0 +1,9 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
Sentry.register_patch(:graphql) do |config|
|
4
|
+
if defined?(::GraphQL::Schema) && defined?(::GraphQL::Tracing::SentryTrace) && ::GraphQL::Schema.respond_to?(:trace_with)
|
5
|
+
::GraphQL::Schema.trace_with(::GraphQL::Tracing::SentryTrace, set_transaction_name: true)
|
6
|
+
else
|
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
|
+
end
|
9
|
+
end
|