sentry-ruby-core 6.7.0 → 7.0.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.
Files changed (51) hide show
  1. checksums.yaml +4 -4
  2. data/gemfiles/ruby-2.7_rack-2_redis-4.gemfile.lock +7 -7
  3. data/gemfiles/ruby-2.7_rack-3.1_redis-4.gemfile.lock +7 -7
  4. data/gemfiles/ruby-2.7_rack-3_redis-4.gemfile.lock +7 -7
  5. data/gemfiles/ruby-3.0_rack-2_redis-4.gemfile.lock +8 -8
  6. data/gemfiles/ruby-3.0_rack-3.1_redis-4.gemfile.lock +8 -8
  7. data/gemfiles/ruby-3.0_rack-3_redis-4.gemfile.lock +8 -8
  8. data/gemfiles/ruby-3.1_rack-2_redis-4.gemfile.lock +16 -16
  9. data/gemfiles/ruby-3.1_rack-3.1_redis-4.gemfile.lock +16 -16
  10. data/gemfiles/ruby-3.1_rack-3_redis-4.gemfile.lock +16 -16
  11. data/gemfiles/ruby-3.2_rack-0_redis-5.gemfile.lock +16 -16
  12. data/gemfiles/ruby-3.2_rack-2_redis-4.gemfile.lock +18 -18
  13. data/gemfiles/ruby-3.2_rack-2_redis-5.gemfile.lock +18 -18
  14. data/gemfiles/ruby-3.2_rack-3.1_redis-4.gemfile.lock +18 -18
  15. data/gemfiles/ruby-3.2_rack-3_redis-4.gemfile.lock +18 -18
  16. data/gemfiles/ruby-3.2_rack-3_redis-5.gemfile.lock +18 -18
  17. data/gemfiles/ruby-3.3_rack-2_redis-4.gemfile.lock +22 -22
  18. data/gemfiles/ruby-3.3_rack-3.1_redis-4.gemfile.lock +22 -22
  19. data/gemfiles/ruby-3.3_rack-3.1_redis-5.3.gemfile.lock +22 -22
  20. data/gemfiles/ruby-3.3_rack-3_redis-4.gemfile.lock +22 -22
  21. data/gemfiles/ruby-3.4_rack-2_redis-4.gemfile.lock +22 -22
  22. data/gemfiles/ruby-3.4_rack-3.1_redis-4.gemfile.lock +22 -22
  23. data/gemfiles/ruby-3.4_rack-3.1_redis-5.3.gemfile.lock +22 -22
  24. data/gemfiles/ruby-3.4_rack-3_redis-4.gemfile.lock +22 -22
  25. data/gemfiles/ruby-4.0_rack-2_redis-4.gemfile.lock +22 -22
  26. data/gemfiles/ruby-4.0_rack-3.1_redis-4.gemfile.lock +22 -22
  27. data/gemfiles/ruby-4.0_rack-3_redis-4.gemfile.lock +22 -22
  28. data/gemfiles/ruby-jruby-9.4.14.0_rack-2_redis-4.gemfile.lock +14 -14
  29. data/gemfiles/ruby-jruby-9.4.14.0_rack-3.1_redis-4.gemfile.lock +14 -14
  30. data/gemfiles/ruby-jruby-9.4.14.0_rack-3_redis-4.gemfile.lock +14 -14
  31. data/lib/sentry/client.rb +2 -6
  32. data/lib/sentry/configuration.rb +34 -12
  33. data/lib/sentry/data_collection/key_value_collection.rb +136 -0
  34. data/lib/sentry/data_collection.rb +203 -0
  35. data/lib/sentry/debug_structured_logger.rb +2 -15
  36. data/lib/sentry/error_event.rb +6 -1
  37. data/lib/sentry/event.rb +8 -4
  38. data/lib/sentry/excon/middleware.rb +3 -8
  39. data/lib/sentry/faraday.rb +3 -4
  40. data/lib/sentry/hub.rb +2 -2
  41. data/lib/sentry/interfaces/exception.rb +8 -2
  42. data/lib/sentry/interfaces/request.rb +42 -46
  43. data/lib/sentry/interfaces/single_exception.rb +2 -2
  44. data/lib/sentry/net/http.rb +3 -4
  45. data/lib/sentry/redis.rb +1 -1
  46. data/lib/sentry/std_lib_logger.rb +2 -6
  47. data/lib/sentry/test_helper.rb +2 -4
  48. data/lib/sentry/utils/http_tracing.rb +42 -26
  49. data/lib/sentry/version.rb +1 -1
  50. data/lib/sentry-ruby.rb +4 -18
  51. metadata +5 -3
@@ -6,7 +6,7 @@ GIT
6
6
  PATH
