sentry-ruby-core 4.8.0 → 4.9.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (50) hide show
  1. checksums.yaml +4 -4
  2. data/.yardopts +2 -0
  3. data/Gemfile +2 -0
  4. data/README.md +2 -0
  5. data/lib/sentry/background_worker.rb +33 -3
  6. data/lib/sentry/backtrace.rb +1 -3
  7. data/lib/sentry/breadcrumb/sentry_logger.rb +2 -0
  8. data/lib/sentry/breadcrumb.rb +24 -3
  9. data/lib/sentry/breadcrumb_buffer.rb +16 -0
  10. data/lib/sentry/client.rb +33 -1
  11. data/lib/sentry/configuration.rb +88 -41
  12. data/lib/sentry/core_ext/object/deep_dup.rb +2 -0
  13. data/lib/sentry/core_ext/object/duplicable.rb +1 -0
  14. data/lib/sentry/dsn.rb +2 -0
  15. data/lib/sentry/envelope.rb +26 -0
  16. data/lib/sentry/event.rb +54 -18
  17. data/lib/sentry/exceptions.rb +2 -0
  18. data/lib/sentry/hub.rb +2 -0
  19. data/lib/sentry/integrable.rb +2 -0
  20. data/lib/sentry/interface.rb +3 -10
  21. data/lib/sentry/interfaces/exception.rb +13 -3
  22. data/lib/sentry/interfaces/request.rb +34 -18
  23. data/lib/sentry/interfaces/single_exception.rb +2 -0
  24. data/lib/sentry/interfaces/stacktrace.rb +6 -0
  25. data/lib/sentry/interfaces/stacktrace_builder.rb +39 -10
  26. data/lib/sentry/interfaces/threads.rb +12 -2
  27. data/lib/sentry/linecache.rb +3 -0
  28. data/lib/sentry/net/http.rb +52 -64
  29. data/lib/sentry/rack/capture_exceptions.rb +2 -0
  30. data/lib/sentry/rack.rb +2 -0
  31. data/lib/sentry/rake.rb +16 -6
  32. data/lib/sentry/release_detector.rb +3 -0
  33. data/lib/sentry/scope.rb +75 -5
  34. data/lib/sentry/span.rb +84 -8
  35. data/lib/sentry/transaction.rb +44 -9
  36. data/lib/sentry/transaction_event.rb +8 -0
  37. data/lib/sentry/transport/configuration.rb +2 -0
  38. data/lib/sentry/transport/dummy_transport.rb +2 -0
  39. data/lib/sentry/transport/http_transport.rb +6 -4
  40. data/lib/sentry/transport.rb +23 -25
  41. data/lib/sentry/utils/argument_checking_helper.rb +2 -0
  42. data/lib/sentry/utils/custom_inspection.rb +2 -0
  43. data/lib/sentry/utils/exception_cause_chain.rb +2 -0
  44. data/lib/sentry/utils/logging_helper.rb +6 -4
  45. data/lib/sentry/utils/real_ip.rb +2 -0
  46. data/lib/sentry/utils/request_id.rb +2 -0
  47. data/lib/sentry/version.rb +3 -1
  48. data/lib/sentry-ruby.rb +122 -29
  49. data/sentry-ruby.gemspec +1 -1
  50. metadata +4 -2
data/lib/sentry/event.rb CHANGED
@@ -10,31 +10,40 @@ require 'sentry/utils/custom_inspection'
10
10
 
11
11
  module Sentry
12
12
  class Event
13
+ # These are readable attributes.
13
14
  SERIALIZEABLE_ATTRIBUTES = %i(
14
15
  event_id level timestamp
15
16
  release environment server_name modules
16
17
  message user tags contexts extra
17
- fingerprint breadcrumbs backtrace transaction
18
+ fingerprint breadcrumbs transaction
18
19
  platform sdk type
19
20
  )
20
21
 
