sentry-ruby 5.18.2 → 5.28.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.
- checksums.yaml +4 -4
- data/.rspec +3 -1
- data/Gemfile +9 -3
- data/README.md +12 -7
- data/Rakefile +9 -11
- data/bin/console +1 -0
- data/lib/sentry/attachment.rb +40 -0
- data/lib/sentry/background_worker.rb +2 -3
- data/lib/sentry/backpressure_monitor.rb +1 -1
- data/lib/sentry/backtrace.rb +7 -8
- data/lib/sentry/baggage.rb +7 -7
- data/lib/sentry/breadcrumb/sentry_logger.rb +6 -6
- data/lib/sentry/breadcrumb.rb +5 -4
- data/lib/sentry/check_in_event.rb +5 -4
- data/lib/sentry/client.rb +121 -19
- data/lib/sentry/configuration.rb +207 -38
- data/lib/sentry/core_ext/object/deep_dup.rb +1 -1
- data/lib/sentry/cron/monitor_check_ins.rb +6 -4
- data/lib/sentry/cron/monitor_config.rb +1 -1
- data/lib/sentry/debug_structured_logger.rb +94 -0
- data/lib/sentry/dsn.rb +35 -3
- data/lib/sentry/envelope/item.rb +88 -0
- data/lib/sentry/envelope.rb +2 -85
- data/lib/sentry/event.rb +13 -8
- data/lib/sentry/excon/middleware.rb +77 -0
- data/lib/sentry/excon.rb +10 -0
- data/lib/sentry/faraday.rb +77 -0
- data/lib/sentry/graphql.rb +1 -1
- data/lib/sentry/hub.rb +57 -4
- data/lib/sentry/interfaces/mechanism.rb +1 -1
- data/lib/sentry/interfaces/request.rb +6 -6
- data/lib/sentry/interfaces/single_exception.rb +3 -3
- data/lib/sentry/interfaces/stacktrace.rb +3 -1
- data/lib/sentry/interfaces/stacktrace_builder.rb +15 -2
- data/lib/sentry/linecache.rb +3 -3
- data/lib/sentry/log_event.rb +219 -0
- data/lib/sentry/log_event_buffer.rb +75 -0
- data/lib/sentry/logger.rb +1 -1
- data/lib/sentry/metrics/aggregator.rb +13 -13
- data/lib/sentry/metrics/configuration.rb +12 -2
- data/lib/sentry/metrics/set_metric.rb +2 -2
- data/lib/sentry/metrics/timing.rb +8 -0
- data/lib/sentry/metrics.rb +27 -15
- data/lib/sentry/net/http.rb +17 -38
- data/lib/sentry/profiler/helpers.rb +46 -0
- data/lib/sentry/profiler.rb +27 -57
- data/lib/sentry/propagation_context.rb +60 -23
- data/lib/sentry/rack/capture_exceptions.rb +2 -2
- data/lib/sentry/rack.rb +2 -2
- data/lib/sentry/rake.rb +2 -2
- data/lib/sentry/release_detector.rb +4 -4
- data/lib/sentry/rspec.rb +91 -0
- data/lib/sentry/scope.rb +27 -2
- data/lib/sentry/session_flusher.rb +10 -6
- data/lib/sentry/span.rb +17 -4
- data/lib/sentry/std_lib_logger.rb +55 -0
- data/lib/sentry/structured_logger.rb +138 -0
- data/lib/sentry/test_helper.rb +45 -1
- data/lib/sentry/threaded_periodic_worker.rb +3 -3
- data/lib/sentry/transaction.rb +41 -13
- data/lib/sentry/transaction_event.rb +5 -3
- data/lib/sentry/transport/debug_transport.rb +70 -0
- data/lib/sentry/transport/dummy_transport.rb +1 -0
- data/lib/sentry/transport/http_transport.rb +21 -18
- data/lib/sentry/transport.rb +26 -11
- data/lib/sentry/utils/env_helper.rb +21 -0
- data/lib/sentry/utils/http_tracing.rb +74 -0
- data/lib/sentry/utils/logging_helper.rb +10 -3
- data/lib/sentry/utils/real_ip.rb +1 -1
- data/lib/sentry/utils/sample_rand.rb +97 -0
- data/lib/sentry/utils/uuid.rb +13 -0
- data/lib/sentry/vernier/output.rb +89 -0
- data/lib/sentry/vernier/profiler.rb +132 -0
- data/lib/sentry/version.rb +1 -1
- data/lib/sentry-ruby.rb +106 -12
- data/sentry-ruby-core.gemspec +3 -1
- data/sentry-ruby.gemspec +4 -2
- metadata +28 -12
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 496e873f83c42877eabed1e6aac9db6e6f043ce9d3d2f5725d6905ddfce917c0
|
|
4
|
+
data.tar.gz: 9e66db9076448282ced30a490dbf07dddd45ce30fa19b514586804f719d3fae6
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 40d1b342d7d6fd63c03f427e9ea3b6391c52252d40d9d22bea5d17d9b175ae9a6e559810eeecc806634355561c51f2f6237b3dc17a0eb43754bb940ce111a36a
|
|
7
|
+
data.tar.gz: 6c4c5dffc5d389dfb365a2678b2545c6681aebe7bdb6aac702cb2e6fc7b540030575696cdb55794501e0effbdeb5b15f7ac88516e49f34bbfba91601187e995b
|
data/.rspec
CHANGED
data/Gemfile
CHANGED
|
@@ -1,6 +1,10 @@
|
|
|
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.dev"
|
|
7
|
+
|
|
4
8
|
gem "sentry-ruby", path: "./"
|
|
5
9
|
|
|
6
10
|
rack_version = ENV["RACK_VERSION"]
|
|
@@ -14,6 +18,7 @@ gem "puma"
|
|
|
14
18
|
|
|
15
19
|
gem "timecop"
|
|
16
20
|
gem "stackprof" unless RUBY_PLATFORM == "java"
|
|
21
|
+
gem "vernier", platforms: :ruby if RUBY_VERSION >= "3.2.1"
|
|
17
22
|
|
|
18
23
|
gem "graphql", ">= 2.2.6" if RUBY_VERSION.to_f >= 2.7
|
|
19
24
|
|
|
@@ -22,7 +27,8 @@ gem "benchmark_driver"
|
|
|
22
27
|
gem "benchmark-ipsa"
|
|
23
28
|
gem "benchmark-memory"
|
|
24
29
|
|
|
25
|
-
gem "yard"
|
|
30
|
+
gem "yard"
|
|
26
31
|
gem "webrick"
|
|
27
|
-
|
|
28
|
-
|
|
32
|
+
gem "faraday"
|
|
33
|
+
gem "excon"
|
|
34
|
+
gem "webmock"
|
data/README.md
CHANGED
|
@@ -15,12 +15,12 @@ Sentry SDK for Ruby
|
|
|
15
15
|
|
|
16
16
|
| Current version | Build | Coverage | API doc |
|
|
17
17
|
| ---------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------ | -------------------------------------------------------------------------------------------------------------------------- |
|
|
18
|
-
| [](https://rubygems.org/gems/sentry-ruby) | [](https://rubygems.org/gems/sentry-rails) | [](https://rubygems.org/gems/sentry-sidekiq) | [](https://rubygems.org/gems/sentry-delayed_job) | [](https://rubygems.org/gems/sentry-resque) | [](https://rubygems.org/gems/sentry-opentelemetry) | [](https://rubygems.org/gems/sentry-ruby) | [](https://github.com/getsentry/sentry-ruby/actions/workflows/tests.yml) | [](https://codecov.io/gh/getsentry/sentry-ruby) | [](https://www.rubydoc.info/gems/sentry-ruby) |
|
|
19
|
+
| [](https://rubygems.org/gems/sentry-rails) | [](https://github.com/getsentry/sentry-ruby/actions/workflows/tests.yml) | [](https://codecov.io/gh/getsentry/sentry-ruby) | [](https://www.rubydoc.info/gems/sentry-rails) |
|
|
20
|
+
| [](https://rubygems.org/gems/sentry-sidekiq) | [](https://github.com/getsentry/sentry-ruby/actions/workflows/tests.yml) | [](https://codecov.io/gh/getsentry/sentry-ruby) | [](https://www.rubydoc.info/gems/sentry-sidekiq) |
|
|
21
|
+
| [](https://rubygems.org/gems/sentry-delayed_job) | [](https://github.com/getsentry/sentry-ruby/actions/workflows/tests.yml) | [](https://codecov.io/gh/getsentry/sentry-ruby) | [](https://www.rubydoc.info/gems/sentry-delayed_job) |
|
|
22
|
+
| [](https://rubygems.org/gems/sentry-resque) | [](https://github.com/getsentry/sentry-ruby/actions/workflows/tests.yml) | [](https://codecov.io/gh/getsentry/sentry-ruby) | [](https://www.rubydoc.info/gems/sentry-resque) |
|
|
23
|
+
| [](https://rubygems.org/gems/sentry-opentelemetry) | [](https://github.com/getsentry/sentry-ruby/actions/workflows/tests.yml) | [](https://codecov.io/gh/getsentry/sentry-ruby) | [](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 from Ruby 2.4 to Ruby 3.
|
|
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
|
|
@@ -116,3 +118,6 @@ Thanks to everyone who has contributed to this project so far.
|
|
|
116
118
|
<a href="https://github.com/getsentry/sentry-ruby/graphs/contributors">
|
|
117
119
|
<img src="https://contributors-img.web.app/image?repo=getsentry/sentry-ruby" />
|
|
118
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
|
-
|
|
9
|
+
require_relative "../lib/sentry/test/rake_tasks"
|
|
8
10
|
|
|
9
|
-
|
|
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
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
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, :
|
|
18
|
+
task default: [:spec, :"spec:isolated"]
|
data/bin/console
CHANGED
|
@@ -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,8 +9,7 @@ module Sentry
|
|
|
9
9
|
include LoggingHelper
|
|
10
10
|
|
|
11
11
|
attr_reader :max_queue, :number_of_threads
|
|
12
|
-
|
|
13
|
-
attr_reader :logger
|
|
12
|
+
|
|
14
13
|
attr_accessor :shutdown_timeout
|
|
15
14
|
|
|
16
15
|
DEFAULT_MAX_QUEUE = 30
|
|
@@ -19,7 +18,7 @@ module Sentry
|
|
|
19
18
|
@shutdown_timeout = 1
|
|
20
19
|
@number_of_threads = configuration.background_worker_threads
|
|
21
20
|
@max_queue = configuration.background_worker_max_queue
|
|
22
|
-
@
|
|
21
|
+
@sdk_logger = configuration.sdk_logger
|
|
23
22
|
@debug = configuration.debug
|
|
24
23
|
@shutdown_callback = nil
|
|
25
24
|
|
data/lib/sentry/backtrace.rb
CHANGED
|
@@ -12,11 +12,11 @@ module Sentry
|
|
|
12
12
|
RUBY_INPUT_FORMAT = /
|
|
13
13
|
^ \s* (?: [a-zA-Z]: | uri:classloader: )? ([^:]+ | <.*>):
|
|
14
14
|
(\d+)
|
|
15
|
-
(?: :in\s('|`)([^']+)')?$
|
|
16
|
-
/x
|
|
15
|
+
(?: :in\s('|`)(?:([\w:]+)\#)?([^']+)')?$
|
|
16
|
+
/x
|
|
17
17
|
|
|
18
18
|
# org.jruby.runtime.callsite.CachingCallSite.call(CachingCallSite.java:170)
|
|
19
|
-
JAVA_INPUT_FORMAT = /^(
|
|
19
|
+
JAVA_INPUT_FORMAT = /^([\w$.]+)\.([\w$]+)\(([\w$.]+):(\d+)\)$/
|
|
20
20
|
|
|
21
21
|
# The file portion of the line (such as app/models/user.rb)
|
|
22
22
|
attr_reader :file
|
|
@@ -37,10 +37,11 @@ module Sentry
|
|
|
37
37
|
# @return [Line] The parsed backtrace line
|
|
38
38
|
def self.parse(unparsed_line, in_app_pattern = nil)
|
|
39
39
|
ruby_match = unparsed_line.match(RUBY_INPUT_FORMAT)
|
|
40
|
+
|
|
40
41
|
if ruby_match
|
|
41
|
-
_, file, number, _, method = ruby_match.to_a
|
|
42
|
+
_, file, number, _, module_name, method = ruby_match.to_a
|
|
42
43
|
file.sub!(/\.class$/, RB_EXTENSION)
|
|
43
|
-
module_name =
|
|
44
|
+
module_name = module_name
|
|
44
45
|
else
|
|
45
46
|
java_match = unparsed_line.match(JAVA_INPUT_FORMAT)
|
|
46
47
|
_, module_name, method, file, number = java_match.to_a
|
|
@@ -80,8 +81,6 @@ module Sentry
|
|
|
80
81
|
end
|
|
81
82
|
end
|
|
82
83
|
|
|
83
|
-
APP_DIRS_PATTERN = /(bin|exe|app|config|lib|test|spec)/.freeze
|
|
84
|
-
|
|
85
84
|
# holder for an Array of Backtrace::Line instances
|
|
86
85
|
attr_reader :lines
|
|
87
86
|
|
|
@@ -91,7 +90,7 @@ module Sentry
|
|
|
91
90
|
ruby_lines = backtrace_cleanup_callback.call(ruby_lines) if backtrace_cleanup_callback
|
|
92
91
|
|
|
93
92
|
in_app_pattern ||= begin
|
|
94
|
-
Regexp.new("^(#{project_root}/)?#{app_dirs_pattern
|
|
93
|
+
Regexp.new("^(#{project_root}/)?#{app_dirs_pattern}")
|
|
95
94
|
end
|
|
96
95
|
|
|
97
96
|
lines = ruby_lines.to_a.map do |unparsed_line|
|
data/lib/sentry/baggage.rb
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require
|
|
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 =
|
|
9
|
-
SENTRY_PREFIX_REGEX = /^sentry
|
|
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(
|
|
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(
|
|
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
|
|
3
|
+
require "logger"
|
|
4
4
|
|
|
5
5
|
module Sentry
|
|
6
6
|
class Breadcrumb
|
|
7
7
|
module SentryLogger
|
|
8
8
|
LEVELS = {
|
|
9
|
-
::Logger::DEBUG =>
|
|
10
|
-
::Logger::INFO =>
|
|
11
|
-
::Logger::WARN =>
|
|
12
|
-
::Logger::ERROR =>
|
|
13
|
-
::Logger::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)
|
data/lib/sentry/breadcrumb.rb
CHANGED
|
@@ -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]
|
|
@@ -47,7 +48,7 @@ module Sentry
|
|
|
47
48
|
# @param message [String]
|
|
48
49
|
# @return [void]
|
|
49
50
|
def message=(message)
|
|
50
|
-
@message = (message
|
|
51
|
+
@message = message && Utils::EncodingHelper.valid_utf_8?(message) ? message.byteslice(0..Event::MAX_MESSAGE_SIZE_IN_BYTES) : ""
|
|
51
52
|
end
|
|
52
53
|
|
|
53
54
|
# @param level [String]
|
|
@@ -60,16 +61,16 @@ module Sentry
|
|
|
60
61
|
|
|
61
62
|
def serialized_data
|
|
62
63
|
begin
|
|
63
|
-
::JSON.parse(::JSON.generate(@data))
|
|
64
|
+
::JSON.parse(::JSON.generate(@data, max_nesting: MAX_NESTING))
|
|
64
65
|
rescue Exception => e
|
|
65
|
-
Sentry.
|
|
66
|
+
Sentry.sdk_logger.debug(LOGGER_PROGNAME) do
|
|
66
67
|
<<~MSG
|
|
67
68
|
can't serialize breadcrumb data because of error: #{e}
|
|
68
69
|
data: #{@data}
|
|
69
70
|
MSG
|
|
70
71
|
end
|
|
71
72
|
|
|
72
|
-
DATA_SERIALIZATION_ERROR_MESSAGE
|
|
73
|
+
{ error: DATA_SERIALIZATION_ERROR_MESSAGE }
|
|
73
74
|
end
|
|
74
75
|
end
|
|
75
76
|
end
|
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require
|
|
4
|
-
require
|
|
3
|
+
require "securerandom"
|
|
4
|
+
require "sentry/cron/monitor_config"
|
|
5
|
+
require "sentry/utils/uuid"
|
|
5
6
|
|
|
6
7
|
module Sentry
|
|
7
8
|
class CheckInEvent < Event
|
|
8
|
-
TYPE =
|
|
9
|
+
TYPE = "check_in"
|
|
9
10
|
|
|
10
11
|
# uuid to identify this check-in.
|
|
11
12
|
# @return [String]
|
|
@@ -43,7 +44,7 @@ module Sentry
|
|
|
43
44
|
self.status = status
|
|
44
45
|
self.duration = duration
|
|
45
46
|
self.monitor_config = monitor_config
|
|
46
|
-
self.check_in_id = check_in_id ||
|
|
47
|
+
self.check_in_id = check_in_id || Utils.uuid
|
|
47
48
|
end
|
|
48
49
|
|
|
49
50
|
# @return [Hash]
|
data/lib/sentry/client.rb
CHANGED
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
require "sentry/transport"
|
|
4
|
+
require "sentry/log_event"
|
|
5
|
+
require "sentry/log_event_buffer"
|
|
6
|
+
require "sentry/utils/uuid"
|
|
4
7
|
|
|
5
8
|
module Sentry
|
|
6
9
|
class Client
|
|
@@ -14,23 +17,23 @@ module Sentry
|
|
|
14
17
|
# @return [SpotlightTransport, nil]
|
|
15
18
|
attr_reader :spotlight_transport
|
|
16
19
|
|
|
20
|
+
# @!visibility private
|
|
21
|
+
attr_reader :log_event_buffer
|
|
22
|
+
|
|
17
23
|
# @!macro configuration
|
|
18
24
|
attr_reader :configuration
|
|
19
25
|
|
|
20
|
-
# @deprecated Use Sentry.logger to retrieve the current logger instead.
|
|
21
|
-
attr_reader :logger
|
|
22
|
-
|
|
23
26
|
# @param configuration [Configuration]
|
|
24
27
|
def initialize(configuration)
|
|
25
28
|
@configuration = configuration
|
|
26
|
-
@
|
|
29
|
+
@sdk_logger = configuration.sdk_logger
|
|
27
30
|
|
|
28
31
|
if transport_class = configuration.transport.transport_class
|
|
29
32
|
@transport = transport_class.new(configuration)
|
|
30
33
|
else
|
|
31
34
|
@transport =
|
|
32
35
|
case configuration.dsn&.scheme
|
|
33
|
-
when
|
|
36
|
+
when "http", "https"
|
|
34
37
|
HTTPTransport.new(configuration)
|
|
35
38
|
else
|
|
36
39
|
DummyTransport.new(configuration)
|
|
@@ -38,6 +41,10 @@ module Sentry
|
|
|
38
41
|
end
|
|
39
42
|
|
|
40
43
|
@spotlight_transport = SpotlightTransport.new(configuration) if configuration.spotlight
|
|
44
|
+
|
|
45
|
+
if configuration.enable_logs
|
|
46
|
+
@log_event_buffer = LogEventBuffer.new(configuration, self).start
|
|
47
|
+
end
|
|
41
48
|
end
|
|
42
49
|
|
|
43
50
|
# Applies the given scope's data to the event and sends it to Sentry.
|
|
@@ -49,7 +56,7 @@ module Sentry
|
|
|
49
56
|
return unless configuration.sending_allowed?
|
|
50
57
|
|
|
51
58
|
if event.is_a?(ErrorEvent) && !configuration.sample_allowed?
|
|
52
|
-
transport.record_lost_event(:sample_rate,
|
|
59
|
+
transport.record_lost_event(:sample_rate, "error")
|
|
53
60
|
return
|
|
54
61
|
end
|
|
55
62
|
|
|
@@ -64,11 +71,11 @@ module Sentry
|
|
|
64
71
|
if event.nil?
|
|
65
72
|
log_debug("Discarded event because one of the event processors returned nil")
|
|
66
73
|
transport.record_lost_event(:event_processor, data_category)
|
|
67
|
-
transport.record_lost_event(:event_processor,
|
|
74
|
+
transport.record_lost_event(:event_processor, "span", num: spans_before + 1) if is_transaction
|
|
68
75
|
return
|
|
69
76
|
elsif is_transaction
|
|
70
77
|
spans_delta = spans_before - event.spans.size
|
|
71
|
-
transport.record_lost_event(:event_processor,
|
|
78
|
+
transport.record_lost_event(:event_processor, "span", num: spans_delta) if spans_delta > 0
|
|
72
79
|
end
|
|
73
80
|
|
|
74
81
|
if async_block = configuration.async
|
|
@@ -76,7 +83,7 @@ module Sentry
|
|
|
76
83
|
elsif configuration.background_worker_threads != 0 && hint.fetch(:background, true)
|
|
77
84
|
unless dispatch_background_event(event, hint)
|
|
78
85
|
transport.record_lost_event(:queue_overflow, data_category)
|
|
79
|
-
transport.record_lost_event(:queue_overflow,
|
|
86
|
+
transport.record_lost_event(:queue_overflow, "span", num: spans_before + 1) if is_transaction
|
|
80
87
|
end
|
|
81
88
|
else
|
|
82
89
|
send_event(event, hint)
|
|
@@ -88,6 +95,15 @@ module Sentry
|
|
|
88
95
|
nil
|
|
89
96
|
end
|
|
90
97
|
|
|
98
|
+
# Buffer a log event to be sent later with other logs in a single envelope
|
|
99
|
+
# @param event [LogEvent] the log event to be buffered
|
|
100
|
+
# @return [LogEvent]
|
|
101
|
+
def buffer_log_event(event, scope)
|
|
102
|
+
return unless event.is_a?(LogEvent)
|
|
103
|
+
@log_event_buffer.add_event(scope.apply_to_event(event))
|
|
104
|
+
event
|
|
105
|
+
end
|
|
106
|
+
|
|
91
107
|
# Capture an envelope directly.
|
|
92
108
|
# @param envelope [Envelope] the envelope to be captured.
|
|
93
109
|
# @return [void]
|
|
@@ -100,6 +116,7 @@ module Sentry
|
|
|
100
116
|
def flush
|
|
101
117
|
transport.flush if configuration.sending_to_dsn_allowed?
|
|
102
118
|
spotlight_transport.flush if spotlight_transport
|
|
119
|
+
@log_event_buffer&.flush
|
|
103
120
|
end
|
|
104
121
|
|
|
105
122
|
# Initializes an Event object with the given exception. Returns `nil` if the exception's class is excluded from reporting.
|
|
@@ -167,6 +184,23 @@ module Sentry
|
|
|
167
184
|
)
|
|
168
185
|
end
|
|
169
186
|
|
|
187
|
+
# Initializes a LogEvent object with the given message and options
|
|
188
|
+
#
|
|
189
|
+
# @param message [String] the log message
|
|
190
|
+
# @param level [Symbol] the log level (:trace, :debug, :info, :warn, :error, :fatal)
|
|
191
|
+
# @param options [Hash] additional options
|
|
192
|
+
# @option options [Array] :parameters Array of values to replace template tokens in the message
|
|
193
|
+
#
|
|
194
|
+
# @return [LogEvent] the created log event
|
|
195
|
+
def event_from_log(message, level:, **options)
|
|
196
|
+
return unless configuration.sending_allowed?
|
|
197
|
+
|
|
198
|
+
attributes = options.reject { |k, _| k == :level || k == :severity || k == :origin }
|
|
199
|
+
origin = options[:origin]
|
|
200
|
+
|
|
201
|
+
LogEvent.new(level: level, body: message, attributes: attributes, origin: origin)
|
|
202
|
+
end
|
|
203
|
+
|
|
170
204
|
# Initializes an Event object with the given Transaction object.
|
|
171
205
|
# @param transaction [Transaction] the transaction to be recorded.
|
|
172
206
|
# @return [TransactionEvent]
|
|
@@ -183,8 +217,19 @@ module Sentry
|
|
|
183
217
|
if event_type != TransactionEvent::TYPE && configuration.before_send
|
|
184
218
|
event = configuration.before_send.call(event, hint)
|
|
185
219
|
|
|
186
|
-
|
|
187
|
-
|
|
220
|
+
case event
|
|
221
|
+
when ErrorEvent, CheckInEvent
|
|
222
|
+
# do nothing
|
|
223
|
+
when Hash
|
|
224
|
+
log_debug(<<~MSG)
|
|
225
|
+
Returning a Hash from before_send is deprecated and will be removed in the next major version.
|
|
226
|
+
Please return a Sentry::ErrorEvent object instead.
|
|
227
|
+
MSG
|
|
228
|
+
else
|
|
229
|
+
# Avoid serializing the event object in this case because we aren't sure what it is and what it contains
|
|
230
|
+
log_debug(<<~MSG)
|
|
231
|
+
Discarded event because before_send didn't return a Sentry::ErrorEvent object but an instance of #{event.class}
|
|
232
|
+
MSG
|
|
188
233
|
transport.record_lost_event(:before_send, data_category)
|
|
189
234
|
return
|
|
190
235
|
end
|
|
@@ -193,15 +238,25 @@ module Sentry
|
|
|
193
238
|
if event_type == TransactionEvent::TYPE && configuration.before_send_transaction
|
|
194
239
|
event = configuration.before_send_transaction.call(event, hint)
|
|
195
240
|
|
|
196
|
-
if event.
|
|
197
|
-
log_debug("Discarded event because before_send_transaction returned nil")
|
|
198
|
-
transport.record_lost_event(:before_send, 'transaction')
|
|
199
|
-
transport.record_lost_event(:before_send, 'span', num: spans_before + 1)
|
|
200
|
-
return
|
|
201
|
-
else
|
|
241
|
+
if event.is_a?(TransactionEvent) || event.is_a?(Hash)
|
|
202
242
|
spans_after = event.is_a?(TransactionEvent) ? event.spans.size : 0
|
|
203
243
|
spans_delta = spans_before - spans_after
|
|
204
|
-
transport.record_lost_event(:before_send,
|
|
244
|
+
transport.record_lost_event(:before_send, "span", num: spans_delta) if spans_delta > 0
|
|
245
|
+
|
|
246
|
+
if event.is_a?(Hash)
|
|
247
|
+
log_debug(<<~MSG)
|
|
248
|
+
Returning a Hash from before_send_transaction is deprecated and will be removed in the next major version.
|
|
249
|
+
Please return a Sentry::TransactionEvent object instead.
|
|
250
|
+
MSG
|
|
251
|
+
end
|
|
252
|
+
else
|
|
253
|
+
# Avoid serializing the event object in this case because we aren't sure what it is and what it contains
|
|
254
|
+
log_debug(<<~MSG)
|
|
255
|
+
Discarded event because before_send_transaction didn't return a Sentry::TransactionEvent object but an instance of #{event.class}
|
|
256
|
+
MSG
|
|
257
|
+
transport.record_lost_event(:before_send, "transaction")
|
|
258
|
+
transport.record_lost_event(:before_send, "span", num: spans_before + 1)
|
|
259
|
+
return
|
|
205
260
|
end
|
|
206
261
|
end
|
|
207
262
|
|
|
@@ -212,10 +267,57 @@ module Sentry
|
|
|
212
267
|
rescue => e
|
|
213
268
|
log_error("Event sending failed", e, debug: configuration.debug)
|
|
214
269
|
transport.record_lost_event(:network_error, data_category)
|
|
215
|
-
transport.record_lost_event(:network_error,
|
|
270
|
+
transport.record_lost_event(:network_error, "span", num: spans_before + 1) if event.is_a?(TransactionEvent)
|
|
216
271
|
raise
|
|
217
272
|
end
|
|
218
273
|
|
|
274
|
+
# Send an envelope with batched logs
|
|
275
|
+
# @param log_events [Array<LogEvent>] the log events to be sent
|
|
276
|
+
# @api private
|
|
277
|
+
# @return [void]
|
|
278
|
+
def send_logs(log_events)
|
|
279
|
+
envelope = Envelope.new(
|
|
280
|
+
event_id: Sentry::Utils.uuid,
|
|
281
|
+
sent_at: Sentry.utc_now.iso8601,
|
|
282
|
+
dsn: configuration.dsn,
|
|
283
|
+
sdk: Sentry.sdk_meta
|
|
284
|
+
)
|
|
285
|
+
|
|
286
|
+
discarded_count = 0
|
|
287
|
+
envelope_items = []
|
|
288
|
+
|
|
289
|
+
if configuration.before_send_log
|
|
290
|
+
log_events.each do |log_event|
|
|
291
|
+
processed_log_event = configuration.before_send_log.call(log_event)
|
|
292
|
+
|
|
293
|
+
if processed_log_event
|
|
294
|
+
envelope_items << processed_log_event.to_hash
|
|
295
|
+
else
|
|
296
|
+
discarded_count += 1
|
|
297
|
+
end
|
|
298
|
+
end
|
|
299
|
+
|
|
300
|
+
envelope_items
|
|
301
|
+
else
|
|
302
|
+
envelope_items = log_events.map(&:to_hash)
|
|
303
|
+
end
|
|
304
|
+
|
|
305
|
+
envelope.add_item(
|
|
306
|
+
{
|
|
307
|
+
type: "log",
|
|
308
|
+
item_count: envelope_items.size,
|
|
309
|
+
content_type: "application/vnd.sentry.items.log+json"
|
|
310
|
+
},
|
|
311
|
+
{ items: envelope_items }
|
|
312
|
+
)
|
|
313
|
+
|
|
314
|
+
send_envelope(envelope)
|
|
315
|
+
|
|
316
|
+
unless discarded_count.zero?
|
|
317
|
+
transport.record_lost_event(:before_send, "log_item", num: discarded_count)
|
|
318
|
+
end
|
|
319
|
+
end
|
|
320
|
+
|
|
219
321
|
# Send an envelope directly to Sentry.
|
|
220
322
|
# @param envelope [Envelope] the envelope to be sent.
|
|
221
323
|
# @return [void]
|