7
7
  remote: ..
8
8
  specs:
9
- sentry-ruby (6.6.2)
9
+ sentry-ruby (6.7.0)
10
10
  bigdecimal
11
11
  concurrent-ruby (~> 1.0, >= 1.0.2)
12
12
  logger
@@ -70,14 +70,14 @@ GEM
70
70
  faraday-net_http (3.4.4)
71
71
  net-http (~> 0.5)
72
72
  fiber-storage (1.0.1)
73
- graphql (2.6.7)
73
+ graphql (2.6.9)
74
74
  base64
75
75
  fiber-storage
76
76
  logger
77
77
  hashdiff (1.2.1)
78
78
  i18n (1.15.2)
79
79
  concurrent-ruby (~> 1.0)
80
- io-console (0.8.2-java)
80
+ io-console (0.9.2-java)
81
81
  irb (1.18.0)
82
82
  pp (>= 0.6.0)
83
83
  prism (>= 1.3.0)
@@ -97,20 +97,20 @@ GEM
97
97
  prettyprint
98
98
  prettyprint (0.2.0)
99
99
  prism (1.9.0)
100
- psych (5.4.0-java)
100
+ psych (5.5.0-java)
101
101
  date
102
102
  jar-dependencies (>= 0.1.7)
103
103
  public_suffix (6.0.2)
104
104
  puma (8.0.2-java)
105
105
  nio4r (~> 2.0)
106
- rack (3.2.6)
106
+ rack (3.2.7)
107
107
  rake (12.3.3)
108
108
  rdoc (7.2.0)
109
109
  erb
110
110
  psych (>= 4.0.0)
111
111
  tsort
112
112
  redis (4.8.1)
113
- reline (0.6.3)
113
+ reline (0.7.0)
114
114
  io-console (~> 0.5)
115
115
  rexml (3.4.1)
116
116
  rspec (3.13.2)
@@ -146,7 +146,7 @@ GEM
146
146
  tzinfo (2.0.6)
147
147
  concurrent-ruby (~> 1.0)
148
148
  uri (1.1.1)
149
- webmock (3.26.2)
149
+ webmock (3.26.3)
150
150
  addressable (>= 2.8.0)
151
151
  crack (>= 0.3.2)
152
152
  hashdiff (>= 0.4.0, < 2.0.0)
@@ -214,10 +214,10 @@ CHECKSUMS
214
214
  faraday (2.14.3) sha256=1882247e6766615c8220b4392bf1d27f6ebb63d8e28267587cef1fb0bf37f278
215
215
  faraday-net_http (3.4.4) sha256=0e78af151747ed1b00f33e25973b4bc220d7f16c00c39676817c8b12331eb588
216
216
  fiber-storage (1.0.1) sha256=f48e5b6d8b0be96dac486332b55cee82240057065dc761c1ea692b2e719240e1
217
- graphql (2.6.7) sha256=759755ce5819c965b6459c5039605cf2e4d876bb8ba5e03451676870ea787c45
217
+ graphql (2.6.9) sha256=afe7bc03164f1a61abc66a415744ffd315c5aca116c9f3438c57391a431e4fe5
218
218
  hashdiff (1.2.1) sha256=9c079dbc513dfc8833ab59c0c2d8f230fa28499cc5efb4b8dd276cf931457cd1
219
219
  i18n (1.15.2) sha256=00f9eb62412fe593b2a65a97daa75300d37abb8f7202ec748e94b6d46a9dd1b5
220
- io-console (0.8.2-java) sha256=837efefe96084c13ae91114917986ae6c6d1cf063b27b8419cc564a722a38af8
220
+ io-console (0.9.2-java) sha256=929c09163ad227cda17f5dc57861b995dbecf69c7ca2ce7b0c5f941f1f3da7d3
221
221
  irb (1.18.0) sha256=de9454a0703a54704b9811a5ef31a60c86949fbf4013fcf244fabc7c775248e3
222
222
  jar-dependencies (0.5.7) sha256=013ce5f4639414ac8cf1169cdbe763da164b81e2d2c983d11042b5ff7bfcce80
223
223
  jdbc-mysql (8.4.0.1) sha256=429cb7999d11c4f46a7153a382b6ac07935a4c10ddc52dd98e2d52b22c17fa13
@@ -231,14 +231,14 @@ CHECKSUMS
231
231
  pp (0.6.4) sha256=dfcb0fce700c41456265922884f9fe195d7fbb0674a3578e6c0f69588e82b570
232
232
  prettyprint (0.2.0) sha256=2bc9e15581a94742064a3cc8b0fb9d45aae3d03a1baa6ef80922627a0766f193