22
+ # These are writable attributes.
21
23
  WRITER_ATTRIBUTES = SERIALIZEABLE_ATTRIBUTES - %i(type timestamp level)
22
24
 
23
25
  MAX_MESSAGE_SIZE_IN_BYTES = 1024 * 8
24
26
 
25
- SKIP_INSPECTION_ATTRIBUTES = [:@configuration, :@modules, :@backtrace]
27
+ SKIP_INSPECTION_ATTRIBUTES = [:@modules, :@stacktrace_builder, :@send_default_pii, :@trusted_proxies, :@rack_env_whitelist]
26
28
 
27
29
  include CustomInspection
28
30
 
29
31
  attr_writer(*WRITER_ATTRIBUTES)
30
32
  attr_reader(*SERIALIZEABLE_ATTRIBUTES)
31
33
 
32
- attr_reader :configuration, :request, :exception, :threads
34
+ # @return [RequestInterface]
35
+ attr_reader :request
33
36
 
34
- def initialize(configuration:, integration_meta: nil, message: nil)
35
- # this needs to go first because some setters rely on configuration
36
- @configuration = configuration
37
+ # @return [ExceptionInterface]
38
+ attr_reader :exception
39
+
40
+ # @return [ThreadsInterface]
41
+ attr_reader :threads
37
42
 
43
+ # @param configuration [Configuration]
44
+ # @param integration_meta [Hash, nil]
45
+ # @param message [String, nil]
46
+ def initialize(configuration:, integration_meta: nil, message: nil)
38
47
  # Set some simple default values
39
48
  @event_id = SecureRandom.uuid.delete("-")
40
49
  @timestamp = Sentry.utc_now.iso8601
@@ -48,17 +57,25 @@ module Sentry
48
57
 
49
58
  @fingerprint = []
50
59
 
60
+ # configuration data that's directly used by events
51
61
  @server_name = configuration.server_name
52
62
  @environment = configuration.environment
53
63
  @release = configuration.release
54
64
  @modules = configuration.gem_specs if configuration.send_modules
55
65
 
66
+ # configuration options to help events process data
67
+ @send_default_pii = configuration.send_default_pii
68
+ @trusted_proxies = configuration.trusted_proxies
69
+ @stacktrace_builder = configuration.stacktrace_builder
70
+ @rack_env_whitelist = configuration.rack_env_whitelist
71
+
56
72
  @message = (message || "").byteslice(0..MAX_MESSAGE_SIZE_IN_BYTES)
57
73
 
58
74
  self.level = :error
59
75
  end
60
76
 
61
77
  class << self
78
+ # @!visibility private
62
79
  def get_log_message(event_hash)
63
80
  message = event_hash[:message] || event_hash['message']
64
81
 
@@ -75,6 +92,7 @@ module Sentry
75
92
  '<no message value>'
76
93
  end
77
94
 
95
+ # @!visibility private
78
96
  def get_message_from_exception(event_hash)
79
97
  if exception = event_hash.dig(:exception, :values, 0)
80
98
  "#{exception[:type]}: #{exception[:value]}"
@@ -84,21 +102,35 @@ module Sentry
84
102
  end
85
103
  end
86
104
 
105
+ # @deprecated This method will be removed in v5.0.0. Please just use Sentry.configuration
106
+ # @return [Configuration]
107
+ def configuration
108
+ Sentry.configuration
109
+ end
110
+
111
+ # Sets the event's timestamp.
112
+ # @param time [Time, Float]
113
+ # @return [void]
87
114
  def timestamp=(time)
88
115
  @timestamp = time.is_a?(Time) ? time.to_f : time
89
116
  end
90
117
 
91
- def level=(new_level) # needed to meet the Sentry spec
92
- @level = new_level.to_s == "warn" ? :warning : new_level
118
+ # Sets the event's level.
119
+ # @param level [String, Symbol]
120
+ # @return [void]
121
+ def level=(level) # needed to meet the Sentry spec
122
+ @level = level.to_s == "warn" ? :warning : level
93
123
  end
