sentry-ruby 5.28.1 → 6.3.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/Gemfile +25 -1
- data/README.md +2 -2
- data/lib/sentry/background_worker.rb +1 -4
- data/lib/sentry/backtrace/line.rb +99 -0
- data/lib/sentry/backtrace.rb +44 -76
- data/lib/sentry/breadcrumb.rb +1 -1
- data/lib/sentry/breadcrumb_buffer.rb +2 -2
- data/lib/sentry/check_in_event.rb +2 -2
- data/lib/sentry/client.rb +57 -135
- data/lib/sentry/configuration.rb +117 -75
- data/lib/sentry/cron/monitor_check_ins.rb +3 -3
- data/lib/sentry/cron/monitor_config.rb +2 -2
- data/lib/sentry/cron/monitor_schedule.rb +2 -2
- data/lib/sentry/envelope/item.rb +3 -3
- data/lib/sentry/error_event.rb +3 -3
- data/lib/sentry/event.rb +4 -10
- data/lib/sentry/hub.rb +26 -4
- data/lib/sentry/interface.rb +1 -1
- data/lib/sentry/interfaces/exception.rb +2 -2
- data/lib/sentry/interfaces/request.rb +2 -0
- data/lib/sentry/interfaces/single_exception.rb +4 -4
- data/lib/sentry/interfaces/stacktrace.rb +3 -3
- data/lib/sentry/interfaces/stacktrace_builder.rb +0 -8
- data/lib/sentry/interfaces/threads.rb +2 -2
- data/lib/sentry/log_event.rb +24 -142
- data/lib/sentry/log_event_buffer.rb +13 -60
- data/lib/sentry/metric_event.rb +49 -0
- data/lib/sentry/metric_event_buffer.rb +28 -0
- data/lib/sentry/metrics.rb +47 -54
- data/lib/sentry/profiler.rb +4 -5
- data/lib/sentry/rack/capture_exceptions.rb +5 -1
- data/lib/sentry/rspec.rb +1 -1
- data/lib/sentry/scope.rb +50 -18
- data/lib/sentry/sequel.rb +35 -0
- data/lib/sentry/span.rb +2 -17
- data/lib/sentry/std_lib_logger.rb +4 -0
- data/lib/sentry/telemetry_event_buffer.rb +130 -0
- data/lib/sentry/test_helper.rb +8 -0
- data/lib/sentry/transaction.rb +52 -103
- data/lib/sentry/transaction_event.rb +4 -9
- data/lib/sentry/transport.rb +2 -5
- data/lib/sentry/utils/encoding_helper.rb +6 -0
- data/lib/sentry/utils/logging_helper.rb +25 -9
- data/lib/sentry/utils/telemetry_attributes.rb +30 -0
- data/lib/sentry/vernier/profiler.rb +4 -3
- data/lib/sentry/version.rb +1 -1
- data/lib/sentry-ruby.rb +53 -30
- data/sentry-ruby-core.gemspec +1 -1
- data/sentry-ruby.gemspec +2 -1
- metadata +27 -16
- data/lib/sentry/metrics/aggregator.rb +0 -248
- data/lib/sentry/metrics/configuration.rb +0 -57
- data/lib/sentry/metrics/counter_metric.rb +0 -25
- data/lib/sentry/metrics/distribution_metric.rb +0 -25
- data/lib/sentry/metrics/gauge_metric.rb +0 -35
- data/lib/sentry/metrics/local_aggregator.rb +0 -53
- data/lib/sentry/metrics/metric.rb +0 -19
- data/lib/sentry/metrics/set_metric.rb +0 -28
- data/lib/sentry/metrics/timing.rb +0 -51
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 647044ccdd8924b2fb1624eca16311ee75855ff8faaf698e8c29b4583b34b0e2
|
|
4
|
+
data.tar.gz: d214dacdee8ac12cf8d6d18844ddc35fce588ed2ad2bd5299945ebc4f342ed00
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: c9bff18970cb7b9c4db570fa833b47933ce107c327aa260ba7612d1926329215d56c36349d187d998e1badf66f1089abbd477318dddd1975453d361bf7e7e242
|
|
7
|
+
data.tar.gz: 6ab13dae0fa67266128b9c5813b9e20dfa3e96d6852aae2179b0506a85b51947bb2650ec607784aaf9c20adb0469b2bce38c2ec14ef216f8dd85fa669809690d
|
data/Gemfile
CHANGED
|
@@ -7,8 +7,11 @@ eval_gemfile "../Gemfile.dev"
|
|
|
7
7
|
|
|
8
8
|
gem "sentry-ruby", path: "./"
|
|
9
9
|
|
|
10
|
+
ruby_version = Gem::Version.new(RUBY_VERSION)
|
|
11
|
+
|
|
10
12
|
rack_version = ENV["RACK_VERSION"]
|
|
11
13
|
rack_version = "3.0.0" if rack_version.nil?
|
|
14
|
+
|
|
12
15
|
gem "rack", "~> #{Gem::Version.new(rack_version)}" unless rack_version == "0"
|
|
13
16
|
|
|
14
17
|
redis_rb_version = ENV.fetch("REDIS_RB_VERSION", "5.0")
|
|
@@ -20,7 +23,7 @@ gem "timecop"
|
|
|
20
23
|
gem "stackprof" unless RUBY_PLATFORM == "java"
|
|
21
24
|
gem "vernier", platforms: :ruby if RUBY_VERSION >= "3.2.1"
|
|
22
25
|
|
|
23
|
-
gem "graphql", ">= 2.2.6"
|
|
26
|
+
gem "graphql", ">= 2.2.6"
|
|
24
27
|
|
|
25
28
|
gem "benchmark-ips"
|
|
26
29
|
gem "benchmark_driver"
|
|
@@ -32,3 +35,24 @@ gem "webrick"
|
|
|
32
35
|
gem "faraday"
|
|
33
36
|
gem "excon"
|
|
34
37
|
gem "webmock"
|
|
38
|
+
|
|
39
|
+
group :sequel do
|
|
40
|
+
gem "sequel"
|
|
41
|
+
|
|
42
|
+
sqlite_version = if ruby_version >= Gem::Version.new("3.2")
|
|
43
|
+
"2.1.0"
|
|
44
|
+
elsif ruby_version >= Gem::Version.new("3.0")
|
|
45
|
+
"1.4.0"
|
|
46
|
+
else
|
|
47
|
+
"1.3.0"
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
platform :ruby do
|
|
51
|
+
gem "sqlite3", "~> #{sqlite_version}"
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
platform :jruby do
|
|
55
|
+
gem "activerecord-jdbcmysql-adapter"
|
|
56
|
+
gem "jdbc-sqlite3"
|
|
57
|
+
end
|
|
58
|
+
end
|
data/README.md
CHANGED
|
@@ -105,9 +105,9 @@ To learn more about sampling transactions, please visit the [official documentat
|
|
|
105
105
|
|
|
106
106
|
* [](https://docs.sentry.io/platforms/ruby/)
|
|
107
107
|
* [](https://forum.sentry.io/c/sdks)
|
|
108
|
-
* [](https://discord.gg/
|
|
108
|
+
* [](https://discord.gg/sentry)
|
|
109
109
|
* [](https://stackoverflow.com/questions/tagged/sentry)
|
|
110
|
-
* [](https://x.com/intent/follow?screen_name=sentry)
|
|
111
111
|
|
|
112
112
|
## Contributing to the SDK
|
|
113
113
|
|
|
@@ -23,10 +23,7 @@ module Sentry
|
|
|
23
23
|
@shutdown_callback = nil
|
|
24
24
|
|
|
25
25
|
@executor =
|
|
26
|
-
if
|
|
27
|
-
log_debug("config.async is set, BackgroundWorker is disabled")
|
|
28
|
-
Concurrent::ImmediateExecutor.new
|
|
29
|
-
elsif @number_of_threads == 0
|
|
26
|
+
if @number_of_threads == 0
|
|
30
27
|
log_debug("config.background_worker_threads is set to 0, all events will be sent synchronously")
|
|
31
28
|
Concurrent::ImmediateExecutor.new
|
|
32
29
|
else
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Sentry
|
|
4
|
+
# @api private
|
|
5
|
+
class Backtrace
|
|
6
|
+
# Handles backtrace parsing line by line
|
|
7
|
+
class Line
|
|
8
|
+
RB_EXTENSION = ".rb"
|
|
9
|
+
# regexp (optional leading X: on windows, or JRuby9000 class-prefix)
|
|
10
|
+
RUBY_INPUT_FORMAT = /
|
|
11
|
+
^ \s* (?: [a-zA-Z]: | uri:classloader: )? ([^:]+ | <.*>):
|
|
12
|
+
(\d+)
|
|
13
|
+
(?: :in\s('|`)(?:([\w:]+)\#)?([^']+)')?$
|
|
14
|
+
/x
|
|
15
|
+
|
|
16
|
+
# org.jruby.runtime.callsite.CachingCallSite.call(CachingCallSite.java:170)
|
|
17
|
+
JAVA_INPUT_FORMAT = /^([\w$.]+)\.([\w$]+)\(([\w$.]+):(\d+)\)$/
|
|
18
|
+
|
|
19
|
+
# The file portion of the line (such as app/models/user.rb)
|
|
20
|
+
attr_reader :file
|
|
21
|
+
|
|
22
|
+
# The line number portion of the line
|
|
23
|
+
attr_reader :number
|
|
24
|
+
|
|
25
|
+
# The method of the line (such as index)
|
|
26
|
+
attr_reader :method
|
|
27
|
+
|
|
28
|
+
# The module name (JRuby)
|
|
29
|
+
attr_reader :module_name
|
|
30
|
+
|
|
31
|
+
attr_reader :in_app_pattern
|
|
32
|
+
|
|
33
|
+
# Parses a single line of a given backtrace
|
|
34
|
+
# @param [String] unparsed_line The raw line from +caller+ or some backtrace
|
|
35
|
+
# @return [Line] The parsed backtrace line
|
|
36
|
+
def self.parse(unparsed_line, in_app_pattern = nil)
|
|
37
|
+
ruby_match = unparsed_line.match(RUBY_INPUT_FORMAT)
|
|
38
|
+
|
|
39
|
+
if ruby_match
|
|
40
|
+
_, file, number, _, module_name, method = ruby_match.to_a
|
|
41
|
+
file.sub!(/\.class$/, RB_EXTENSION)
|
|
42
|
+
module_name = module_name
|
|
43
|
+
else
|
|
44
|
+
java_match = unparsed_line.match(JAVA_INPUT_FORMAT)
|
|
45
|
+
_, module_name, method, file, number = java_match.to_a
|
|
46
|
+
end
|
|
47
|
+
new(file, number, method, module_name, in_app_pattern)
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
# Creates a Line from a Thread::Backtrace::Location object
|
|
51
|
+
# This is more efficient than converting to string and parsing with regex
|
|
52
|
+
# @param [Thread::Backtrace::Location] location The location object
|
|
53
|
+
# @param [Regexp, nil] in_app_pattern Optional pattern to determine if the line is in-app
|
|
54
|
+
# @return [Line] The backtrace line
|
|
55
|
+
def self.from_source_location(location, in_app_pattern = nil)
|
|
56
|
+
file = location.absolute_path
|
|
57
|
+
number = location.lineno
|
|
58
|
+
method = location.base_label
|
|
59
|
+
|
|
60
|
+
label = location.label
|
|
61
|
+
index = label.index("#") || label.index(".")
|
|
62
|
+
module_name = label[0, index] if index
|
|
63
|
+
|
|
64
|
+
new(file, number, method, module_name, in_app_pattern)
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
def initialize(file, number, method, module_name, in_app_pattern)
|
|
68
|
+
@file = file
|
|
69
|
+
@module_name = module_name
|
|
70
|
+
@number = number.to_i
|
|
71
|
+
@method = method
|
|
72
|
+
@in_app_pattern = in_app_pattern
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
def in_app
|
|
76
|
+
return false unless in_app_pattern
|
|
77
|
+
|
|
78
|
+
if file =~ in_app_pattern
|
|
79
|
+
true
|
|
80
|
+
else
|
|
81
|
+
false
|
|
82
|
+
end
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
# Reconstructs the line in a readable fashion
|
|
86
|
+
def to_s
|
|
87
|
+
"#{file}:#{number}:in `#{method}'"
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
def ==(other)
|
|
91
|
+
to_s == other.to_s
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
def inspect
|
|
95
|
+
"<Line:#{self}>"
|
|
96
|
+
end
|
|
97
|
+
end
|
|
98
|
+
end
|
|
99
|
+
end
|
data/lib/sentry/backtrace.rb
CHANGED
|
@@ -1,86 +1,12 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
require "rubygems"
|
|
4
|
+
require "concurrent/map"
|
|
5
|
+
require "sentry/backtrace/line"
|
|
4
6
|
|
|
5
7
|
module Sentry
|
|
6
8
|
# @api private
|
|
7
9
|
class Backtrace
|
|
8
|
-
# Handles backtrace parsing line by line
|
|
9
|
-
class Line
|
|
10
|
-
RB_EXTENSION = ".rb"
|
|
11
|
-
# regexp (optional leading X: on windows, or JRuby9000 class-prefix)
|
|
12
|
-
RUBY_INPUT_FORMAT = /
|
|
13
|
-
^ \s* (?: [a-zA-Z]: | uri:classloader: )? ([^:]+ | <.*>):
|
|
14
|
-
(\d+)
|
|
15
|
-
(?: :in\s('|`)(?:([\w:]+)\#)?([^']+)')?$
|
|
16
|
-
/x
|
|
17
|
-
|
|
18
|
-
# org.jruby.runtime.callsite.CachingCallSite.call(CachingCallSite.java:170)
|
|
19
|
-
JAVA_INPUT_FORMAT = /^([\w$.]+)\.([\w$]+)\(([\w$.]+):(\d+)\)$/
|
|
20
|
-
|
|
21
|
-
# The file portion of the line (such as app/models/user.rb)
|
|
22
|
-
attr_reader :file
|
|
23
|
-
|
|
24
|
-
# The line number portion of the line
|
|
25
|
-
attr_reader :number
|
|
26
|
-
|
|
27
|
-
# The method of the line (such as index)
|
|
28
|
-
attr_reader :method
|
|
29
|
-
|
|
30
|
-
# The module name (JRuby)
|
|
31
|
-
attr_reader :module_name
|
|
32
|
-
|
|
33
|
-
attr_reader :in_app_pattern
|
|
34
|
-
|
|
35
|
-
# Parses a single line of a given backtrace
|
|
36
|
-
# @param [String] unparsed_line The raw line from +caller+ or some backtrace
|
|
37
|
-
# @return [Line] The parsed backtrace line
|
|
38
|
-
def self.parse(unparsed_line, in_app_pattern = nil)
|
|
39
|
-
ruby_match = unparsed_line.match(RUBY_INPUT_FORMAT)
|
|
40
|
-
|
|
41
|
-
if ruby_match
|
|
42
|
-
_, file, number, _, module_name, method = ruby_match.to_a
|
|
43
|
-
file.sub!(/\.class$/, RB_EXTENSION)
|
|
44
|
-
module_name = module_name
|
|
45
|
-
else
|
|
46
|
-
java_match = unparsed_line.match(JAVA_INPUT_FORMAT)
|
|
47
|
-
_, module_name, method, file, number = java_match.to_a
|
|
48
|
-
end
|
|
49
|
-
new(file, number, method, module_name, in_app_pattern)
|
|
50
|
-
end
|
|
51
|
-
|
|
52
|
-
def initialize(file, number, method, module_name, in_app_pattern)
|
|
53
|
-
@file = file
|
|
54
|
-
@module_name = module_name
|
|
55
|
-
@number = number.to_i
|
|
56
|
-
@method = method
|
|
57
|
-
@in_app_pattern = in_app_pattern
|
|
58
|
-
end
|
|
59
|
-
|
|
60
|
-
def in_app
|
|
61
|
-
return false unless in_app_pattern
|
|
62
|
-
|
|
63
|
-
if file =~ in_app_pattern
|
|
64
|
-
true
|
|
65
|
-
else
|
|
66
|
-
false
|
|
67
|
-
end
|
|
68
|
-
end
|
|
69
|
-
|
|
70
|
-
# Reconstructs the line in a readable fashion
|
|
71
|
-
def to_s
|
|
72
|
-
"#{file}:#{number}:in `#{method}'"
|
|
73
|
-
end
|
|
74
|
-
|
|
75
|
-
def ==(other)
|
|
76
|
-
to_s == other.to_s
|
|
77
|
-
end
|
|
78
|
-
|
|
79
|
-
def inspect
|
|
80
|
-
"<Line:#{self}>"
|
|
81
|
-
end
|
|
82
|
-
end
|
|
83
|
-
|
|
84
10
|
# holder for an Array of Backtrace::Line instances
|
|
85
11
|
attr_reader :lines
|
|
86
12
|
|
|
@@ -100,6 +26,48 @@ module Sentry
|
|
|
100
26
|
new(lines)
|
|
101
27
|
end
|
|
102
28
|
|
|
29
|
+
# Thread.each_caller_location is an API added in Ruby 3.2 that doesn't always collect
|
|
30
|
+
# the entire stack like Kernel#caller or #caller_locations do.
|
|
31
|
+
#
|
|
32
|
+
# @see https://github.com/rails/rails/pull/49095 for more context.
|
|
33
|
+
if Thread.respond_to?(:each_caller_location)
|
|
34
|
+
def self.source_location(&backtrace_cleaner)
|
|
35
|
+
Thread.each_caller_location do |location|
|
|
36
|
+
frame_key = [location.absolute_path, location.lineno]
|
|
37
|
+
cached_value = line_cache[frame_key]
|
|
38
|
+
|
|
39
|
+
next if cached_value == :skip
|
|
40
|
+
|
|
41
|
+
if cached_value
|
|
42
|
+
return cached_value
|
|
43
|
+
else
|
|
44
|
+
if cleaned_frame = backtrace_cleaner.(location)
|
|
45
|
+
line = Line.from_source_location(location)
|
|
46
|
+
line_cache[frame_key] = line
|
|
47
|
+
|
|
48
|
+
return line
|
|
49
|
+
else
|
|
50
|
+
line_cache[frame_key] = :skip
|
|
51
|
+
|
|
52
|
+
next
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
def self.line_cache
|
|
59
|
+
@line_cache ||= Concurrent::Map.new
|
|
60
|
+
end
|
|
61
|
+
else
|
|
62
|
+
# Since Sentry is mostly used in production, we don't want to fallback
|
|
63
|
+
# to the slower implementation and adds potentially big overhead to the
|
|
64
|
+
# application.
|
|
65
|
+
def self.source_location(*)
|
|
66
|
+
nil
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
|
|
103
71
|
def initialize(lines)
|
|
104
72
|
@lines = lines
|
|
105
73
|
end
|
data/lib/sentry/breadcrumb.rb
CHANGED
|
@@ -48,13 +48,13 @@ module Sentry
|
|
|
48
48
|
end
|
|
49
49
|
|
|
50
50
|
# @return [Hash]
|
|
51
|
-
def
|
|
51
|
+
def to_h
|
|
52
52
|
data = super
|
|
53
53
|
data[:check_in_id] = check_in_id
|
|
54
54
|
data[:monitor_slug] = monitor_slug
|
|
55
55
|
data[:status] = status
|
|
56
56
|
data[:duration] = duration if duration
|
|
57
|
-
data[:monitor_config] = monitor_config.
|
|
57
|
+
data[:monitor_config] = monitor_config.to_h if monitor_config
|
|
58
58
|
data
|
|
59
59
|
end
|
|
60
60
|
end
|
data/lib/sentry/client.rb
CHANGED
|
@@ -3,7 +3,10 @@
|
|
|
3
3
|
require "sentry/transport"
|
|
4
4
|
require "sentry/log_event"
|
|
5
5
|
require "sentry/log_event_buffer"
|
|
6
|
+
require "sentry/metric_event"
|
|
7
|
+
require "sentry/metric_event_buffer"
|
|
6
8
|
require "sentry/utils/uuid"
|
|
9
|
+
require "sentry/utils/encoding_helper"
|
|
7
10
|
|
|
8
11
|
module Sentry
|
|
9
12
|
class Client
|
|
@@ -20,6 +23,9 @@ module Sentry
|
|
|
20
23
|
# @!visibility private
|
|
21
24
|
attr_reader :log_event_buffer
|
|
22
25
|
|
|
26
|
+
# @!visibility private
|
|
27
|
+
attr_reader :metric_event_buffer
|
|
28
|
+
|
|
23
29
|
# @!macro configuration
|
|
24
30
|
attr_reader :configuration
|
|
25
31
|
|
|
@@ -43,7 +49,11 @@ module Sentry
|
|
|
43
49
|
@spotlight_transport = SpotlightTransport.new(configuration) if configuration.spotlight
|
|
44
50
|
|
|
45
51
|
if configuration.enable_logs
|
|
46
|
-
@log_event_buffer = LogEventBuffer.new(configuration, self)
|
|
52
|
+
@log_event_buffer = LogEventBuffer.new(configuration, self)
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
if configuration.enable_metrics
|
|
56
|
+
@metric_event_buffer = MetricEventBuffer.new(configuration, self)
|
|
47
57
|
end
|
|
48
58
|
end
|
|
49
59
|
|
|
@@ -60,8 +70,7 @@ module Sentry
|
|
|
60
70
|
return
|
|
61
71
|
end
|
|
62
72
|
|
|
63
|
-
|
|
64
|
-
data_category = Envelope::Item.data_category(event_type)
|
|
73
|
+
data_category = Envelope::Item.data_category(event.type)
|
|
65
74
|
|
|
66
75
|
is_transaction = event.is_a?(TransactionEvent)
|
|
67
76
|
spans_before = is_transaction ? event.spans.size : 0
|
|
@@ -78,9 +87,7 @@ module Sentry
|
|
|
78
87
|
transport.record_lost_event(:event_processor, "span", num: spans_delta) if spans_delta > 0
|
|
79
88
|
end
|
|
80
89
|
|
|
81
|
-
if
|
|
82
|
-
dispatch_async_event(async_block, event, hint)
|
|
83
|
-
elsif configuration.background_worker_threads != 0 && hint.fetch(:background, true)
|
|
90
|
+
if configuration.background_worker_threads != 0 && hint.fetch(:background, true)
|
|
84
91
|
unless dispatch_background_event(event, hint)
|
|
85
92
|
transport.record_lost_event(:queue_overflow, data_category)
|
|
86
93
|
transport.record_lost_event(:queue_overflow, "span", num: spans_before + 1) if is_transaction
|
|
@@ -100,7 +107,17 @@ module Sentry
|
|
|
100
107
|
# @return [LogEvent]
|
|
101
108
|
def buffer_log_event(event, scope)
|
|
102
109
|
return unless event.is_a?(LogEvent)
|
|
103
|
-
@log_event_buffer.
|
|
110
|
+
@log_event_buffer.add_item(scope.apply_to_telemetry(event))
|
|
111
|
+
event
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
# Buffer a metric event to be sent later with other metrics in a single envelope
|
|
115
|
+
# @param event [MetricEvent] the metric event to be buffered
|
|
116
|
+
# @return [MetricEvent]
|
|
117
|
+
def buffer_metric_event(event, scope)
|
|
118
|
+
return unless event.is_a?(MetricEvent)
|
|
119
|
+
event = scope.apply_to_telemetry(event)
|
|
120
|
+
@metric_event_buffer.add_item(event)
|
|
104
121
|
event
|
|
105
122
|
end
|
|
106
123
|
|
|
@@ -117,6 +134,7 @@ module Sentry
|
|
|
117
134
|
transport.flush if configuration.sending_to_dsn_allowed?
|
|
118
135
|
spotlight_transport.flush if spotlight_transport
|
|
119
136
|
@log_event_buffer&.flush
|
|
137
|
+
@metric_event_buffer&.flush
|
|
120
138
|
end
|
|
121
139
|
|
|
122
140
|
# Initializes an Event object with the given exception. Returns `nil` if the exception's class is excluded from reporting.
|
|
@@ -197,8 +215,17 @@ module Sentry
|
|
|
197
215
|
|
|
198
216
|
attributes = options.reject { |k, _| k == :level || k == :severity || k == :origin }
|
|
199
217
|
origin = options[:origin]
|
|
218
|
+
body = Utils::EncodingHelper.safe_utf_8_string(message)
|
|
219
|
+
|
|
220
|
+
sanitized_attributes = attributes.transform_values do |value|
|
|
221
|
+
if value.is_a?(String)
|
|
222
|
+
Utils::EncodingHelper.safe_utf_8_string(value)
|
|
223
|
+
else
|
|
224
|
+
value
|
|
225
|
+
end
|
|
226
|
+
end
|
|
200
227
|
|
|
201
|
-
LogEvent.new(level: level, body:
|
|
228
|
+
LogEvent.new(level: level, body: body, attributes: sanitized_attributes, origin: origin)
|
|
202
229
|
end
|
|
203
230
|
|
|
204
231
|
# Initializes an Event object with the given Transaction object.
|
|
@@ -210,22 +237,13 @@ module Sentry
|
|
|
210
237
|
|
|
211
238
|
# @!macro send_event
|
|
212
239
|
def send_event(event, hint = nil)
|
|
213
|
-
|
|
214
|
-
data_category = Envelope::Item.data_category(event_type)
|
|
240
|
+
data_category = Envelope::Item.data_category(event.type)
|
|
215
241
|
spans_before = event.is_a?(TransactionEvent) ? event.spans.size : 0
|
|
216
242
|
|
|
217
|
-
if
|
|
243
|
+
if event.is_a?(ErrorEvent) && configuration.before_send
|
|
218
244
|
event = configuration.before_send.call(event, hint)
|
|
219
245
|
|
|
220
|
-
|
|
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
|
|
246
|
+
if !event.is_a?(ErrorEvent)
|
|
229
247
|
# Avoid serializing the event object in this case because we aren't sure what it is and what it contains
|
|
230
248
|
log_debug(<<~MSG)
|
|
231
249
|
Discarded event because before_send didn't return a Sentry::ErrorEvent object but an instance of #{event.class}
|
|
@@ -235,21 +253,10 @@ module Sentry
|
|
|
235
253
|
end
|
|
236
254
|
end
|
|
237
255
|
|
|
238
|
-
if
|
|
256
|
+
if event.is_a?(TransactionEvent) && configuration.before_send_transaction
|
|
239
257
|
event = configuration.before_send_transaction.call(event, hint)
|
|
240
258
|
|
|
241
|
-
if event.is_a?(TransactionEvent)
|
|
242
|
-
spans_after = event.is_a?(TransactionEvent) ? event.spans.size : 0
|
|
243
|
-
spans_delta = spans_before - spans_after
|
|
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
|
|
259
|
+
if !event.is_a?(TransactionEvent)
|
|
253
260
|
# Avoid serializing the event object in this case because we aren't sure what it is and what it contains
|
|
254
261
|
log_debug(<<~MSG)
|
|
255
262
|
Discarded event because before_send_transaction didn't return a Sentry::TransactionEvent object but an instance of #{event.class}
|
|
@@ -258,6 +265,23 @@ module Sentry
|
|
|
258
265
|
transport.record_lost_event(:before_send, "span", num: spans_before + 1)
|
|
259
266
|
return
|
|
260
267
|
end
|
|
268
|
+
|
|
269
|
+
spans_after = event.is_a?(TransactionEvent) ? event.spans.size : 0
|
|
270
|
+
spans_delta = spans_before - spans_after
|
|
271
|
+
transport.record_lost_event(:before_send, "span", num: spans_delta) if spans_delta > 0
|
|
272
|
+
end
|
|
273
|
+
|
|
274
|
+
if event.is_a?(CheckInEvent) && configuration.before_send_check_in
|
|
275
|
+
event = configuration.before_send_check_in.call(event, hint)
|
|
276
|
+
|
|
277
|
+
if !event.is_a?(CheckInEvent)
|
|
278
|
+
# Avoid serializing the event object in this case because we aren't sure what it is and what it contains
|
|
279
|
+
log_debug(<<~MSG)
|
|
280
|
+
Discarded event because before_send_check_in didn't return a Sentry::CheckInEvent object but an instance of #{event.class}
|
|
281
|
+
MSG
|
|
282
|
+
transport.record_lost_event(:before_send, data_category)
|
|
283
|
+
return
|
|
284
|
+
end
|
|
261
285
|
end
|
|
262
286
|
|
|
263
287
|
transport.send_event(event) if configuration.sending_to_dsn_allowed?
|
|
@@ -271,53 +295,6 @@ module Sentry
|
|
|
271
295
|
raise
|
|
272
296
|
end
|
|
273
297
|
|
|
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
|
-
|
|
321
298
|
# Send an envelope directly to Sentry.
|
|
322
299
|
# @param envelope [Envelope] the envelope to be sent.
|
|
323
300
|
# @return [void]
|
|
@@ -334,38 +311,6 @@ module Sentry
|
|
|
334
311
|
raise
|
|
335
312
|
end
|
|
336
313
|
|
|
337
|
-
# @deprecated use Sentry.get_traceparent instead.
|
|
338
|
-
#
|
|
339
|
-
# Generates a Sentry trace for distribted tracing from the given Span.
|
|
340
|
-
# Returns `nil` if `config.propagate_traces` is `false`.
|
|
341
|
-
# @param span [Span] the span to generate trace from.
|
|
342
|
-
# @return [String, nil]
|
|
343
|
-
def generate_sentry_trace(span)
|
|
344
|
-
return unless configuration.propagate_traces
|
|
345
|
-
|
|
346
|
-
trace = span.to_sentry_trace
|
|
347
|
-
log_debug("[Tracing] Adding #{SENTRY_TRACE_HEADER_NAME} header to outgoing request: #{trace}")
|
|
348
|
-
trace
|
|
349
|
-
end
|
|
350
|
-
|
|
351
|
-
# @deprecated Use Sentry.get_baggage instead.
|
|
352
|
-
#
|
|
353
|
-
# Generates a W3C Baggage header for distributed tracing from the given Span.
|
|
354
|
-
# Returns `nil` if `config.propagate_traces` is `false`.
|
|
355
|
-
# @param span [Span] the span to generate trace from.
|
|
356
|
-
# @return [String, nil]
|
|
357
|
-
def generate_baggage(span)
|
|
358
|
-
return unless configuration.propagate_traces
|
|
359
|
-
|
|
360
|
-
baggage = span.to_baggage
|
|
361
|
-
|
|
362
|
-
if baggage && !baggage.empty?
|
|
363
|
-
log_debug("[Tracing] Adding #{BAGGAGE_HEADER_NAME} header to outgoing request: #{baggage}")
|
|
364
|
-
end
|
|
365
|
-
|
|
366
|
-
baggage
|
|
367
|
-
end
|
|
368
|
-
|
|
369
314
|
private
|
|
370
315
|
|
|
371
316
|
def dispatch_background_event(event, hint)
|
|
@@ -373,28 +318,5 @@ module Sentry
|
|
|
373
318
|
send_event(event, hint)
|
|
374
319
|
end
|
|
375
320
|
end
|
|
376
|
-
|
|
377
|
-
def dispatch_async_event(async_block, event, hint)
|
|
378
|
-
# We have to convert to a JSON-like hash, because background job
|
|
379
|
-
# processors (esp ActiveJob) may not like weird types in the event hash
|
|
380
|
-
|
|
381
|
-
event_hash =
|
|
382
|
-
begin
|
|
383
|
-
event.to_json_compatible
|
|
384
|
-
rescue => e
|
|
385
|
-
log_error("Converting #{event.type} (#{event.event_id}) to JSON compatible hash failed", e, debug: configuration.debug)
|
|
386
|
-
return
|
|
387
|
-
end
|
|
388
|
-
|
|
389
|
-
if async_block.arity == 2
|
|
390
|
-
hint = JSON.parse(JSON.generate(hint))
|
|
391
|
-
async_block.call(event_hash, hint)
|
|
392
|
-
else
|
|
393
|
-
async_block.call(event_hash)
|
|
394
|
-
end
|
|
395
|
-
rescue => e
|
|
396
|
-
log_error("Async #{event_hash["type"]} sending failed", e, debug: configuration.debug)
|
|
397
|
-
send_event(event, hint)
|
|
398
|
-
end
|
|
399
321
|
end
|
|
400
322
|
end
|