233
233
  prism (1.9.0) sha256=7b530c6a9f92c24300014919c9dcbc055bf4cdf51ec30aed099b06cd6674ef85
234
- psych (5.4.0-java) sha256=5f948b27c94be491e6ae3e19484700fe87b7bea75f91a5ab8cdf18bb215b1a3b
234
+ psych (5.5.0-java) sha256=3b7cf3684c44d049c3dee87ec4118ec9cd6ac714cbdcfba386997f96dbbd36ab
235
235
  public_suffix (6.0.2) sha256=bfa7cd5108066f8c9602e0d6d4114999a5df5839a63149d3e8b0f9c1d3558394
236
236
  puma (8.0.2-java) sha256=37392e0dbd01e2a157748b92b818bfacf801bb32628e41680e9ab1171dea2b3d
237
- rack (3.2.6) sha256=5ed78e1f73b2e25679bec7d45ee2d4483cc4146eb1be0264fc4d94cb5ef212c2
237
+ rack (3.2.7) sha256=93e13e1c24f93556671d85d2d79fa228c3485815c50d7e2f265b5330c6528fb7
238
238
  rake (12.3.3) sha256=f7694adb4fe638da35452300cee6c545e9c377a0e3190018ac04d590b3c26ab3
239
239
  rdoc (7.2.0) sha256=8650f76cd4009c3b54955eb5d7e3a075c60a57276766ebf36f9085e8c9f23192
240
240
  redis (4.8.1) sha256=387ee086694fffc9632aaeb1efe4a7b1627ca783bf373320346a8a20cd93333a
241
- reline (0.6.3) sha256=1198b04973565b36ec0f11542ab3f5cfeeec34823f4e54cebde90968092b1835
241
+ reline (0.7.0) sha256=5b012d8e55dbf9d450f12bde2cf7d15ff546ae80b3f8f3b30e570d431815583d
242
242
  rexml (3.4.1) sha256=c74527a9a0a04b4ec31dbe0dc4ed6004b960af943d8db42e539edde3a871abca
243
243
  rspec (3.13.2) sha256=206284a08ad798e61f86d7ca3e376718d52c0bc944626b2349266f239f820587
244
244
  rspec-core (3.13.6) sha256=a8823c6411667b60a8bca135364351dda34cd55e44ff94c4be4633b37d828b2d
@@ -247,7 +247,7 @@ CHECKSUMS
247
247
  rspec-retry (0.6.2) sha256=6101ba23a38809811ae3484acde4ab481c54d846ac66d5037ccb40131a60d858
248
248
  rspec-support (3.13.7) sha256=0640e5570872aafefd79867901deeeeb40b0c9875a36b983d85f54fb7381c47c
249
249
  securerandom (0.4.1) sha256=cc5193d414a4341b6e225f0cb4446aceca8e50d5e1888743fac16987638ea0b1
250
- sentry-ruby (6.6.2)
250
+ sentry-ruby (6.7.0)
251
251
  sequel (5.107.0) sha256=019629313205295b007f6df2c5eab19ddc40710d549fd445ac300f2853a370db
252
252
  simplecov (0.22.0) sha256=fe2622c7834ff23b98066bb0a854284b2729a569ac659f82621fc22ef36213a5
253
253
  simplecov-cobertura (3.2.0) sha256=70d702658677fcb20e5aceb6915ccf8bc62ff2ccd38b62b3ad5c9db5c0888740
@@ -258,7 +258,7 @@ CHECKSUMS
258
258
  tsort (0.2.0) sha256=9650a793f6859a43b6641671278f79cfead60ac714148aabe4e3f0060480089f
259
259
  tzinfo (2.0.6) sha256=8daf828cc77bcf7d63b0e3bdb6caa47e2272dcfaf4fbfe46f8c3a9df087a829b
260
260
  uri (1.1.1) sha256=379fa58d27ffb1387eaada68c749d1426738bd0f654d812fcc07e7568f5c57c6
261
- webmock (3.26.2) sha256=774556f2ea6371846cca68c01769b2eac0d134492d21f6d0ab5dd643965a4c90
261
+ webmock (3.26.3) sha256=77c612816bdcb2fc43db0e42fd98b19be7d4770fd708816fdde65a006664ddec
262
262
  webrick (1.9.2) sha256=beb4a15fc474defed24a3bda4ffd88a490d517c9e4e6118c3edce59e45864131
263
263
  yard (0.9.45) sha256=52e211493f7cb8a3ebf7e104a25a1e73937a3103092545d34cb88fafebb3dc51
264
264
 
data/lib/sentry/client.rb CHANGED
@@ -48,13 +48,9 @@ module Sentry
48
48
 
49
49
  @spotlight_transport = SpotlightTransport.new(configuration) if configuration.spotlight