94
124
 
125
+ # Sets the event's request environment data with RequestInterface.
126
+ # @see RequestInterface
127
+ # @param env [Hash]
128
+ # @return [void]
95
129
  def rack_env=(env)
96
130
  unless request || env.empty?
97
- env = env.dup
98
-
99
131
  add_request_interface(env)
100
132
 
101
- if configuration.send_default_pii
133
+ if @send_default_pii
102
134
  user[:ip_address] = calculate_real_ip_from_rack(env)
103
135
  end
104
136
 
@@ -108,6 +140,7 @@ module Sentry
108
140
  end
109
141
  end
110
142
 
143
+ # @return [Hash]
111
144
  def to_hash
112
145
  data = serialize_attributes
113
146
  data[:breadcrumbs] = breadcrumbs.to_hash if breadcrumbs
@@ -118,32 +151,35 @@ module Sentry
118
151
  data
119
152
  end
120
153
 
154
+ # @return [Hash]
121
155
  def to_json_compatible
122
156
  JSON.parse(JSON.generate(to_hash))
123
157
  end
124
158
 
125
- def add_request_interface(env)
126
- @request = Sentry::RequestInterface.build(env: env)
127
- end
128
-
159
+ # @!visibility private
129
160
  def add_threads_interface(backtrace: nil, **options)
130
161
  @threads = ThreadsInterface.build(
131
162
  backtrace: backtrace,
132
- stacktrace_builder: configuration.stacktrace_builder,
163
+ stacktrace_builder: @stacktrace_builder,
133
164
  **options
134
165
  )
135
166
  end
136
167
 
168
+ # @!visibility private
137
169
  def add_exception_interface(exception)
138
170
  if exception.respond_to?(:sentry_context)
139
171
  @extra.merge!(exception.sentry_context)
140
172
  end
141
173
 
142
- @exception = Sentry::ExceptionInterface.build(exception: exception, stacktrace_builder: configuration.stacktrace_builder)
174
+ @exception = Sentry::ExceptionInterface.build(exception: exception, stacktrace_builder: @stacktrace_builder)
143
175
  end
144
176
 
145
177
  private
146
178
 
179
+ def add_request_interface(env)
180
+ @request = Sentry::RequestInterface.new(env: env, send_default_pii: @send_default_pii, rack_env_whitelist: @rack_env_whitelist)
181
+ end
182
+
147
183
  def serialize_attributes
148
184
  self.class::SERIALIZEABLE_ATTRIBUTES.each_with_object({}) do |att, memo|
149
185
  if value = public_send(att)
@@ -160,7 +196,7 @@ module Sentry
160
196
  :client_ip => env["HTTP_CLIENT_IP"],
161
197
  :real_ip => env["HTTP_X_REAL_IP"],
162
198
  :forwarded_for => env["HTTP_X_FORWARDED_FOR"],
163
- :trusted_proxies => configuration.trusted_proxies
199
+ :trusted_proxies => @trusted_proxies
164
200
  ).calculate_ip
165
201
  end
166
202
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Sentry
2
4
  class Error < StandardError
3
5
  end
data/lib/sentry/hub.rb CHANGED
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "sentry/scope"
2
4
  require "sentry/client"
3
5
 
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Sentry
2
4
  module Integrable
3
5
  def register_integration(name:, version:)
@@ -1,15 +1,8 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Sentry
2
4
  class Interface
3
- def self.inherited(klass)
4
- name = klass.name.split("::").last.downcase.gsub("interface", "")
5
- registered[name.to_sym] = klass
6
- super
7
- end
8
-
9
- def self.registered
10
- @@registered ||= {} # rubocop:disable Style/ClassVars
11
- end
12
-
5
+ # @return [Hash]
13
6
  def to_hash
14
7
  Hash[instance_variables.map { |name| [name[1..-1].to_sym, instance_variable_get(name)] }]
