sentry-ruby 5.26.0 → 6.1.1

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 (60) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +2 -4
  3. data/README.md +1 -1
  4. data/lib/sentry/background_worker.rb +1 -4
  5. data/lib/sentry/backtrace/line.rb +99 -0
  6. data/lib/sentry/backtrace.rb +44 -76
  7. data/lib/sentry/breadcrumb.rb +1 -1
  8. data/lib/sentry/breadcrumb_buffer.rb +2 -2
  9. data/lib/sentry/check_in_event.rb +2 -2
  10. data/lib/sentry/client.rb +39 -89
  11. data/lib/sentry/configuration.rb +125 -78
  12. data/lib/sentry/cron/monitor_check_ins.rb +3 -3
  13. data/lib/sentry/cron/monitor_config.rb +2 -2
  14. data/lib/sentry/cron/monitor_schedule.rb +2 -2
  15. data/lib/sentry/debug_structured_logger.rb +94 -0
  16. data/lib/sentry/dsn.rb +32 -0
  17. data/lib/sentry/envelope/item.rb +1 -2
  18. data/lib/sentry/error_event.rb +3 -3
  19. data/lib/sentry/event.rb +4 -10
  20. data/lib/sentry/graphql.rb +1 -1
  21. data/lib/sentry/hub.rb +6 -5
  22. data/lib/sentry/interface.rb +1 -1
  23. data/lib/sentry/interfaces/exception.rb +2 -2
  24. data/lib/sentry/interfaces/request.rb +2 -0
  25. data/lib/sentry/interfaces/single_exception.rb +3 -3
  26. data/lib/sentry/interfaces/stacktrace.rb +3 -3
  27. data/lib/sentry/interfaces/stacktrace_builder.rb +0 -8
  28. data/lib/sentry/interfaces/threads.rb +2 -2
  29. data/lib/sentry/log_event.rb +19 -6
  30. data/lib/sentry/profiler.rb +4 -5
  31. data/lib/sentry/propagation_context.rb +55 -18
  32. data/lib/sentry/rspec.rb +1 -1
  33. data/lib/sentry/span.rb +2 -17
  34. data/lib/sentry/std_lib_logger.rb +6 -1
  35. data/lib/sentry/test_helper.rb +23 -0
  36. data/lib/sentry/transaction.rb +72 -95
  37. data/lib/sentry/transaction_event.rb +4 -9
  38. data/lib/sentry/transport/debug_transport.rb +70 -0
  39. data/lib/sentry/transport/dummy_transport.rb +1 -0
  40. data/lib/sentry/transport/http_transport.rb +9 -5
  41. data/lib/sentry/transport.rb +3 -5
  42. data/lib/sentry/utils/encoding_helper.rb +7 -0
  43. data/lib/sentry/utils/logging_helper.rb +8 -6
  44. data/lib/sentry/utils/sample_rand.rb +97 -0
  45. data/lib/sentry/vernier/profiler.rb +4 -3
  46. data/lib/sentry/version.rb +1 -1
  47. data/lib/sentry-ruby.rb +6 -30
  48. data/sentry-ruby-core.gemspec +1 -1
  49. data/sentry-ruby.gemspec +1 -1
  50. metadata +12 -18
  51. data/lib/sentry/metrics/aggregator.rb +0 -248
  52. data/lib/sentry/metrics/configuration.rb +0 -47
  53. data/lib/sentry/metrics/counter_metric.rb +0 -25
  54. data/lib/sentry/metrics/distribution_metric.rb +0 -25
  55. data/lib/sentry/metrics/gauge_metric.rb +0 -35
  56. data/lib/sentry/metrics/local_aggregator.rb +0 -53
  57. data/lib/sentry/metrics/metric.rb +0 -19
  58. data/lib/sentry/metrics/set_metric.rb +0 -28
  59. data/lib/sentry/metrics/timing.rb +0 -51
  60. data/lib/sentry/metrics.rb +0 -56