50
50
 
51
- if configuration.enable_logs
52
- @log_event_buffer = LogEventBuffer.new(configuration, self)
53
- end
51
+ @log_event_buffer = LogEventBuffer.new(configuration, self)
54
52
 
55
- if configuration.enable_metrics
56
- @metric_event_buffer = MetricEventBuffer.new(configuration, self)
57
- end
53
+ @metric_event_buffer = MetricEventBuffer.new(configuration, self)
58
54
  end
59
55
 
60
56
  # Applies the given scope's data to the event and sends it to Sentry.
@@ -16,6 +16,7 @@ require "sentry/logger"
16
16
  require "sentry/structured_logger"
17
17
  require "sentry/log_event_buffer"
18
18
  require "sentry/metric_event_buffer"
19
+ require "sentry/data_collection"
19
20
 
20
21
  module Sentry
21
22
  class Configuration
@@ -132,6 +133,7 @@ module Sentry
132
133
  attr_accessor :max_breadcrumbs
133
134
 
134
135
  # Number of lines of code context to capture, or nil for none
136
+ # @deprecated Use {#data_collection} and `frame_context_lines` instead.
135
137
  # @return [Integer, nil]
136
138
  attr_accessor :context_lines
137
139
 
@@ -167,8 +169,14 @@ module Sentry
167
169
  alias inspect_exception_causes_for_exclusion? inspect_exception_causes_for_exclusion
168
170
 
169
171
  # Whether to capture local variables from the raised exception's frame. Default is false.
172
+ # @deprecated Use {#data_collection} and `stack_frame_variables` instead.
170
173
  # @return [Boolean]
171
- attr_accessor :include_local_variables
174
+ attr_reader :include_local_variables
175
+
176
+ def include_local_variables=(value)
177
+ @include_local_variables = value
178
+ @data_collection.backfill_stack_frame_variables(self)
179
+ end
172
180
 
173
181
  # Whether to capture events and traces into Spotlight. Default is false.
174
182
  # If you set this to true, Sentry will send events and traces to the local
@@ -209,6 +217,7 @@ module Sentry
209
217
  attr_accessor :propagate_traces
210
218
 
211
219
  # Array of rack env parameters to be included in the event sent to sentry.
220
+ # @deprecated Use `data_collection.http_headers.request` to control request data collection instead.
212
221
  # @return [Array<String>]
213
222
  attr_accessor :rack_env_whitelist
214
223
 
@@ -232,8 +241,14 @@ module Sentry
232
241
  # - request body
233
242
  # - query string
234
243
  # will not be sent to Sentry.
244
+ # @deprecated Use {#data_collection} instead.
235
245
  # @return [Boolean]
236
- attr_accessor :send_default_pii
246
+ attr_reader :send_default_pii
247
+
248
+ # Controls which categories of data may be collected.
249
+ # Replacement for send_default_pii.
250
+ # @return [DataCollection]
251
+ attr_accessor :data_collection
237
252
 
238
253
  # Capture queue time from X-Request-Start header set by reverse proxies.
239
254
  # Works with any Rack app behind Nginx, HAProxy, Heroku router, etc.
@@ -273,10 +288,6 @@ module Sentry
273
288
  # @return [Proc]
274
289
  attr_accessor :traces_sampler
275
290
 
276
- # Enable Structured Logging
277
- # @return [Boolean]
278
- attr_accessor :enable_logs
279
-
280
291
  # Structured logging configuration.
281
292
  # @return [StructuredLoggingConfiguration]
282
293
  attr_reader :structured_logging
@@ -345,10 +356,6 @@ module Sentry
345
356
  # @return [Integer]
346
357
  attr_accessor :max_log_events
347
358
 
348
- # Enable metrics collection, defaults to true
349
- # @return [Boolean]
350
- attr_accessor :enable_metrics
351
-
352
359
  # Maximum number of metric events to buffer before sending
353
360
  # @return [Integer]
354
361
  attr_accessor :max_metric_events
@@ -527,6 +534,7 @@ module Sentry
527
534
  def initialize
528
535
  run_callbacks(:before, :initialize)
529
536
 
537
+ self.data_collection = DataCollection.new
530
538
  self.app_dirs_pattern = APP_DIRS_PATTERN
531
539
  self.debug = Sentry::Utils::EnvHelper.env_to_bool(ENV["SENTRY_DEBUG"])
532
540
  self.background_worker_threads = (processor_count / 2.0).ceil
@@ -537,6 +545,7 @@ module Sentry
537
545
  self.breadcrumbs_logger = []
538
546
  self.context_lines = 3
539
547
  self.include_local_variables = false
548
+
540
549
  self.environment = environment_from_env