15
8
  end
@@ -1,15 +1,25 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Sentry
2
4
  class ExceptionInterface < Interface
3
- def initialize(values:)
4
- @values = values
5
+ # @param exceptions [Array<SingleExceptionInterface>]
6
+ def initialize(exceptions:)
7
+ @values = exceptions
5
8
  end
6
9
 
10
+ # @return [Hash]
7
11
  def to_hash
8
12
  data = super
9
13
  data[:values] = data[:values].map(&:to_hash) if data[:values]
10
14
  data
11
15
  end
12
16
 
17
+ # Builds ExceptionInterface with given exception and stacktrace_builder.
18
+ # @param exception [Exception]
19
+ # @param stacktrace_builder [StacktraceBuilder]
20
+ # @see SingleExceptionInterface#build_with_stacktrace
21
+ # @see SingleExceptionInterface#initialize
22
+ # @return [ExceptionInterface]
13
23
  def self.build(exception:, stacktrace_builder:)
14
24
  exceptions = Sentry::Utils::ExceptionCauseChain.exception_to_array(exception).reverse
15
25
  processed_backtrace_ids = Set.new
@@ -23,7 +33,7 @@ module Sentry
23
33
  end
24
34
  end
25
35
 
26
- new(values: exceptions)
36
+ new(exceptions: exceptions)
27
37
  end
28
38
  end
29
39
  end
@@ -15,29 +15,45 @@ module Sentry
15
15
  # https://github.com/getsentry/sentry/blob/master/src/sentry/conf/server.py
16
16
  MAX_BODY_LIMIT = 4096 * 4
17
17
 
18
- attr_accessor :url, :method, :data, :query_string, :cookies, :headers, :env
18
+ # @return [String]
19
+ attr_accessor :url
19
20
 
20
- def self.build(env:)
21
- env = clean_env(env)
22
- request = ::Rack::Request.new(env)
23
- self.new(request: request)
24
- end
21
+ # @return [String]
22
+ attr_accessor :method
23
+
24
+ # @return [Hash]
25
+ attr_accessor :data
26
+
27
+ # @return [String]
28
+ attr_accessor :query_string
29
+
30
+ # @return [String]
31
+ attr_accessor :cookies
32
+
33
+ # @return [Hash]
34
+ attr_accessor :headers
25
35
 
26
- def self.clean_env(env)
27
- unless Sentry.configuration.send_default_pii
36
+ # @return [Hash]
37
+ attr_accessor :env
38
+
39
+ # @param env [Hash]
40
+ # @param send_default_pii [Boolean]
41
+ # @param rack_env_whitelist [Array]
42
+ # @see Configuration#send_default_pii
43
+ # @see Configuration#rack_env_whitelist
44
+ def initialize(env:, send_default_pii:, rack_env_whitelist:)
45
+ env = env.dup
46
+
47
+ unless send_default_pii
28
48
  # need to completely wipe out ip addresses
29
49
  RequestInterface::IP_HEADERS.each do |header|
30
50
  env.delete(header)
31
51
  end
32
52
  end
33
53
 
34
- env
35
- end
36
-
37
- def initialize(request:)
38
- env = request.env
54
+ request = ::Rack::Request.new(env)
39
55
 
40
- if Sentry.configuration.send_default_pii
56
+ if send_default_pii
41
57
  self.data = read_data_from(request)
42
58
  self.cookies = request.cookies
43
59
  self.query_string = request.query_string
@@ -47,7 +63,7 @@ module Sentry
47
63
  self.method = request.request_method
48
64
 
49
65
  self.headers = filter_and_format_headers(env)
50
- self.env = filter_and_format_env(env)
66
+ self.env = filter_and_format_env(env, rack_env_whitelist)
51
67
  end
52
68
 
53
69
  private
@@ -116,11 +132,11 @@ module Sentry
116
132
  key == 'HTTP_VERSION' && value == protocol_version