@@ -9,10 +9,10 @@ require "sentry/dsn"
9
9
  require "sentry/release_detector"
10
10
  require "sentry/transport/configuration"
11
11
  require "sentry/cron/configuration"
12
- require "sentry/metrics/configuration"
13
12
  require "sentry/linecache"
14
13
  require "sentry/interfaces/stacktrace_builder"
15
14
  require "sentry/logger"
15
+ require "sentry/structured_logger"
16
16
  require "sentry/log_event_buffer"
17
17
 
18
18
  module Sentry
@@ -30,13 +30,6 @@ module Sentry
30
30
  # @return [Regexp, nil]
31
31
  attr_accessor :app_dirs_pattern
32
32
 
33
- # Provide an object that responds to `call` to send events asynchronously.
34
- # E.g.: lambda { |event| Thread.new { Sentry.send_event(event) } }
35
- #
36
- # @deprecated It will be removed in the next major release. Please read https://github.com/getsentry/sentry-ruby/issues/1522 for more information
37
- # @return [Proc, nil]
38
- attr_reader :async
39
-
40
33
  # to send events in a non-blocking way, sentry-ruby has its own background worker
41
34
  # by default, the worker holds a thread pool that has [the number of processors] threads
42
35
  # but you can configure it with this configuration option
@@ -74,11 +67,10 @@ module Sentry
74
67
  # @return [Proc]
75
68
  attr_reader :before_breadcrumb
76
69
 
77
- # Optional Proc, called before sending an event to the server
70
+ # Optional Proc, called before sending an error event to the server
78
71
  # @example
79
72
  # config.before_send = lambda do |event, hint|
80
73
  # # skip ZeroDivisionError exceptions
81
- # # note: hint[:exception] would be a String if you use async callback
82
74
  # if hint[:exception].is_a?(ZeroDivisionError)
83
75
  # nil
84
76
  # else
@@ -88,7 +80,7 @@ module Sentry
88
80
  # @return [Proc]
89
81
  attr_reader :before_send
90
82
 
91
- # Optional Proc, called before sending an event to the server
83
+ # Optional Proc, called before sending a transaction event to the server
92
84
  # @example
93
85
  # config.before_send_transaction = lambda do |event, hint|
94
86
  # # skip unimportant transactions or strip sensitive data
@@ -101,6 +93,18 @@ module Sentry
101
93
  # @return [Proc]
102
94
  attr_reader :before_send_transaction
103
95
 
96
+ # Optional Proc, called before sending a check-in event to the server
97
+ # @example
98
+ # config.before_send_check_in = lambda do |event, hint|
99
+ # if event.monitor_slug == "unimportant_job"
100
+ # nil
101
+ # else
102
+ # event
103
+ # end
104
+ # end
105
+ # @return [Proc]
106
+ attr_reader :before_send_check_in
107
+
104
108
  # Optional Proc, called before sending an event to the server
105
109
  # @example
106
110
  # config.before_send_log = lambda do |log|
@@ -117,7 +121,6 @@ module Sentry
117
121
  #
118
122
  # And if you also use sentry-rails:
119
123
  # - :active_support_logger
120
- # - :monotonic_active_support_logger
121
124
  #
122
125
  # @return [Array<Symbol>]
123
126
  attr_reader :breadcrumbs_logger
@@ -144,7 +147,7 @@ module Sentry
144
147
  attr_reader :dsn
145
148
 
146
149
  # Whitelist of enabled_environments that will send notifications to Sentry. Array of Strings.
147
- # @return [Array<String>]
150
+ # @return [Array<String>, nil]
148
151
  attr_accessor :enabled_environments
149
152
 
150
153
  # Logger 'progname's to exclude from breadcrumbs
@@ -173,18 +176,6 @@ module Sentry
173
176
  # @return [Boolean, String]
174
177
  attr_accessor :spotlight
175
178
 