541
550
  self.enabled_environments = nil
542
551
  self.exclude_loggers = []
@@ -578,8 +587,6 @@ module Sentry
578
587
  self.std_lib_logger_filter = nil
579
588
  self.rack_env_whitelist = RACK_ENV_WHITELIST_DEFAULT
580
589
  self.traces_sampler = nil
581
- self.enable_logs = false
582
- self.enable_metrics = true
583
590
 
584
591
  self.profiler_class = Sentry::Profiler
585
592
  self.profiles_sample_interval = DEFAULT_PROFILES_SAMPLE_INTERVAL
@@ -596,6 +603,8 @@ module Sentry
596
603
 
597
604
  yield(self) if block_given?
598
605
 
606
+ log_deprecations
607
+
599
608
  run_callbacks(:after, :configured)
600
609
  end
601
610
 
@@ -621,6 +630,11 @@ module Sentry
621
630
  @dsn = init_dsn(value)
622
631
  end
623
632
 
633
+ def send_default_pii=(value)
634
+ @send_default_pii = value
635
+ self.data_collection = DataCollection.backfill(self)
636
+ end
637
+
624
638
  alias server= dsn=
625
639
 
626
640
  def release=(value)
@@ -804,6 +818,14 @@ module Sentry
804
818
  end
805
819
  end
806
820
 
821
+ # @api private
822
+ def log_deprecations
823
+ log_warn("`send_default_pii` is deprecated; use `data_collection` instead.") if self.send_default_pii
824
+ log_warn("`include_local_variables` is deprecated; use `data_collection.stack_frame_variables` instead.") if include_local_variables
825
+ log_warn("`context_lines` is deprecated; use `data_collection.frame_context_lines` instead.") if context_lines != 3
826
+ log_warn("`rack_env_whitelist` is deprecated; use `data_collection.http_headers.request` to control request data collection instead.") if rack_env_whitelist != RACK_ENV_WHITELIST_DEFAULT
827
+ end
828
+
807
829
  # @api private
808
830
  def stacktrace_builder
