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.
Files changed (92) hide show
  1. checksums.yaml +4 -4
  2. data/.rspec +3 -1
  3. data/Gemfile +12 -13
  4. data/README.md +26 -11
  5. data/Rakefile +9 -11
  6. data/bin/console +2 -0
  7. data/lib/sentry/attachment.rb +40 -0
  8. data/lib/sentry/background_worker.rb +11 -5
  9. data/lib/sentry/backpressure_monitor.rb +45 -0
  10. data/lib/sentry/backtrace.rb +12 -9
  11. data/lib/sentry/baggage.rb +7 -7
  12. data/lib/sentry/breadcrumb/sentry_logger.rb +6 -6
  13. data/lib/sentry/breadcrumb.rb +13 -6
  14. data/lib/sentry/check_in_event.rb +61 -0
  15. data/lib/sentry/client.rb +214 -25
  16. data/lib/sentry/configuration.rb +221 -38
  17. data/lib/sentry/core_ext/object/deep_dup.rb +1 -1
  18. data/lib/sentry/cron/configuration.rb +23 -0
  19. data/lib/sentry/cron/monitor_check_ins.rb +77 -0
  20. data/lib/sentry/cron/monitor_config.rb +53 -0
  21. data/lib/sentry/cron/monitor_schedule.rb +42 -0
  22. data/lib/sentry/dsn.rb +4 -4
  23. data/lib/sentry/envelope/item.rb +88 -0
  24. data/lib/sentry/envelope.rb +2 -68
  25. data/lib/sentry/error_event.rb +2 -2
  26. data/lib/sentry/event.rb +28 -47
  27. data/lib/sentry/excon/middleware.rb +77 -0
  28. data/lib/sentry/excon.rb +10 -0
  29. data/lib/sentry/faraday.rb +77 -0
  30. data/lib/sentry/graphql.rb +9 -0
  31. data/lib/sentry/hub.rb +138 -6
  32. data/lib/sentry/integrable.rb +10 -0
  33. data/lib/sentry/interface.rb +1 -0
  34. data/lib/sentry/interfaces/exception.rb +5 -3
  35. data/lib/sentry/interfaces/mechanism.rb +20 -0
  36. data/lib/sentry/interfaces/request.rb +8 -8
  37. data/lib/sentry/interfaces/single_exception.rb +13 -9
  38. data/lib/sentry/interfaces/stacktrace.rb +3 -1
  39. data/lib/sentry/interfaces/stacktrace_builder.rb +23 -2
  40. data/lib/sentry/linecache.rb +3 -3
  41. data/lib/sentry/log_event.rb +206 -0
  42. data/lib/sentry/log_event_buffer.rb +75 -0
  43. data/lib/sentry/logger.rb +1 -1
  44. data/lib/sentry/metrics/aggregator.rb +248 -0
  45. data/lib/sentry/metrics/configuration.rb +47 -0
  46. data/lib/sentry/metrics/counter_metric.rb +25 -0
  47. data/lib/sentry/metrics/distribution_metric.rb +25 -0
  48. data/lib/sentry/metrics/gauge_metric.rb +35 -0
  49. data/lib/sentry/metrics/local_aggregator.rb +53 -0
  50. data/lib/sentry/metrics/metric.rb +19 -0
  51. data/lib/sentry/metrics/set_metric.rb +28 -0
  52. data/lib/sentry/metrics/timing.rb +51 -0
  53. data/lib/sentry/metrics.rb +56 -0
  54. data/lib/sentry/net/http.rb +27 -44
  55. data/lib/sentry/profiler/helpers.rb +46 -0
  56. data/lib/sentry/profiler.rb +41 -60
  57. data/lib/sentry/propagation_context.rb +135 -0
  58. data/lib/sentry/puma.rb +12 -5
  59. data/lib/sentry/rack/capture_exceptions.rb +17 -8
  60. data/lib/sentry/rack.rb +2 -2
  61. data/lib/sentry/rake.rb +4 -15
  62. data/lib/sentry/redis.rb +10 -4
  63. data/lib/sentry/release_detector.rb +5 -5
  64. data/lib/sentry/rspec.rb +91 -0
  65. data/lib/sentry/scope.rb +75 -39
  66. data/lib/sentry/session.rb +2 -2
  67. data/lib/sentry/session_flusher.rb +15 -43
  68. data/lib/sentry/span.rb +92 -8
  69. data/lib/sentry/std_lib_logger.rb +50 -0
  70. data/lib/sentry/structured_logger.rb +138 -0
  71. data/lib/sentry/test_helper.rb +42 -13
  72. data/lib/sentry/threaded_periodic_worker.rb +39 -0
  73. data/lib/sentry/transaction.rb +44 -43
  74. data/lib/sentry/transaction_event.rb +10 -6
  75. data/lib/sentry/transport/configuration.rb +73 -1
  76. data/lib/sentry/transport/http_transport.rb +71 -41
  77. data/lib/sentry/transport/spotlight_transport.rb +50 -0
  78. data/lib/sentry/transport.rb +53 -49
  79. data/lib/sentry/utils/argument_checking_helper.rb +12 -0
  80. data/lib/sentry/utils/env_helper.rb +21 -0
  81. data/lib/sentry/utils/http_tracing.rb +74 -0
  82. data/lib/sentry/utils/logging_helper.rb +10 -7
  83. data/lib/sentry/utils/real_ip.rb +2 -2
  84. data/lib/sentry/utils/request_id.rb +1 -1
  85. data/lib/sentry/utils/uuid.rb +13 -0
  86. data/lib/sentry/vernier/output.rb +89 -0
  87. data/lib/sentry/vernier/profiler.rb +132 -0
  88. data/lib/sentry/version.rb +1 -1
  89. data/lib/sentry-ruby.rb +206 -35
  90. data/sentry-ruby-core.gemspec +3 -1
  91. data/sentry-ruby.gemspec +15 -6
  92. metadata +61 -11
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 2373a9b8990fd62763c4d1b26001f953f95efdd8b51f803e5d59bdb1ba984e3e
4
- data.tar.gz: d09371eb4bf3aaff6e7735f74cd5887b2e99f636a60f1dca3cf653bbb8ba9bb4
3
+ metadata.gz: eb03eb536d1060c3a097a1ff3726ae71c8ffbd0012580d75c491665e054ac7c1
4
+ data.tar.gz: 65df577369b281f3e1d1d9335e78786a800947c2014b35608d88c863458f24ca
5
5
  SHA512:
6
- metadata.gz: 4799b727ddaab0622be00e73b58a2e3f723779e1b46c7d5007d5711a8897022190ff9f87cc90df7411f32fd6b59d4f4637bcf26cc7eba8484cb04429871e9242
7
- data.tar.gz: d97d9272ee815447ebdcbb72adb4e2255584475547e7878ed6c7af4f312d170bd37f3029acaaa6866eb04f2d89c1581c4854b849c2d57a1a51eb4b67e4ebeb0e
6
+ metadata.gz: b4e398e02a8fe619afc8982760c290a168785c4557dca30767fbeb039032d7907135e84d0598a5ac90b7b1cfb8413ceda83ebe4647702ba5c10c613ff0543574
7
+ data.tar.gz: 285a3e0f650a41bcb6cc4539f48c7efcb9bc3442f31c76f301089c4672e6d9c790f407dd9d53db4e216df4eacd9be019b5bc46e453437fa1614aa48555541c9a
data/.rspec CHANGED
@@ -1,2 +1,4 @@
1
- --format documentation
1
+ --require spec_helper
2
+ --format progress
2
3
  --color
4
+ --order rand
data/Gemfile CHANGED
@@ -1,37 +1,36 @@
1
+ # frozen_string_literal: true
2
+
1
3
  source "https://rubygems.org"
2
4
  git_source(:github) { |name| "https://github.com/#{name}.git" }
3
5
 
6
+ eval_gemfile "../Gemfile"
7
+
4
8
  gem "sentry-ruby", path: "./"
5
9
 
6
10
  rack_version = ENV["RACK_VERSION"]
7
11
  rack_version = "3.0.0" if rack_version.nil?
8
12
  gem "rack", "~> #{Gem::Version.new(rack_version)}" unless rack_version == "0"
9
13
 
14
+ gem "ostruct" if RUBY_VERSION >= "3.4"
15
+
10
16
  redis_rb_version = ENV.fetch("REDIS_RB_VERSION", "5.0")
11
17
  gem "redis", "~> #{redis_rb_version}"
12
18
 
13
19
  gem "puma"
14
20
 
15
- gem "rake", "~> 12.0"
16
- gem "rspec", "~> 3.0"
17
- gem "rspec-retry"
18
21
  gem "timecop"
19
- gem "simplecov"
20
- gem "simplecov-cobertura", "~> 1.4"
21
- gem "rexml"
22
22
  gem "stackprof" unless RUBY_PLATFORM == "java"
23
+ gem "vernier", platforms: :ruby if RUBY_VERSION >= "3.2.1"
23
24
 
24
- if RUBY_VERSION.to_f >= 2.6
25
- gem "debug", github: "ruby/debug", platform: :ruby
26
- gem "irb"
27
- end
28
-
29
- gem "pry"
25
+ gem "graphql", ">= 2.2.6" if RUBY_VERSION.to_f >= 2.7
30
26
 
31
27
  gem "benchmark-ips"
32
28
  gem "benchmark_driver"
33
29
  gem "benchmark-ipsa"
34
30
  gem "benchmark-memory"
35
31
 
36
- gem "yard", github: "lsegal/yard"
32
+ gem "yard"
37
33
  gem "webrick"