176
- # @deprecated Use {#include_local_variables} instead.
177
- alias_method :capture_exception_frame_locals, :include_local_variables
178
-
179
- # @deprecated Use {#include_local_variables=} instead.
180
- def capture_exception_frame_locals=(value)
181
- log_warn <<~MSG
182
- `capture_exception_frame_locals` is now deprecated in favor of `include_local_variables`.
183
- MSG
184
-
185
- self.include_local_variables = value
186
- end
187
-
188
179
  # You may provide your own LineCache for matching paths with source files.
189
180
  # This may be useful if you need to get source code from places other than the disk.
190
181
  # @see LineCache
@@ -196,17 +187,10 @@ module Sentry
196
187
  # @return [Logger]
197
188
  attr_accessor :sdk_logger
198
189
 
199
- # @deprecated Use {#sdk_logger=} instead.
200
- def logger=(logger)
201
- warn "[sentry] `config.logger=` is deprecated. Please use `config.sdk_logger=` instead."
202
- self.sdk_logger = logger
203
- end
204
-
205
- # @deprecated Use {#sdk_logger} instead.
206
- def logger
207
- warn "[sentry] `config.logger` is deprecated. Please use `config.sdk_logger` instead."
208
- self.sdk_logger
209
- end
190
+ # File path for DebugTransport to log events to. If not set, defaults to a temporary file.
191
+ # This is useful for debugging and testing purposes.
192
+ # @return [String, nil]
193
+ attr_accessor :sdk_debug_transport_log_file
210
194
 
211
195
  # Project directory root for in_app detection. Could be Rails root, etc.
212
196
  # Set automatically for Rails.
@@ -267,10 +251,6 @@ module Sentry
267
251
  # @return [Cron::Configuration]
268
252
  attr_reader :cron
269
253
 
270
- # Metrics related configuration.
271
- # @return [Metrics::Configuration]
272
- attr_reader :metrics
273
-
274
254
  # Take a float between 0.0 and 1.0 as the sample rate for tracing events (transactions).
275
255
  # @return [Float, nil]
276
256
  attr_reader :traces_sample_rate
@@ -289,11 +269,9 @@ module Sentry
289
269
  # @return [Boolean]
290
270
  attr_accessor :enable_logs
291
271
 
292
- # Easier way to use performance tracing
293
- # If set to true, will set traces_sample_rate to 1.0
294
- # @deprecated It will be removed in the next major release.
295
- # @return [Boolean, nil]
296
- attr_reader :enable_tracing
272
+ # Structured logging configuration.
273
+ # @return [StructuredLoggingConfiguration]
274
+ attr_reader :structured_logging
297
275
 
298
276
  # Send diagnostic client reports about dropped events, true by default
299
277
  # tries to attach to an existing envelope max once every 30s
@@ -315,6 +293,18 @@ module Sentry
315
293
  # @return [Array<String, Regexp>]
316
294
  attr_accessor :trace_propagation_targets
317
295
 
296
+ # Collection of HTTP status codes or ranges of codes to ignore when tracing incoming requests.
297
+ # If a transaction's http.response.status_code matches one of these values,
298
+ # the transaction will be dropped and marked as not sampled.
299
+ # Defaults to TRACE_IGNORE_STATUS_CODES_DEFAULT.
300
+ #
301
+ # @example
302
+ # # ignore 404 and 502 <= status_code <= 511
303
+ # config.trace_ignore_status_codes = [404, (502..511)]
304
+ #
305
+ # @return [Array<Integer>, Array<Range>]
306
+ attr_reader :trace_ignore_status_codes
307
+
318
308
  # The instrumenter to use, :sentry or :otel
319
309
  # @return [Symbol]
320
310
  attr_reader :instrumenter
@@ -329,6 +319,15 @@ module Sentry
329
319
  # @return [Float, nil]
330
320
  attr_reader :profiles_sample_rate
331
321
 