809
831
  @stacktrace_builder ||= StacktraceBuilder.new(
@@ -0,0 +1,136 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Sentry
4
+ class DataCollection
5
+ # Configuration for key-value data collection.
6
+ class KeyValueCollection
7
+ FILTERED_VALUE = "[Filtered]"
8
+
9
+ # Keys from this list are ALWAYS filtered, regardless of :mode
10
+ SENSITIVE_DENY_LIST = %w[
11
+ auth
12
+ token
13
+ secret
14
+ session
15
+ password
16
+ passwd
17
+ pwd
18
+ key
19
+ jwt
20
+ bearer
21
+ sso
22
+ saml
23
+ csrf
24
+ xsrf
25
+ credentials
26
+ sid
27
+ identity
28
+ cookie
29
+ set-cookie
30
+ ].freeze
31
+
32
+ # Additional terms applied to cookie names only. These cover common
33
+ # opaque session, identity-provider, and load-balancer cookies without
34
+ # making the general header denylist overly broad.
35
+ SENSITIVE_COOKIE_NAME_DENY_LIST = %w[
36
+ .sid
37
+ sessid
38
+ remember
39
+ oidc
40
+ pkce
41
+ nonce
42
+ __secure-
43
+ __host-
44
+ awsalb
45
+ awselb
46
+ akamai
47
+ __stripe
48
+ cognito
49
+ firebase
50
+ supabase
51
+ sb-
52
+ mfa
53
+ 2fa
54
+ ].freeze
55
+
56
+ # `mode` controls whether values are collected:
57
+ # - `:off` disables collection.
58
+ # - `:deny_list` collects values except those matching `terms`.
59
+ # - `:allow_list` collects only values matching `terms`.
60
+ # Boolean values are accepted as shorthand for `:deny_list` and `:off`.
61
+ # @return [:off, :deny_list, :allow_list]
62
+ attr_reader :mode
63
+
64
+ # `terms` contains the keys or patterns used by the selected mode.
65
+ # @return [Array<String, Regexp>, nil]
66
+ attr_reader :terms
67
+
68
+ def initialize(mode:, terms:)
69
+ self.mode = mode
70
+ self.terms = terms
71
+ end
72
+
73
+ def mode=(mode)
74
+ @mode = case mode
75
+ when true then :deny_list
76
+ when false, nil then :off
77
+ else mode
78
+ end
79
+ end
80
+
81
+ # Converts the boolean shorthand into a collection configuration.
82
+ def self.from(value)
83
+ return new(mode: value, terms: nil) if value.equal?(true) || value.equal?(false) || value.nil?
84
+
85
+ value
86
+ end
87
+
88
+ def terms=(terms)
89
+ @terms = terms&.map { |term| term.is_a?(Regexp) ? term : term.to_s.downcase }
90
+ &.reject { |term| !term.is_a?(Regexp) && term.strip.empty? }
91
+ end
92
+
93
+ # Applies this collection configuration without changing the input hash.
94
+ # Keys are retained whenever the category is collected; values that are not
95
+ # safe to send are replaced with FILTERED_VALUE.
96
+ #
97
+ # @param values [Hash] key-value data to filter
98
+ # @return [Hash] a new filtered hash, or an empty hash when collection is off
99
+ def filter(values, cookie: false)
100
+ return {} if mode == :off
101
+
102
+ values.each_with_object({}) do |(key, value), filtered|
103
+ filtered[key] = safe_value?(key, cookie: cookie) ? value : FILTERED_VALUE
104
+ end
105
+ end
106
+
107
+ private
108
+
109
+ def safe_value?(key, cookie: false)
110
+ key_string = key.to_s
111
+ key_downcase = key_string.downcase
112
+ return false if sensitive?(key_downcase, cookie: cookie)
113
+
114
+ case mode
115
+ when :deny_list
116
+ !matches_any_term?(key_string, key_downcase)
117
+ when :allow_list
118
+ matches_any_term?(key_string, key_downcase)
119
+ else
120
+ false
121
+ end
122
+ end
123
+
124
+ def sensitive?(key, cookie: false)
125
+ SENSITIVE_DENY_LIST.any? { |term| key.include?(term) } ||
126
+ (cookie && SENSITIVE_COOKIE_NAME_DENY_LIST.any? { |term| key.include?(term) })
127
+ end
128
+
129
+ def matches_any_term?(key, key_downcase)
130
+ @terms&.any? do |term|
131
+ term.is_a?(Regexp) ? term.match?(key) : key_downcase.include?(term)
132
+ end
133
+ end
134
+ end
135
+ end
136
+ end
@@ -0,0 +1,203 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "sentry/data_collection/key_value_collection"
4
+
5
+ module Sentry
6
+ class DataCollection
7
+ # Configuration for the categories of data collected by the SDK.
8
+ # Replacement for send_default_pii.
9
+ # Spec: https://develop.sentry.dev/sdk/foundations/client/data-collection/
10
+ #
11
+ # @example Configure data collection
12
+ # Sentry.init do |config|
13
+ # data_collection = config.data_collection
14
+ # data_collection.user_info = true
15
+ # data_collection.cookies.mode = :deny_list
16
+ # data_collection.cookies.terms = ["session", "token"]
17
+ # data_collection.http_headers.request.mode = :deny_list
18
+ # data_collection.http_headers.request.terms = nil
19
+ # data_collection.http_headers.response.mode = :allow_list
20
+ # data_collection.http_headers.response.terms = ["my_special_header"]
21
+ # data_collection.http_bodies = [:incoming_request]
22
+ # data_collection.url_query_params.mode = :allow_list
23
+ # data_collection.url_query_params.terms = ["page", "limit"]
24
+ # data_collection.graphql.document = true
25
+ # data_collection.graphql.variables = true
26
+ # data_collection.database_query_data = true
27
+ # data_collection.queues = true
28
+ # data_collection.stack_frame_variables = true
29
+ # data_collection.frame_context_lines = 5
30
+ # end
31
+
32
+ MODES = %i[off deny_list allow_list].freeze
33
+
34
+ PII_HEADER_SNIPPETS = %w[forwarded -ip _ip remote via _user -user].freeze
35
+
36
+ BODY_TYPES = %i[
37
+ incoming_request
38
+ outgoing_request
39
+ incoming_response
40
+ outgoing_response
41
+ ].freeze
42
+
43
+ class HttpHeaders
44
+ # @return [KeyValueCollection]
45
+ attr_reader :request
46
+
47
+ # @return [KeyValueCollection]
48
+ attr_reader :response
49
+
50
+ def initialize(request:, response:)
51
+ self.request = request
52
+ self.response = response
53
+ end
54
+
55
+ def request=(value)
56
+ @request = KeyValueCollection.from(value)
57
+ end
58
+
59
+ def response=(value)
60
+ @response = KeyValueCollection.from(value)
61
+ end
62
+ end
63
+
64
+ class GraphQL
65
+ # @return [Boolean]
66
+ attr_accessor :document
67
+
68
+ # @return [Boolean]
69
+ attr_accessor :variables
70
+
71
+ def initialize(document:, variables:)
72
+ @document = document
73
+ @variables = variables
74
+ end
75
+ end
76
+
77
+ # @return [Boolean]
78
+ # @default `true`
79
+ attr_accessor :user_info
80
+
81
+ # @return [Boolean, KeyValueCollection]
82
+ # A boolean is shorthand for `mode: :deny_list` (`true`) or `mode: :off` (`false`).
83
+ # @default `mode: :deny_list, terms: nil`
84
+ attr_reader :cookies
85
+
86
+ # @return [HttpHeaders]
87
+ # @default request and response use `mode: :deny_list, terms: nil`
88
+ attr_accessor :http_headers
89
+
90
+ # @return [Array<Symbol>] containing values from BODY_TYPES
91
+ # @default `nil` (all valid body types)
92
+ attr_accessor :http_bodies
93
+
94
+ # @return [Boolean, KeyValueCollection]
95
+ # A boolean is shorthand for `mode: :deny_list` (`true`) or `mode: :off` (`false`).
96
+ # @default `mode: :deny_list, terms: nil`
97
+ attr_reader :url_query_params
98
+
99
+ # @return [Boolean]
100
+ # @default `true`
101
+ attr_accessor :database_query_data
102
+
103
+ # @return [GraphQL]
104
+ # @default `document: true, variables: true`
105
+ attr_accessor :graphql
106
+
107
+ # @return [Boolean]
108
+ # @default `true`
109
+ attr_accessor :queues
110
+
111
+ # @return [Boolean, KeyValueCollection]
112
+ # A boolean is shorthand for `mode: :deny_list` (`true`) or `mode: :off` (`false`).
113
+ # @default `false` (Ruby-specific to avoid TracePoint overhead)
114
+ attr_reader :stack_frame_variables
115
+
116
+ # @return [Integer]
117
+ # @default `3`
118
+ attr_accessor :frame_context_lines
119
+
120
+ # Filters key-value data using the default sensitive denylist.
121
+ def self.filter(values)
122
+ default_filter.filter(values, cookie: false)
123
+ end
124
+
125
+ def self.default_filter
126
+ @default_filter ||= KeyValueCollection.new(mode: :deny_list, terms: nil)
127
+ end
128
+
129
+ # Builds data collection settings compatible with the legacy send_default_pii
130
+ # configuration.
131
+ def self.backfill(configuration)
132
+ data_collection = new
133
+ data_collection.backfill_stack_frame_variables(configuration)
134
+ return data_collection if configuration.send_default_pii
135
+
136
+ # TODO-neel-data map to exact ruby behaviour for backwards compat behavior
137
+ data_collection.user_info = false
138
+ data_collection.cookies.mode = :off
139
+ data_collection.http_headers.request.mode = :deny_list
140
+ data_collection.http_headers.request.terms = PII_HEADER_SNIPPETS
141
+ data_collection.http_headers.response.mode = :deny_list
142
+ data_collection.http_headers.response.terms = PII_HEADER_SNIPPETS
143
+ data_collection.http_bodies = []
144
+ data_collection.url_query_params.mode = :off
145
+ data_collection.graphql.document = false
146
+ data_collection.graphql.variables = false
147
+ data_collection.database_query_data = false
148
+ data_collection.queues = false
149
+ data_collection.frame_context_lines = configuration.context_lines
150
+ data_collection
151
+ end
152
+
153
+ def initialize
154
+ @user_info = true
155
+ self.cookies = KeyValueCollection.new(mode: :deny_list, terms: nil)
156
+ @http_headers = HttpHeaders.new(
157
+ request: KeyValueCollection.new(mode: :deny_list, terms: nil),
158
+ response: KeyValueCollection.new(mode: :deny_list, terms: nil)
159
+ )
160
+ @http_bodies = BODY_TYPES.dup
161
+ self.url_query_params = KeyValueCollection.new(mode: :deny_list, terms: nil)
162
+ @database_query_data = true
163
+ @graphql = GraphQL.new(document: true, variables: true)
164
+ @queues = true
165
+ self.stack_frame_variables = false
166
+ @frame_context_lines = 3
167
+ end
168
+
169
+ # Copies the legacy stack frame variable configuration.
170
+ def backfill_stack_frame_variables(configuration)
171
+ self.stack_frame_variables = configuration.include_local_variables
172
+ end
173
+
174
+ # Returns whether stack frame local variables should be captured.
175
+ def collect_stack_frame_variables?
176
+ stack_frame_variables.mode != :off
177
+ end
178
+
179
+ def stack_frame_variables=(value)
180
+ @stack_frame_variables = KeyValueCollection.from(value)
181
+ end
182
+
183
+ def cookies=(value)
184
+ @cookies = KeyValueCollection.from(value)
185
+ end
186
+
187
+ def url_query_params=(value)
188
+ @url_query_params = KeyValueCollection.from(value)
189
+ end
190
+
191
+ # Returns whether incoming HTTP request bodies should be collected.
192
+ # nil implies all BODY_TYPES according to spec
193
+ def collect_incoming_http_body?
194
+ http_bodies.nil? || http_bodies.include?(:incoming_request)
195
+ end
196
+
197
+ # Returns whether outgoing HTTP request bodies should be collected.
198
+ # nil implies all BODY_TYPES according to spec
199
+ def collect_outgoing_http_body?
200
+ http_bodies.nil? || http_bodies.include?(:outgoing_request)
201
+ end
202
+ end
203
+ end
@@ -8,8 +8,7 @@ require "delegate"
8
8
  module Sentry
9
9
  # DebugStructuredLogger is a logger that captures structured log events to a file for debugging purposes.
10
10
  #
11
- # It can optionally also send log events to Sentry via the normal structured logger if logging
12
- # is enabled.
11
+ # It also sends log events to Sentry via the normal structured logger.
13
12
  class DebugStructuredLogger < SimpleDelegator
14
13
  DEFAULT_LOG_FILE_PATH = File.join("log", "sentry_debug_logs.log")
15
14
 
@@ -68,12 +67,7 @@ module Sentry
68
67
  private
69
68
 
70
69
  def initialize_backend(configuration)
71
- if configuration.enable_logs
72
- StructuredLogger.new(configuration)
73
- else
74
- # Create a no-op logger if logging is disabled
75
- NoOpLogger.new
76
- end
70
+ StructuredLogger.new(configuration)
77
71
  end
78
72
 
79
73
  def initialize_log_file(log_file_path)
@@ -83,12 +77,5 @@ module Sentry
83
77
 
84
78
  log_file
85
79
  end
86
-
87
- # No-op logger for when structured logging is disabled
88
- class NoOpLogger
89
- %i[trace debug info warn error fatal log].each do |method|
90
- define_method(method) { |*args, **kwargs| nil }
91
- end
92
- end
93
80
  end
94
81
  end
@@ -32,7 +32,12 @@ module Sentry
32
32
  @extra.merge!(exception.sentry_context)
33
33
  end
34
34
 
35
- @exception = Sentry::ExceptionInterface.build(exception: exception, stacktrace_builder: @stacktrace_builder, mechanism: mechanism)
35
+ @exception = Sentry::ExceptionInterface.build(
36
+ exception: exception,
37
+ stacktrace_builder: @stacktrace_builder,
38
+ mechanism: mechanism,
39
+ data_collection: @data_collection
40
+ )
36
41
  end
37
42
  end
38
43
  end
data/lib/sentry/event.rb CHANGED
@@ -28,7 +28,7 @@ module Sentry
28
28
 
29
29
  MAX_MESSAGE_SIZE_IN_BYTES = 1024 * 8
30
30
 
31
- SKIP_INSPECTION_ATTRIBUTES = [:@modules, :@stacktrace_builder, :@send_default_pii, :@trusted_proxies, :@rack_env_whitelist]
31
+ SKIP_INSPECTION_ATTRIBUTES = [:@modules, :@stacktrace_builder, :@data_collection, :@trusted_proxies, :@rack_env_whitelist]
32
32
 
33
33
  include CustomInspection
34
34
 
@@ -73,7 +73,7 @@ module Sentry
73
73
  @modules = configuration.gem_specs if configuration.send_modules
74
74
 
75
75
  # configuration options to help events process data
76
- @send_default_pii = configuration.send_default_pii
76
+ @data_collection = configuration.data_collection
77
77
  @trusted_proxies = configuration.trusted_proxies
78
78
  @stacktrace_builder = configuration.stacktrace_builder
79
79
  @rack_env_whitelist = configuration.rack_env_whitelist
@@ -103,7 +103,7 @@ module Sentry
103
103
  unless request || env.empty?
104
104
  add_request_interface(env)
105
105
 
106
- user[:ip_address] ||= calculate_real_ip_from_rack(env) if @send_default_pii
106
+ user[:ip_address] ||= calculate_real_ip_from_rack(env) if @data_collection.user_info
107
107
 
108
108
  if request_id = Utils::RequestId.read_from(env)
109
109
  tags[:request_id] = request_id
@@ -127,7 +127,11 @@ module Sentry
127
127
  private
128
128
 
129
129
  def add_request_interface(env)
130
- @request = Sentry::RequestInterface.new(env: env, send_default_pii: @send_default_pii, rack_env_whitelist: @rack_env_whitelist)
130
+ @request = Sentry::RequestInterface.new(
131
+ env: env,
132
+ data_collection: @data_collection,
133
+ rack_env_whitelist: @rack_env_whitelist
134
+ )
131
135
  end
132
136
 
133
137
  def serialize_attributes