34
+ gem "faraday"
35
+ gem "excon"
36
+ gem "webmock"
data/README.md CHANGED
@@ -13,14 +13,14 @@ _Bad software is everywhere, and we're tired of it. Sentry is on a mission to he
13
13
  Sentry SDK for Ruby
14
14
  ===========
15
15
 
16
- | current version | build | coverage | downloads |
17
- | --- | ----- | -------- | --------- |
18
- | [![Gem Version](https://img.shields.io/gem/v/sentry-ruby?label=sentry-ruby)](https://rubygems.org/gems/sentry-ruby) | [![Build Status](https://github.com/getsentry/sentry-ruby/workflows/sentry-ruby%20Test/badge.svg)](https://github.com/getsentry/sentry-ruby/actions/workflows/sentry_ruby_test.yml) | [![Coverage Status](https://img.shields.io/codecov/c/github/getsentry/sentry-ruby/master?logo=codecov)](https://codecov.io/gh/getsentry/sentry-ruby/branch/master) | [![Downloads](https://img.shields.io/gem/dt/sentry-ruby.svg)](https://rubygems.org/gems/sentry-ruby/) |
19
- | [![Gem Version](https://img.shields.io/gem/v/sentry-rails?label=sentry-rails)](https://rubygems.org/gems/sentry-rails) | [![Build Status](https://github.com/getsentry/sentry-ruby/workflows/sentry-rails%20Test/badge.svg)](https://github.com/getsentry/sentry-ruby/actions/workflows/sentry_rails_test.yml) | [![Coverage Status](https://img.shields.io/codecov/c/github/getsentry/sentry-ruby/master?logo=codecov)](https://codecov.io/gh/getsentry/sentry-ruby/branch/master) | [![Downloads](https://img.shields.io/gem/dt/sentry-rails.svg)](https://rubygems.org/gems/sentry-rails/) |
20
- | [![Gem Version](https://img.shields.io/gem/v/sentry-sidekiq?label=sentry-sidekiq)](https://rubygems.org/gems/sentry-sidekiq) | [![Build Status](https://github.com/getsentry/sentry-ruby/workflows/sentry-sidekiq%20Test/badge.svg)](https://github.com/getsentry/sentry-ruby/actions/workflows/sentry_sidekiq_test.yml) | [![Coverage Status](https://img.shields.io/codecov/c/github/getsentry/sentry-ruby/master?logo=codecov)](https://codecov.io/gh/getsentry/sentry-ruby/branch/master) | [![Downloads](https://img.shields.io/gem/dt/sentry-sidekiq.svg)](https://rubygems.org/gems/sentry-sidekiq/) |
21
- | [![Gem Version](https://img.shields.io/gem/v/sentry-delayed_job?label=sentry-delayed_job)](https://rubygems.org/gems/sentry-delayed_job) | [![Build Status](https://github.com/getsentry/sentry-ruby/workflows/sentry-delayed_job%20Test/badge.svg)](https://github.com/getsentry/sentry-ruby/actions/workflows/sentry_delayed_job_test.yml) | [![Coverage Status](https://img.shields.io/codecov/c/github/getsentry/sentry-ruby/master?logo=codecov)](https://codecov.io/gh/getsentry/sentry-ruby/branch/master) | [![Downloads](https://img.shields.io/gem/dt/sentry-delayed_job.svg)](https://rubygems.org/gems/sentry-delayed_job/) |
22
- | [![Gem Version](https://img.shields.io/gem/v/sentry-resque?label=sentry-resque)](https://rubygems.org/gems/sentry-resque) | [![Build Status](https://github.com/getsentry/sentry-ruby/workflows/sentry-resque%20Test/badge.svg)](https://github.com/getsentry/sentry-ruby/actions/workflows/sentry_resque_test.yml) | [![Coverage Status](https://img.shields.io/codecov/c/github/getsentry/sentry-ruby/master?logo=codecov)](https://codecov.io/gh/getsentry/sentry-ruby/branch/master) | [![Downloads](https://img.shields.io/gem/dt/sentry-resque.svg)](https://rubygems.org/gems/sentry-resque/) |
23
- | [![Gem Version](https://img.shields.io/gem/v/sentry-opentelemetry?label=sentry-opentelemetry)](https://rubygems.org/gems/sentry-opentelemetry) | [![Build Status](https://github.com/getsentry/sentry-ruby/workflows/sentry-opentelemetry%20Test/badge.svg)](https://github.com/getsentry/sentry-ruby/actions/workflows/sentry_opentelemetry_test.yml) | [![Coverage Status](https://img.shields.io/codecov/c/github/getsentry/sentry-ruby/master?logo=codecov)](https://codecov.io/gh/getsentry/sentry-ruby/branch/master) | [![Downloads](https://img.shields.io/gem/dt/sentry-opentelemetry.svg)](https://rubygems.org/gems/sentry-opentelemetry/) |
16
+ | Current version | Build | Coverage | API doc |
17
+ | ---------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------ | -------------------------------------------------------------------------------------------------------------------------- |
18
+ | [![Gem Version](https://img.shields.io/gem/v/sentry-ruby?label=sentry-ruby)](https://rubygems.org/gems/sentry-ruby) | [![Build Status](https://github.com/getsentry/sentry-ruby/actions/workflows/tests.yml/badge.svg)](https://github.com/getsentry/sentry-ruby/actions/workflows/tests.yml) | [![codecov](https://codecov.io/gh/getsentry/sentry-ruby/graph/badge.svg?token=ZePzrpZFP6&component=sentry-ruby)](https://codecov.io/gh/getsentry/sentry-ruby) | [![API doc](https://img.shields.io/badge/API%20doc-rubydoc.info-blue)](https://www.rubydoc.info/gems/sentry-ruby) |
19
+ | [![Gem Version](https://img.shields.io/gem/v/sentry-rails?label=sentry-rails)](https://rubygems.org/gems/sentry-rails) | [![Build Status](https://github.com/getsentry/sentry-ruby/actions/workflows/tests.yml/badge.svg)](https://github.com/getsentry/sentry-ruby/actions/workflows/tests.yml) | [![codecov](https://codecov.io/gh/getsentry/sentry-ruby/graph/badge.svg?token=ZePzrpZFP6&component=sentry-rails)](https://codecov.io/gh/getsentry/sentry-ruby) | [![API doc](https://img.shields.io/badge/API%20doc-rubydoc.info-blue)](https://www.rubydoc.info/gems/sentry-rails) |
20
+ | [![Gem Version](https://img.shields.io/gem/v/sentry-sidekiq?label=sentry-sidekiq)](https://rubygems.org/gems/sentry-sidekiq) | [![Build Status](https://github.com/getsentry/sentry-ruby/actions/workflows/tests.yml/badge.svg)](https://github.com/getsentry/sentry-ruby/actions/workflows/tests.yml) | [![codecov](https://codecov.io/gh/getsentry/sentry-ruby/graph/badge.svg?token=ZePzrpZFP6&component=sentry-sidekiq)](https://codecov.io/gh/getsentry/sentry-ruby) | [![API doc](https://img.shields.io/badge/API%20doc-rubydoc.info-blue)](https://www.rubydoc.info/gems/sentry-sidekiq) |
21
+ | [![Gem Version](https://img.shields.io/gem/v/sentry-delayed_job?label=sentry-delayed_job)](https://rubygems.org/gems/sentry-delayed_job) | [![Build Status](https://github.com/getsentry/sentry-ruby/actions/workflows/tests.yml/badge.svg)](https://github.com/getsentry/sentry-ruby/actions/workflows/tests.yml) | [![codecov](https://codecov.io/gh/getsentry/sentry-ruby/graph/badge.svg?token=ZePzrpZFP6&component=sentry-delayed_job)](https://codecov.io/gh/getsentry/sentry-ruby) | [![API doc](https://img.shields.io/badge/API%20doc-rubydoc.info-blue)](https://www.rubydoc.info/gems/sentry-delayed_job) |
22
+ | [![Gem Version](https://img.shields.io/gem/v/sentry-resque?label=sentry-resque)](https://rubygems.org/gems/sentry-resque) | [![Build Status](https://github.com/getsentry/sentry-ruby/actions/workflows/tests.yml/badge.svg)](https://github.com/getsentry/sentry-ruby/actions/workflows/tests.yml) | [![codecov](https://codecov.io/gh/getsentry/sentry-ruby/graph/badge.svg?token=ZePzrpZFP6&component=sentry-resque)](https://codecov.io/gh/getsentry/sentry-ruby) | [![API doc](https://img.shields.io/badge/API%20doc-rubydoc.info-blue)](https://www.rubydoc.info/gems/sentry-resque) |
23
+ | [![Gem Version](https://img.shields.io/gem/v/sentry-opentelemetry?label=sentry-opentelemetry)](https://rubygems.org/gems/sentry-opentelemetry) | [![Build Status](https://github.com/getsentry/sentry-ruby/actions/workflows/tests.yml/badge.svg)](https://github.com/getsentry/sentry-ruby/actions/workflows/tests.yml) | [![codecov](https://codecov.io/gh/getsentry/sentry-ruby/graph/badge.svg?token=ZePzrpZFP6&component=sentry-opentelemetry)](https://codecov.io/gh/getsentry/sentry-ruby) | [![API doc](https://img.shields.io/badge/API%20doc-rubydoc.info-blue)](https://www.rubydoc.info/gems/sentry-opentelemetry) |
24
24
 
25
25
 
26
26
 
@@ -33,7 +33,7 @@ If you're using `sentry-raven`, we recommend you to migrate to this new SDK. You
33
33
 
34
34
  ## Requirements
35
35
 
36
- We test on Ruby 2.4, 2.5, 2.6, 2.7, 3.0, and 3.1 at the latest patchlevel/teeny version. We also support JRuby 9.0.
36
+ We test from Ruby 2.4 to Ruby 3.4 at the latest patchlevel/teeny version. We also support JRuby 9.0.
37
37
 
38
38
  If you use self-hosted Sentry, please also make sure its version is above `20.6.0`.
39
39
 
@@ -59,6 +59,8 @@ gem "sentry-opentelemetry"
59
59
 
60
60
  You need to use Sentry.init to initialize and configure your SDK:
61
61
  ```ruby
62
+ require "sentry-ruby"
63
+
62
64
  Sentry.init do |config|
63
65
  config.dsn = "MY_DSN"
64
66
  end
@@ -90,7 +92,7 @@ To learn more about sampling transactions, please visit the [official documentat
90
92
  - [Sidekiq](https://docs.sentry.io/platforms/ruby/guides/sidekiq/)
91
93
  - [DelayedJob](https://docs.sentry.io/platforms/ruby/guides/delayed_job/)
92
94
  - [Resque](https://docs.sentry.io/platforms/ruby/guides/resque/)
93
- - [OpenTemeletry](https://docs.sentry.io/platforms/ruby/performance/instrumentation/opentelemetry/)
95
+ - [OpenTelemetry](https://docs.sentry.io/platforms/ruby/performance/instrumentation/opentelemetry/)
94
96
 
95
97
  ### Enriching Events
96
98
 
@@ -103,6 +105,19 @@ To learn more about sampling transactions, please visit the [official documentat
103
105
 
104
106
  * [![Ruby docs](https://img.shields.io/badge/documentation-sentry.io-green.svg?label=ruby%20docs)](https://docs.sentry.io/platforms/ruby/)
105
107
  * [![Forum](https://img.shields.io/badge/forum-sentry-green.svg)](https://forum.sentry.io/c/sdks)
106
- * [![Discord Chat](https://img.shields.io/discord/621778831602221064?logo=discord&logoColor=ffffff&color=7389D8)](https://discord.gg/PXa5Apfe7K)
108
+ * [![Discord Chat](https://img.shields.io/discord/621778831602221064?logo=discord&logoColor=ffffff&color=7389D8)](https://discord.gg/PXa5Apfe7K)
107
109
  * [![Stack Overflow](https://img.shields.io/badge/stack%20overflow-sentry-green.svg)](https://stackoverflow.com/questions/tagged/sentry)
108
110
  * [![Twitter Follow](https://img.shields.io/twitter/follow/getsentry?label=getsentry&style=social)](https://twitter.com/intent/follow?screen_name=getsentry)
111
+
112
+ ## Contributing to the SDK
113
+
114
+ Please make sure to read the [CONTRIBUTING.md](https://github.com/getsentry/sentry-ruby/blob/master/CONTRIBUTING.md) before making a pull request.
115
+
116
+ Thanks to everyone who has contributed to this project so far.
117
+
118
+ <a href="https://github.com/getsentry/sentry-ruby/graphs/contributors">
119
+ <img src="https://contributors-img.web.app/image?repo=getsentry/sentry-ruby" />
120
+ </a>
121
+
122
+ > [!WARNING]
123
+ > Example and sample code in sentry-rails/examples and sentry-rails/spec/dummy is unmaintained. Sample code may contain security vulnerabilities, should never be used in production, and exists only for illustrative purposes.
data/Rakefile CHANGED
@@ -1,20 +1,18 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "rake/clean"
2
4
  CLOBBER.include "pkg"
3
5
 
4
6
  require "bundler/gem_helper"
5
7
  Bundler::GemHelper.install_tasks(name: "sentry-ruby")
6
8
 
7
- require "rspec/core/rake_task"
9
+ require_relative "../lib/sentry/test/rake_tasks"
8
10
 
9
- RSpec::Core::RakeTask.new(:spec).tap do |task|
10
- task.rspec_opts = "--order rand"
11
- task.exclude_pattern = "spec/isolated/**/*_spec.rb"
12
- end
11
+ ISOLATED_SPECS = "spec/isolated/**/*_spec.rb"
13
12
 
14
- task :isolated_specs do
15
- Dir["spec/isolated/*"].each do |file|
16
- sh "bundle exec rspec #{file}"
17
- end
18
- end
13
+ Sentry::Test::RakeTasks.define_spec_tasks(
14
+ isolated_specs_pattern: ISOLATED_SPECS,
15
+ spec_exclude_pattern: ISOLATED_SPECS
16
+ )
19
17
 
20
- task :default => [:spec, :isolated_specs]
18
+ task default: [:spec, :"spec:isolated"]
data/bin/console CHANGED
@@ -1,6 +1,8 @@
1
1
  #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
2
3
 
3
4
  require "bundler/setup"
5
+ require "debug"
4
6
  require "sentry-ruby"
5
7
 
6
8
  # You can add fixtures and/or initialization code here to make experimenting
@@ -0,0 +1,40 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Sentry
4
+ class Attachment
5
+ PathNotFoundError = Class.new(StandardError)
6
+
7
+ attr_reader :bytes, :filename, :path, :content_type
8
+
9
+ def initialize(bytes: nil, filename: nil, content_type: nil, path: nil)
10
+ @bytes = bytes
11
+ @filename = filename || infer_filename(path)
12
+ @path = path
13
+ @content_type = content_type
14
+ end
15
+
16
+ def to_envelope_headers
17
+ { type: "attachment", filename: filename, content_type: content_type, length: payload.bytesize }
18
+ end
19
+
20
+ def payload
21
+ @payload ||= if bytes
22
+ bytes
23
+ else
24
+ File.binread(path)
25
+ end
26
+ rescue Errno::ENOENT
27
+ raise PathNotFoundError, "Failed to read attachment file, file not found: #{path}"
28
+ end
29
+
30
+ private
31
+
32
+ def infer_filename(path)
33
+ if path
34
+ File.basename(path)
35
+ else
36
+ raise ArgumentError, "filename or path is required"
37
+ end
38
+ end
39
+ end
40
+ end
@@ -9,15 +9,16 @@ module Sentry
9
9
  include LoggingHelper
10
10
 
11
11
  attr_reader :max_queue, :number_of_threads
12
- # @deprecated Use Sentry.logger to retrieve the current logger instead.
13
- attr_reader :logger
12
+
14
13
  attr_accessor :shutdown_timeout
15
14
 
15
+ DEFAULT_MAX_QUEUE = 30
16
+
16
17
  def initialize(configuration)
17
- @max_queue = 30
18
18
  @shutdown_timeout = 1
19
19
  @number_of_threads = configuration.background_worker_threads
20
- @logger = configuration.logger
20
+ @max_queue = configuration.background_worker_max_queue
21
+ @sdk_logger = configuration.sdk_logger
21
22
  @debug = configuration.debug
22
23
  @shutdown_callback = nil
23
24
 
@@ -29,7 +30,7 @@ module Sentry
29
30
  log_debug("config.background_worker_threads is set to 0, all events will be sent synchronously")
30
31
  Concurrent::ImmediateExecutor.new
31
32
  else
32
- log_debug("Initializing the background worker with #{@number_of_threads} threads")
33
+ log_debug("Initializing the Sentry background worker with #{@number_of_threads} threads")
33
34
 
34
35
  executor = Concurrent::ThreadPoolExecutor.new(
35
36
  min_threads: 0,
@@ -63,6 +64,11 @@ module Sentry
63
64
  @shutdown_callback&.call
64
65
  end
65
66
 
67
+ def full?
68
+ @executor.is_a?(Concurrent::ThreadPoolExecutor) &&
69
+ @executor.remaining_capacity == 0
70
+ end
71
+
66
72
  private
67
73
 
68
74
  def _perform(&block)
@@ -0,0 +1,45 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Sentry
4
+ class BackpressureMonitor < ThreadedPeriodicWorker
5
+ DEFAULT_INTERVAL = 10
6
+ MAX_DOWNSAMPLE_FACTOR = 10
7
+
8
+ def initialize(configuration, client, interval: DEFAULT_INTERVAL)
9
+ super(configuration.sdk_logger, interval)
10
+ @client = client
11
+
12
+ @healthy = true
13
+ @downsample_factor = 0
14
+ end
15
+
16
+ def healthy?
17
+ ensure_thread
18
+ @healthy
19
+ end
20
+
21
+ def downsample_factor
22
+ ensure_thread
23
+ @downsample_factor
24
+ end
25
+
26
+ def run
27
+ check_health
28
+ set_downsample_factor
29
+ end
30
+
31
+ def check_health
32
+ @healthy = !(@client.transport.any_rate_limited? || Sentry.background_worker&.full?)
33
+ end
34
+
35
+ def set_downsample_factor
36
+ if @healthy
37
+ log_debug("[BackpressureMonitor] health check positive, reverting to normal sampling") if @downsample_factor.positive?
38
+ @downsample_factor = 0
39
+ else
40
+ @downsample_factor += 1 if @downsample_factor < MAX_DOWNSAMPLE_FACTOR
41
+ log_debug("[BackpressureMonitor] health check negative, downsampling with a factor of #{@downsample_factor}")
42
+ end
43
+ end
44
+ end
45
+ end
@@ -1,5 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require "rubygems"
4
+
3
5
  module Sentry
4
6
  # @api private
5
7
  class Backtrace
@@ -10,11 +12,11 @@ module Sentry
10
12
  RUBY_INPUT_FORMAT = /
11
13
  ^ \s* (?: [a-zA-Z]: | uri:classloader: )? ([^:]+ | <.*>):
12
14
  (\d+)
13
- (?: :in \s `([^']+)')?$
14
- /x.freeze
15
+ (?: :in\s('|`)(?:([\w:]+)\#)?([^']+)')?$
16
+ /x
15
17
 
16
18
  # org.jruby.runtime.callsite.CachingCallSite.call(CachingCallSite.java:170)
17
- JAVA_INPUT_FORMAT = /^(.+)\.([^\.]+)\(([^\:]+)\:(\d+)\)$/.freeze
19
+ JAVA_INPUT_FORMAT = /^([\w$.]+)\.([\w$]+)\(([\w$.]+):(\d+)\)$/
18
20
 
19
21
  # The file portion of the line (such as app/models/user.rb)
20
22
  attr_reader :file
@@ -33,12 +35,13 @@ module Sentry
33
35
  # Parses a single line of a given backtrace
34
36
  # @param [String] unparsed_line The raw line from +caller+ or some backtrace
35
37
  # @return [Line] The parsed backtrace line
36
- def self.parse(unparsed_line, in_app_pattern)
38
+ def self.parse(unparsed_line, in_app_pattern = nil)
37
39
  ruby_match = unparsed_line.match(RUBY_INPUT_FORMAT)
40
+
38
41
  if ruby_match
39
- _, file, number, method = ruby_match.to_a
42
+ _, file, number, _, module_name, method = ruby_match.to_a
40
43
  file.sub!(/\.class$/, RB_EXTENSION)
41
- module_name = nil
44
+ module_name = module_name
42
45
  else
43
46
  java_match = unparsed_line.match(JAVA_INPUT_FORMAT)
44
47
  _, module_name, method, file, number = java_match.to_a
@@ -55,6 +58,8 @@ module Sentry
55
58
  end
56
59
 
57
60
  def in_app
61
+ return false unless in_app_pattern
62
+
58
63
  if file =~ in_app_pattern
59
64
  true
60
65
  else
@@ -76,8 +81,6 @@ module Sentry
76
81
  end
77
82
  end
78
83
 
79
- APP_DIRS_PATTERN = /(bin|exe|app|config|lib|test|spec)/.freeze
80
-
81
84
  # holder for an Array of Backtrace::Line instances
82
85
  attr_reader :lines
83
86
 
@@ -87,7 +90,7 @@ module Sentry
87
90
  ruby_lines = backtrace_cleanup_callback.call(ruby_lines) if backtrace_cleanup_callback
88
91
 
89
92
  in_app_pattern ||= begin
90
- Regexp.new("^(#{project_root}/)?#{app_dirs_pattern || APP_DIRS_PATTERN}")
93
+ Regexp.new("^(#{project_root}/)?#{app_dirs_pattern}")
91
94
  end
92
95
 
93
96
  lines = ruby_lines.to_a.map do |unparsed_line|
@@ -1,12 +1,12 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'cgi'
3
+ require "cgi"
4
4
 
5
5
  module Sentry
6
6
  # A {https://www.w3.org/TR/baggage W3C Baggage Header} implementation.
7
7
  class Baggage
8
- SENTRY_PREFIX = 'sentry-'
9
- SENTRY_PREFIX_REGEX = /^sentry-/.freeze
8
+ SENTRY_PREFIX = "sentry-"
9
+ SENTRY_PREFIX_REGEX = /^sentry-/
10
10
 
11
11
  # @return [Hash]
12
12
  attr_reader :items
@@ -30,14 +30,14 @@ module Sentry
30
30
  items = {}
31
31
  mutable = true
32
32
 
33
- header.split(',').each do |item|
33
+ header.split(",").each do |item|
34
34
  item = item.strip
35
- key, val = item.split('=')
35
+ key, val = item.split("=")
36
36
 
37
37
  next unless key && val
38
38
  next unless key =~ SENTRY_PREFIX_REGEX
39
39
 
40
- baggage_key = key.split('-')[1]
40
+ baggage_key = key.split("-")[1]
41
41
  next unless baggage_key
42
42
 
43
43
  items[CGI.unescape(baggage_key)] = CGI.unescape(val)
@@ -64,7 +64,7 @@ module Sentry
64
64
  # @return [String]
65
65
  def serialize
66
66
  items = @items.map { |k, v| "#{SENTRY_PREFIX}#{CGI.escape(k)}=#{CGI.escape(v)}" }
67
- items.join(',')
67
+ items.join(",")
68
68
  end
69
69
  end
70
70
  end
@@ -1,16 +1,16 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'logger'
3
+ require "logger"
4
4
 
5
5
  module Sentry
6
6
  class Breadcrumb
7
7
  module SentryLogger
8
8
  LEVELS = {
9
- ::Logger::DEBUG => 'debug',
10
- ::Logger::INFO => 'info',
11
- ::Logger::WARN => 'warn',
12
- ::Logger::ERROR => 'error',
13
- ::Logger::FATAL => 'fatal'
9
+ ::Logger::DEBUG => "debug",
10
+ ::Logger::INFO => "info",
11
+ ::Logger::WARN => "warn",
12
+ ::Logger::ERROR => "error",
13
+ ::Logger::FATAL => "fatal"
14
14
  }.freeze
15
15
 
16
16
  def add(*args, &block)
@@ -2,6 +2,7 @@
2
2
 
3
3
  module Sentry
4
4
  class Breadcrumb
5
+ MAX_NESTING = 10
5
6
  DATA_SERIALIZATION_ERROR_MESSAGE = "[data were removed due to serialization issues]"
6
7
 
7
8
  # @return [String, nil]
@@ -9,7 +10,7 @@ module Sentry
9
10
  # @return [Hash, nil]
10
11
  attr_accessor :data
11
12
  # @return [String, nil]
12
- attr_accessor :level
13
+ attr_reader :level
13
14
  # @return [Time, Integer, nil]
14
15
  attr_accessor :timestamp
15
16
  # @return [String, nil]
@@ -26,10 +27,10 @@ module Sentry
26
27
  def initialize(category: nil, data: nil, message: nil, timestamp: nil, level: nil, type: nil)
27
28
  @category = category
28
29
  @data = data || {}
29
- @level = level
30
30
  @timestamp = timestamp || Sentry.utc_now.to_i
31
31
  @type = type
32
32
  self.message = message
33
+ self.level = level
33
34
  end
34
35
 
35
36
  # @return [Hash]
@@ -47,23 +48,29 @@ module Sentry
47
48
  # @param message [String]
48
49
  # @return [void]
49
50
  def message=(message)
50
- @message = (message || "").byteslice(0..Event::MAX_MESSAGE_SIZE_IN_BYTES)
51
+ @message = message && Utils::EncodingHelper.valid_utf_8?(message) ? message.byteslice(0..Event::MAX_MESSAGE_SIZE_IN_BYTES) : ""
52
+ end
53
+
54
+ # @param level [String]
55
+ # @return [void]
56
+ def level=(level) # needed to meet the Sentry spec
57
+ @level = level == "warn" ? "warning" : level
51
58
  end
52
59
 
53
60
  private
54
61
 
55
62
  def serialized_data
56
63
  begin
57
- ::JSON.parse(::JSON.generate(@data))
64
+ ::JSON.parse(::JSON.generate(@data, max_nesting: MAX_NESTING))
58
65
  rescue Exception => e
59
- Sentry.logger.debug(LOGGER_PROGNAME) do
66
+ Sentry.sdk_logger.debug(LOGGER_PROGNAME) do
60
67
  <<~MSG
61
68
  can't serialize breadcrumb data because of error: #{e}
62
69
  data: #{@data}
63
70
  MSG
64
71
  end
65
72
 
66
- DATA_SERIALIZATION_ERROR_MESSAGE
73
+ { error: DATA_SERIALIZATION_ERROR_MESSAGE }
67
74
  end
68
75
  end
69
76
  end
@@ -0,0 +1,61 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "securerandom"
4
+ require "sentry/cron/monitor_config"
5
+ require "sentry/utils/uuid"
6
+
7
+ module Sentry
8
+ class CheckInEvent < Event
9
+ TYPE = "check_in"
10
+
11
+ # uuid to identify this check-in.
12
+ # @return [String]
13
+ attr_accessor :check_in_id
14
+
15
+ # Identifier of the monitor for this check-in.
16
+ # @return [String]
17
+ attr_accessor :monitor_slug
18
+
19
+ # Duration of this check since it has started in seconds.
20
+ # @return [Integer, nil]
21
+ attr_accessor :duration
22
+
23
+ # Monitor configuration to support upserts.
24
+ # @return [Cron::MonitorConfig, nil]
25
+ attr_accessor :monitor_config
26
+
27
+ # Status of this check-in.
28
+ # @return [Symbol]
29
+ attr_accessor :status
30
+
31
+ VALID_STATUSES = %i[ok in_progress error]
32
+
33
+ def initialize(
34
+ slug:,
35
+ status:,
36
+ duration: nil,
37
+ monitor_config: nil,
38
+ check_in_id: nil,
39
+ **options
40
+ )
41
+ super(**options)
42
+
43
+ self.monitor_slug = slug
44
+ self.status = status
45
+ self.duration = duration
46
+ self.monitor_config = monitor_config
47
+ self.check_in_id = check_in_id || Utils.uuid
48
+ end
49
+
50
+ # @return [Hash]
51
+ def to_hash
52
+ data = super
53
+ data[:check_in_id] = check_in_id
54
+ data[:monitor_slug] = monitor_slug
55
+ data[:status] = status
56
+ data[:duration] = duration if duration
57
+ data[:monitor_config] = monitor_config.to_hash if monitor_config
58
+ data
59
+ end
60
+ end
61
+ end