322
+ # Interval in microseconds at which to take samples.
323
+ # The default is 1e6 / 101, or 101Hz.
324
+ # Note that the 101 is intentional to avoid lockstep sampling.
325
+ #
326
+ # @example
327
+ # config.profiles_sample_interval = 1e5 / 101
328
+ # @return [Float]
329
+ attr_accessor :profiles_sample_interval
330
+
332
331
  # Array of patches to apply.
333
332
  # Default is {DEFAULT_PATCHES}
334
333
  # @return [Array<Symbol>]
@@ -366,6 +365,8 @@ module Sentry
366
365
  SERVER_PORT
367
366
  ].freeze
368
367
 
368
+ TRACE_IGNORE_STATUS_CODES_DEFAULT = [(301..303), (305..399), (401..404)]
369
+
369
370
  HEROKU_DYNO_METADATA_MESSAGE = "You are running on Heroku but haven't enabled Dyno Metadata. For Sentry's "\
370
371
  "release detection to work correctly, please run `heroku labs:enable runtime-dyno-metadata`"
371
372
 
@@ -381,6 +382,9 @@ module Sentry
381
382
 
382
383
  APP_DIRS_PATTERN = /(bin|exe|app|config|lib|test|spec)/
383
384
 
385
+ # 101 Hz in microseconds
386
+ DEFAULT_PROFILES_SAMPLE_INTERVAL = 1e6 / 101
387
+
384
388
  class << self
385
389
  # Post initialization callbacks are called at the end of initialization process
386
390
  # allowing extending the configuration of sentry-ruby by multiple extensions
@@ -390,7 +394,23 @@ module Sentry
390
394
 
391
395
  # allow extensions to add their hooks to the Configuration class
392
396
  def add_post_initialization_callback(&block)
393
- post_initialization_callbacks << block
397
+ callbacks[:initialize][:after] << block
398
+ end
399
+
400
+ def before(event, &block)
401
+ callbacks[event.to_sym][:before] << block
402
+ end
403
+
404
+ def after(event, &block)
405
+ callbacks[event.to_sym][:after] << block
406
+ end
407
+
408
+ # @!visibility private
409
+ def callbacks
410
+ @callbacks ||= {
411
+ initialize: { before: [], after: [] },
412
+ configured: { before: [], after: [] }
413
+ }
394
414
  end
395
415
 
396
416
  def validations
@@ -434,6 +454,8 @@ module Sentry
434
454
  validate :profiles_sample_rate, optional: true, type: :numeric
435
455
 
436
456
  def initialize
457
+ run_callbacks(:before, :initialize)
458
+
437
459
  self.app_dirs_pattern = APP_DIRS_PATTERN
438
460
  self.debug = Sentry::Utils::EnvHelper.env_to_bool(ENV["SENTRY_DEBUG"])
439
461
  self.background_worker_threads = (processor_count / 2.0).ceil
@@ -445,7 +467,7 @@ module Sentry
445
467
  self.context_lines = 3
446
468
  self.include_local_variables = false
447
469
  self.environment = environment_from_env
448
- self.enabled_environments = []
470
+ self.enabled_environments = nil
449
471
  self.exclude_loggers = []
450
472
  self.excluded_exceptions = IGNORE_DEFAULT + PUMA_IGNORE_DEFAULT
451
473
  self.inspect_exception_causes_for_exclusion = true
@@ -470,26 +492,32 @@ module Sentry
470
492
  self.server_name = server_name_from_env
471
493
  self.instrumenter = :sentry
472
494
  self.trace_propagation_targets = [PROPAGATION_TARGETS_MATCH_ALL]
495
+ self.trace_ignore_status_codes = TRACE_IGNORE_STATUS_CODES_DEFAULT
473
496
  self.enabled_patches = DEFAULT_PATCHES.dup
474
497
 
475
498
  self.before_send = nil
476
499
  self.before_send_transaction = nil