117
133
  end
118
134
 
119
- def filter_and_format_env(env)
120
- return env if Sentry.configuration.rack_env_whitelist.empty?
135
+ def filter_and_format_env(env, rack_env_whitelist)
136
+ return env if rack_env_whitelist.empty?
121
137
 
122
138
  env.select do |k, _v|
123
- Sentry.configuration.rack_env_whitelist.include? k.to_s
139
+ rack_env_whitelist.include? k.to_s
124
140
  end
125
141
  end
126
142
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "sentry/utils/exception_cause_chain"
2
4
 
3
5
  module Sentry
@@ -1,15 +1,21 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Sentry
2
4
  class StacktraceInterface
5
+ # @return [<Array[Frame]>]
3
6
  attr_reader :frames
4
7
 
8
+ # @param frames [<Array[Frame]>]
5
9
  def initialize(frames:)
6
10
  @frames = frames
7
11
  end
8
12
 
13
+ # @return [Hash]
9
14
  def to_hash
10
15
  { frames: @frames.map(&:to_hash) }
11
16
  end
12
17
 
18
+ # @return [String]
13
19
  def inspect
14
20
  @frames.map(&:to_s)
15
21
  end
@@ -1,7 +1,32 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Sentry
2
4
  class StacktraceBuilder
3
- attr_reader :project_root, :app_dirs_pattern, :linecache, :context_lines, :backtrace_cleanup_callback
5
+ # @return [String]
6
+ attr_reader :project_root
7
+
8
+ # @return [Regexp, nil]
9
+ attr_reader :app_dirs_pattern
10
+
11
+ # @return [LineCache]
12
+ attr_reader :linecache
13
+
14
+ # @return [Integer, nil]
15
+ attr_reader :context_lines
16
+
17
+ # @return [Proc, nil]
18
+ attr_reader :backtrace_cleanup_callback
4
19
 
20
+ # @param project_root [String]
21
+ # @param app_dirs_pattern [Regexp, nil]
22
+ # @param linecache [LineCache]
23
+ # @param context_lines [Integer, nil]
24
+ # @param backtrace_cleanup_callback [Proc, nil]
25
+ # @see Configuration#project_root
26
+ # @see Configuration#app_dirs_pattern
27
+ # @see Configuration#linecache
28
+ # @see Configuration#context_lines
29
+ # @see Configuration#backtrace_cleanup_callback
5
30
  def initialize(project_root:, app_dirs_pattern:, linecache:, context_lines:, backtrace_cleanup_callback: nil)
6
31
  @project_root = project_root
7
32
  @app_dirs_pattern = app_dirs_pattern
@@ -10,17 +35,21 @@ module Sentry
10
35
  @backtrace_cleanup_callback = backtrace_cleanup_callback
11
36
  end
12
37
 
13
- # you can pass a block to customize/exclude frames:
38
+ # Generates a StacktraceInterface with the given backtrace.
39
+ # You can pass a block to customize/exclude frames:
14
40
  #
15
- # ```ruby
16
- # builder.build(backtrace) do |frame|
17
- # if frame.module.match?(/a_gem/)
18
- # nil
19
- # else
20
- # frame
41
+ # @example
42
+ # builder.build(backtrace) do |frame|
43
+ # if frame.module.match?(/a_gem/)
44
+ # nil
45
+ # else
46
+ # frame
47
+ # end
21
48
  # end
22
- # end
23
- # ```
49
+ # @param backtrace [Array<String>]
50
+ # @param frame_callback [Proc]
51
+ # @yieldparam frame [StacktraceInterface::Frame]
52
+ # @return [StacktraceInterface]
24
53
  def build(backtrace:, &frame_callback)
25
54
  parsed_lines = parse_backtrace_lines(backtrace).select(&:file)
26
55
 
@@ -1,5 +1,9 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Sentry
2
4
  class ThreadsInterface