500
+ self.before_send_check_in = nil
477
501
  self.before_send_log = nil
478
502
  self.rack_env_whitelist = RACK_ENV_WHITELIST_DEFAULT
479
503
  self.traces_sampler = nil
480
- self.enable_tracing = nil
481
504
  self.enable_logs = false
482
505
 
483
506
  self.profiler_class = Sentry::Profiler
507
+ self.profiles_sample_interval = DEFAULT_PROFILES_SAMPLE_INTERVAL
484
508
 
485
509
  @transport = Transport::Configuration.new
486
510
  @cron = Cron::Configuration.new
487
- @metrics = Metrics::Configuration.new
511
+ @structured_logging = StructuredLoggingConfiguration.new
488
512
  @gem_specs = Hash[Gem::Specification.map { |spec| [spec.name, spec.version.to_s] }] if Gem::Specification.respond_to?(:map)
489
513
 
490
- run_post_initialization_callbacks
491
-
492
514
  self.max_log_events = LogEventBuffer::DEFAULT_MAX_EVENTS
515
+
516
+ run_callbacks(:after, :initialize)
517
+
518
+ yield(self) if block_given?
519
+
520
+ run_callbacks(:after, :configured)
493
521
  end
494
522
 
495
523
  def validate
@@ -522,22 +550,6 @@ module Sentry
522
550
  @release = value
523
551
  end
524
552
 
525
- def async=(value)
526
- check_callable!("async", value)
527
-
528
- log_warn <<~MSG
529
-
530
- sentry-ruby now sends events asynchronously by default with its background worker (supported since 4.1.0).
531
- The `config.async` callback has become redundant while continuing to cause issues.
532
- (The problems of `async` are detailed in https://github.com/getsentry/sentry-ruby/issues/1522)
533
-
534
- Therefore, we encourage you to remove it and let the background worker take care of async job sending.
535
- It's deprecation is planned in the next major release (6.0), which is scheduled around the 3rd quarter of 2022.
536
- MSG
537
-
538
- @async = value
539
- end
540
-
541
553
  def breadcrumbs_logger=(logger)
542
554
  loggers =
543
555
  if logger.is_a?(Array)
@@ -563,6 +575,12 @@ module Sentry
563
575
  @before_send_transaction = value
564
576
  end
565
577
 
578
+ def before_send_check_in=(value)
579
+ check_callable!("before_send_check_in", value)
580
+
581
+ @before_send_check_in = value
582
+ end
583
+
566
584
  def before_breadcrumb=(value)
567
585
  check_callable!("before_breadcrumb", value)
568
586
 
@@ -577,15 +595,12 @@ module Sentry
577
595
  @instrumenter = INSTRUMENTERS.include?(instrumenter) ? instrumenter : :sentry
578
596
  end
579
597
 
580
- def enable_tracing=(enable_tracing)
581
- unless enable_tracing.nil?
582
- log_warn <<~MSG
583
- `enable_tracing` is now deprecated in favor of `traces_sample_rate = 1.0`.
584
- MSG
598
+ def trace_ignore_status_codes=(codes)
599
+ unless codes.is_a?(Array) && codes.all? { |code| valid_status_code_entry?(code) }
600
+ raise ArgumentError, "trace_ignore_status_codes must be an Array of integers or ranges between (100-599) where begin <= end"
585
601
  end
586
602
 
587
- @enable_tracing = enable_tracing
588
- @traces_sample_rate ||= 1.0 if enable_tracing
603
+ @trace_ignore_status_codes = codes
589
604
  end
590
605
 
591
606
  def traces_sample_rate=(traces_sample_rate)
@@ -641,7 +656,7 @@ module Sentry
641
656
  end
642
657
 
643
658
  def enabled_in_current_env?
644
- enabled_environments.empty? || enabled_environments.include?(environment)
659
+ enabled_environments.nil? || enabled_environments.include?(environment)
645
660
  end
646
661
 
647
662
  def valid_sample_rate?(sample_rate)
@@ -652,7 +667,7 @@ module Sentry
652
667
  def tracing_enabled?
653
668
  valid_sampler = !!((valid_sample_rate?(@traces_sample_rate)) || @traces_sampler)
654
669
 
655
- (@enable_tracing != false) && valid_sampler && sending_allowed?
670
+ valid_sampler && sending_allowed?
656
671
  end
657
672
 
658
673
  def profiling_enabled?
@@ -773,8 +788,8 @@ module Sentry
773
788
  File.directory?("/etc/heroku") && !ENV["CI"]
774
789
  end
775
790
 
776
- def run_post_initialization_callbacks
777
- self.class.post_initialization_callbacks.each do |hook|
791
+ def run_callbacks(hook, event)
792
+ self.class.callbacks[event][hook].each do |hook|
778
793
  instance_eval(&hook)
779
794
  end
780
795
  end
@@ -783,5 +798,37 @@ module Sentry
783
798
  available_processor_count = Concurrent.available_processor_count if Concurrent.respond_to?(:available_processor_count)
784
799
  available_processor_count || Concurrent.processor_count
785
800
  end
801
+
802
+ def valid_http_status_code?(code)
803
+ code.is_a?(Integer) && code >= 100 && code <= 599
804
+ end
805
+
806
+ def valid_status_code_entry?(entry)
807
+ case entry
808
+ when Integer
809
+ valid_http_status_code?(entry)
810
+ when Range
811
+ valid_http_status_code?(entry.begin) &&
812
+ valid_http_status_code?(entry.end) &&
813
+ entry.begin <= entry.end
814
+ else
815
+ false
816
+ end
817
+ end
818
+ end
819
+
820
+ class StructuredLoggingConfiguration
821
+ # File path for DebugStructuredLogger to log events to
822
+ # @return [String, Pathname, nil]
823
+ attr_accessor :file_path
824
+
825
+ # The class to use as a structured logger.
826
+ # @return [Class]
827
+ attr_accessor :logger_class
828
+
829
+ def initialize
830
+ @file_path = nil
831
+ @logger_class = Sentry::StructuredLogger
832
+ end
786
833
  end
787
834
  end
@@ -14,12 +14,12 @@ module Sentry
14
14
  :in_progress,
15
15
  monitor_config: monitor_config)
16
16
 
17
- start = Metrics::Timing.duration_start
17
+ start = Process.clock_gettime(Process::CLOCK_MONOTONIC)
18
18
 
19
19
  begin
20
20
  # need to do this on ruby <= 2.6 sadly
21
21
  ret = method(:perform).super_method.arity == 0 ? super() : super
22
- duration = Metrics::Timing.duration_end(start)
22
+ duration = Process.clock_gettime(Process::CLOCK_MONOTONIC) - start
23
23
 
24
24
  Sentry.capture_check_in(slug,
25
25
  :ok,
@@ -29,7 +29,7 @@ module Sentry
29
29
 
30
30
  ret
31
31
  rescue Exception
32
- duration = Metrics::Timing.duration_end(start)
32
+ duration = Process.clock_gettime(Process::CLOCK_MONOTONIC) - start
33
33
 
34
34
  Sentry.capture_check_in(slug,
35
35
  :error,
@@ -40,9 +40,9 @@ module Sentry
40
40
  new(MonitorSchedule::Interval.new(num, unit), **options)
41
41
  end
42
42
 
43
- def to_hash
43
+ def to_h
44
44
  {
45
- schedule: schedule.to_hash,
45
+ schedule: schedule.to_h,
46
46
  checkin_margin: checkin_margin,
47
47
  max_runtime: max_runtime,
48
48
  timezone: timezone
@@ -12,7 +12,7 @@ module Sentry
12
12
  @value = value
13
13
  end
14
14
 
15
- def to_hash
15
+ def to_h
16
16
  { type: :crontab, value: value }
17
17
  end
18
18
  end
@@ -33,7 +33,7 @@ module Sentry
33
33
  @unit = unit
34
34
  end
35
35
 
36
- def to_hash
36
+ def to_h
37
37
  { type: :interval, value: value, unit: unit }
38
38
  end
39
39
  end
@@ -0,0 +1,94 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "json"
4
+ require "fileutils"
5
+ require "pathname"
6
+ require "delegate"
7
+
8
+ module Sentry
9
+ # DebugStructuredLogger is a logger that captures structured log events to a file for debugging purposes.
10
+ #
11
+ # It can optionally also send log events to Sentry via the normal structured logger if logging
12
+ # is enabled.
13
+ class DebugStructuredLogger < SimpleDelegator
14
+ DEFAULT_LOG_FILE_PATH = File.join("log", "sentry_debug_logs.log")
15
+
16
+ attr_reader :log_file, :backend
17
+
18
+ def initialize(configuration)
19
+ @log_file = initialize_log_file(
20
+ configuration.structured_logging.file_path || DEFAULT_LOG_FILE_PATH
21
+ )
22
+ @backend = initialize_backend(configuration)
23
+
24
+ super(@backend)
25
+ end
26
+
27
+ # Override all log level methods to capture events
28
+ %i[trace debug info warn error fatal].each do |level|
29
+ define_method(level) do |message, parameters = [], **attributes|
30
+ log_event = capture_log_event(level, message, parameters, **attributes)
31
+ backend.public_send(level, message, parameters, **attributes)
32
+ log_event
33
+ end
34
+ end
35
+
36
+ def log(level, message, parameters:, **attributes)
37
+ log_event = capture_log_event(level, message, parameters, **attributes)
38
+ backend.log(level, message, parameters: parameters, **attributes)
39
+ log_event
40
+ end
41
+
42
+ def capture_log_event(level, message, parameters, **attributes)
43
+ log_event_json = {
44
+ timestamp: Time.now.utc.iso8601,
45
+ level: level.to_s,
46
+ message: message,
47
+ parameters: parameters,
48
+ attributes: attributes
49
+ }
50
+
51
+ File.open(log_file, "a") { |file| file << JSON.dump(log_event_json) << "\n" }
52
+ log_event_json
53
+ end
54
+
55
+ def logged_events
56
+ File.readlines(log_file).map do |line|
57
+ JSON.parse(line)
58
+ end
59
+ end
60
+
61
+ def clear
62
+ File.write(log_file, "")
63
+ if backend.respond_to?(:config)
64
+ backend.config.sdk_logger.debug("DebugStructuredLogger: Cleared events from #{log_file}")
65
+ end
66
+ end
67
+
68
+ private
69
+
70
+ 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
77
+ end
78
+
79
+ def initialize_log_file(log_file_path)
80
+ log_file = Pathname(log_file_path)
81
+
82
+ FileUtils.mkdir_p(log_file.dirname) unless log_file.dirname.exist?
83
+
84
+ log_file
85
+ 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
+ end
94
+ end
data/lib/sentry/dsn.rb CHANGED
@@ -1,11 +1,15 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require "uri"
4
+ require "ipaddr"
5
+ require "resolv"
4
6
 
5
7
  module Sentry
6
8
  class DSN
7
9
  PORT_MAP = { "http" => 80, "https" => 443 }.freeze
8
10
  REQUIRED_ATTRIBUTES = %w[host path public_key project_id].freeze
11
+ LOCALHOST_NAMES = %w[localhost 127.0.0.1 ::1 [::1]].freeze
12
+ LOCALHOST_PATTERN = /\.local(host|domain)?$/i
9
13
 
10
14
  attr_reader :scheme, :secret_key, :port, *REQUIRED_ATTRIBUTES
11
15
 
@@ -49,5 +53,33 @@ module Sentry
49
53
  def envelope_endpoint
50
54
  "#{path}/api/#{project_id}/envelope/"
51
55
  end
56
+
57
+ def local?
58
+ @local ||= (localhost? || private_ip? || resolved_ips_private?)
59
+ end
60
+
61
+ def localhost?
62
+ LOCALHOST_NAMES.include?(host.downcase) || LOCALHOST_PATTERN.match?(host)
63
+ end
64
+
65
+ def private_ip?
66
+ @private_ip ||= begin
67
+ begin
68
+ IPAddr.new(host).private?
69
+ rescue IPAddr::InvalidAddressError
70
+ false
71
+ end
72
+ end
73
+ end
74
+
75
+ def resolved_ips_private?
76
+ @resolved_ips_private ||= begin
77
+ begin
78
+ Resolv.getaddresses(host).any? { |ip| IPAddr.new(ip).private? }
79
+ rescue Resolv::ResolvError, IPAddr::InvalidAddressError
80
+ false
81
+ end
82
+ end
83
+ end
52
84
  end
53
85
  end
@@ -3,7 +3,7 @@
3
3
  module Sentry
4
4
  # @api private
5
5
  class Envelope::Item
6
- STACKTRACE_FRAME_LIMIT_ON_OVERSIZED_PAYLOAD = 500
6
+ STACKTRACE_FRAME_LIMIT_ON_OVERSIZED_PAYLOAD = 1000
7
7
  MAX_SERIALIZED_PAYLOAD_SIZE = 1024 * 1000
8
8
 
9
9
  SIZE_LIMITS = Hash.new(MAX_SERIALIZED_PAYLOAD_SIZE).update(
@@ -18,7 +18,6 @@ module Sentry
18
18
  when "session", "attachment", "transaction", "profile", "span", "log" then type
19
19
  when "sessions" then "session"
20
20
  when "check_in" then "monitor"
21
- when "statsd", "metric_meta" then "metric_bucket"
22
21
  when "event" then "error"
23
22
  when "client_report" then "internal"
24
23
  else "default"
@@ -10,10 +10,10 @@ module Sentry
10
10
  attr_reader :threads
11
11
 
12
12
  # @return [Hash]
13
- def to_hash
13
+ def to_h
14
14
  data = super
15
- data[:threads] = threads.to_hash if threads
16
- data[:exception] = exception.to_hash if exception
15
+ data[:threads] = threads.to_h if threads
16
+ data[:exception] = exception.to_h if exception
17
17
  data
18
18
  end
19
19
 
data/lib/sentry/event.rb CHANGED
@@ -81,12 +81,6 @@ module Sentry
81
81
  @message = (message || "").byteslice(0..MAX_MESSAGE_SIZE_IN_BYTES)
82
82
  end
83
83
 
84
- # @deprecated This method will be removed in v5.0.0. Please just use Sentry.configuration
85
- # @return [Configuration]
86
- def configuration
87
- Sentry.configuration
88
- end
89
-
90
84
  # Sets the event's timestamp.
91
85
  # @param time [Time, Float]
92
86
  # @return [void]
@@ -118,16 +112,16 @@ module Sentry
118
112
  end
119
113
 
120
114
  # @return [Hash]
121
- def to_hash
115
+ def to_h
122
116
  data = serialize_attributes
123
- data[:breadcrumbs] = breadcrumbs.to_hash if breadcrumbs
124
- data[:request] = request.to_hash if request
117
+ data[:breadcrumbs] = breadcrumbs.to_h if breadcrumbs
118
+ data[:request] = request.to_h if request
125
119
  data
126
120
  end
127
121
 
128
122
  # @return [Hash]
129
123
  def to_json_compatible
130
- JSON.parse(JSON.generate(to_hash))
124
+ JSON.parse(JSON.generate(to_h))
131
125
  end
132
126
 
133
127
  private
@@ -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) { "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." }
7
+ config.sdk_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