5
+ # @param crashed [Boolean]
6
+ # @param stacktrace [Array]
3
7
  def initialize(crashed: false, stacktrace: nil)
4
8
  @id = Thread.current.object_id
5
9
  @name = Thread.current.name
@@ -8,6 +12,7 @@ module Sentry
8
12
  @stacktrace = stacktrace
9
13
  end
10
14
 
15
+ # @return [Hash]
11
16
  def to_hash
12
17
  {
13
18
  values: [
@@ -22,8 +27,13 @@ module Sentry
22
27
  }
23
28
  end
24
29
 
25
- # patch this method if you want to change a threads interface's stacktrace frames
26
- # also see `StacktraceBuilder.build`.
30
+ # Builds the ThreadsInterface with given backtrace and stacktrace_builder.
31
+ # Patch this method if you want to change a threads interface's stacktrace frames.
32
+ # @see StacktraceBuilder.build
33
+ # @param backtrace [Array]
34
+ # @param stacktrace_builder [StacktraceBuilder]
35
+ # @param crashed [Hash]
36
+ # @return [ThreadsInterface]
27
37
  def self.build(backtrace:, stacktrace_builder:, **options)
28
38
  stacktrace = stacktrace_builder.build(backtrace: backtrace) if backtrace
29
39
  new(**options, stacktrace: stacktrace)
@@ -1,4 +1,7 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Sentry
4
+ # @api private
2
5
  class LineCache
3
6
  def initialize
4
7
  @cache = {}
@@ -1,6 +1,9 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "net/http"
2
4
 
3
5
  module Sentry
6
+ # @api private
4
7
  module Net
5
8
  module HTTP
6
9
  OP_NAME = "net.http"
@@ -20,90 +23,67 @@ module Sentry
20
23
  # end
21
24
  # ```
22
25
  #
23
- # So when the entire flow looks like this:
24
- #
25
- # 1. #request is called.
26
- # - But because the request hasn't started yet, it calls #start (which then calls #do_start)
27
- # - At this moment @sentry_span is still nil, so #set_sentry_trace_header returns early
28
- # 2. #do_start then creates a new Span and assigns it to @sentry_span
29
- # 3. #request is called for the second time.
30
- # - This time @sentry_span should present. So #set_sentry_trace_header will set the sentry-trace header on the request object
31
- # 4. Once the request finished, it
32
- # - Records a breadcrumb if http_logger is set
33
- # - Finishes the Span inside @sentry_span and clears the instance variable
34
- #
26
+ # So we're only instrumenting request when `Net::HTTP` is already started
35
27
  def request(req, body = nil, &block)
36
- set_sentry_trace_header(req)
28
+ return super unless started?
29
+
30
+ sentry_span = start_sentry_span
31
+ set_sentry_trace_header(req, sentry_span)
37
32
 
38
33
  super.tap do |res|
39
34
  record_sentry_breadcrumb(req, res)
40
- record_sentry_span(req, res)
41
- end
42
- end
43
-
44
- def do_start
45
- super.tap do
46
- start_sentry_span
47
- end
48
- end
49
-
50
- def do_finish
51
- super.tap do
52
- finish_sentry_span
35
+ record_sentry_span(req, res, sentry_span)
53
36
  end
54
37
  end
55
38
 
56
39
  private
57
40
 
58
- def set_sentry_trace_header(req)
59
- return unless @sentry_span
41
+ def set_sentry_trace_header(req, sentry_span)
42
+ return unless sentry_span
60
43
 
61
- trace = Sentry.get_current_client.generate_sentry_trace(@sentry_span)
44
+ trace = Sentry.get_current_client.generate_sentry_trace(sentry_span)
62
45
  req[SENTRY_TRACE_HEADER_NAME] = trace if trace
63
46
  end
64
47
 
65
48
  def record_sentry_breadcrumb(req, res)
66
- if Sentry.initialized? && Sentry.configuration.breadcrumbs_logger.include?(:http_logger)
67
- return if from_sentry_sdk?
68
-
69
- request_info = extract_request_info(req)
70
- crumb = Sentry::Breadcrumb.new(
71
- level: :info,
72
- category: OP_NAME,
73
- type: :info,
74
- data: {
75
- method: request_info[:method],
76
- url: request_info[:url],
77
- status: res.code.to_i
78
- }
79
- )
80
- Sentry.add_breadcrumb(crumb)
81
- end
49
+ return unless Sentry.initialized? && Sentry.configuration.breadcrumbs_logger.include?(:http_logger)
50
+ return if from_sentry_sdk?
51
+
52
+ request_info = extract_request_info(req)
53
+
54
+ crumb = Sentry::Breadcrumb.new(
55
+ level: :info,
56
+ category: OP_NAME,
57
+ type: :info,
58
+ data: {
59
+ status: res.code.to_i,
60
+ **request_info
61
+ }
62
+ )
63
+ Sentry.add_breadcrumb(crumb)
82
64
  end
83
65
 
84
- def record_sentry_span(req, res)
85
- if Sentry.initialized? && @sentry_span
86
- request_info = extract_request_info(req)
87
- @sentry_span.set_description("#{request_info[:method]} #{request_info[:url]}")
88
- @sentry_span.set_data(:status, res.code.to_i)
89
- end
66
+ def record_sentry_span(req, res, sentry_span)
67
+ return unless Sentry.initialized? && sentry_span
68
+
69
+ request_info = extract_request_info(req)
70
+ sentry_span.set_description("#{request_info[:method]} #{request_info[:url]}")
71
+ sentry_span.set_data(:status, res.code.to_i)
72
+ finish_sentry_span(sentry_span)
90
73
  end
91
74
 
92
75
  def start_sentry_span
93
- if Sentry.initialized? && transaction = Sentry.get_current_scope.get_transaction
94
- return if from_sentry_sdk?
95
- return if transaction.sampled == false
76
+ return unless Sentry.initialized? && transaction = Sentry.get_current_scope.get_transaction
77
+ return if from_sentry_sdk?
78
+ return if transaction.sampled == false
96
79
 
97
- child_span = transaction.start_child(op: OP_NAME, start_timestamp: Sentry.utc_now.to_f)
98
- @sentry_span = child_span
99
- end
80
+ transaction.start_child(op: OP_NAME, start_timestamp: Sentry.utc_now.to_f)
100
81
  end
101
82
 
102
- def finish_sentry_span
103
- if Sentry.initialized? && @sentry_span
104
- @sentry_span.set_timestamp(Sentry.utc_now.to_f)
105
- @sentry_span = nil
106
- end
83
+ def finish_sentry_span(sentry_span)
84
+ return unless Sentry.initialized? && sentry_span
85
+
86
+ sentry_span.set_timestamp(Sentry.utc_now.to_f)
107
87
  end
108
88
 
109
89
  def from_sentry_sdk?
@@ -112,9 +92,17 @@ module Sentry
112
92
  end
113
93
 
114
94
  def extract_request_info(req)
115
- uri = req.uri
95
+ uri = req.uri || URI.parse("#{use_ssl? ? 'https' : 'http'}://#{address}#{req.path}")
116
96
  url = "#{uri.scheme}://#{uri.host}#{uri.path}" rescue uri.to_s
117
- { method: req.method, url: url }
97
+
98
+ result = { method: req.method, url: url }
99
+
100
+ if Sentry.configuration.send_default_pii
101
+ result[:url] = result[:url] + "?#{uri.query}"
102
+ result[:body] = req.body
103
+ end
104
+
105
+ result
118
106
  end
119
107
  end
120
108
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Sentry
2
4
  module Rack
3
5
  class CaptureExceptions
data/lib/sentry/rack.rb CHANGED
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'rack'
2
4
 
3
5
  require 'sentry/rack/capture_exceptions'