sentry-ruby 5.19.0 → 5.21.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.
- checksums.yaml +4 -4
- data/Gemfile +3 -0
- data/Rakefile +2 -0
- data/bin/console +1 -0
- data/lib/sentry/attachment.rb +3 -5
- data/lib/sentry/backtrace.rb +3 -5
- data/lib/sentry/baggage.rb +7 -7
- data/lib/sentry/breadcrumb/sentry_logger.rb +6 -6
- data/lib/sentry/check_in_event.rb +4 -4
- data/lib/sentry/client.rb +9 -9
- data/lib/sentry/configuration.rb +52 -19
- data/lib/sentry/core_ext/object/deep_dup.rb +1 -1
- data/lib/sentry/cron/monitor_check_ins.rb +3 -1
- data/lib/sentry/cron/monitor_config.rb +1 -1
- data/lib/sentry/dsn.rb +3 -3
- data/lib/sentry/envelope/item.rb +88 -0
- data/lib/sentry/envelope.rb +2 -85
- data/lib/sentry/event.rb +7 -7
- data/lib/sentry/graphql.rb +1 -1
- data/lib/sentry/hub.rb +8 -1
- data/lib/sentry/interfaces/mechanism.rb +1 -1
- data/lib/sentry/interfaces/request.rb +5 -5
- 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/logger.rb +1 -1
- data/lib/sentry/metrics/aggregator.rb +12 -12
- data/lib/sentry/metrics/set_metric.rb +2 -2
- data/lib/sentry/metrics.rb +15 -15
- data/lib/sentry/net/http.rb +1 -1
- data/lib/sentry/profiler/helpers.rb +46 -0
- data/lib/sentry/profiler.rb +25 -56
- data/lib/sentry/propagation_context.rb +1 -1
- 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/scope.rb +1 -0
- data/lib/sentry/session_flusher.rb +1 -1
- data/lib/sentry/span.rb +6 -0
- data/lib/sentry/test_helper.rb +3 -1
- data/lib/sentry/transaction.rb +4 -4
- data/lib/sentry/transaction_event.rb +1 -2
- data/lib/sentry/transport/http_transport.rb +12 -12
- data/lib/sentry/transport.rb +4 -4
- data/lib/sentry/utils/env_helper.rb +21 -0
- data/lib/sentry/utils/real_ip.rb +1 -1
- data/lib/sentry/vernier/output.rb +89 -0
- data/lib/sentry/vernier/profiler.rb +125 -0
- data/lib/sentry/version.rb +1 -1
- data/lib/sentry-ruby.rb +5 -4
- data/sentry-ruby-core.gemspec +3 -1
- data/sentry-ruby.gemspec +3 -1
- metadata +13 -8
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: cf62f77a0a968d4080fac612bf67f996bee72b51e050e17bf8d40c04c9c895ea
|
4
|
+
data.tar.gz: 348af55b8f56829cbf5fc5569ddc8308d4cd6ae508480de206443349e1221235
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 5baaf6d507772d4a3882a99a43b3f4c88ae4ee56ddfd505433dc88b1e1f21430a2b8fa374932ec4b94478e054a9d1baf12789594bcfe9574db94f449b6526fc2
|
7
|
+
data.tar.gz: 8eacb9b0e326b529c743af650920b17e382b379032895d112a83689965a53fe42ae48eb9c070cd86085b1d7d5d9cc7300e0d9199b975edc25ee4aca1f093ecd6
|
data/Gemfile
CHANGED
@@ -1,3 +1,5 @@
|
|
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
|
|
@@ -14,6 +16,7 @@ gem "puma"
|
|
14
16
|
|
15
17
|
gem "timecop"
|
16
18
|
gem "stackprof" unless RUBY_PLATFORM == "java"
|
19
|
+
gem "vernier", platforms: :ruby if RUBY_VERSION >= "3.2.1"
|
17
20
|
|
18
21
|
gem "graphql", ">= 2.2.6" if RUBY_VERSION.to_f >= 2.7
|
19
22
|
|
data/Rakefile
CHANGED
data/bin/console
CHANGED
data/lib/sentry/attachment.rb
CHANGED
@@ -8,13 +8,13 @@ module Sentry
|
|
8
8
|
|
9
9
|
def initialize(bytes: nil, filename: nil, content_type: nil, path: nil)
|
10
10
|
@bytes = bytes
|
11
|
-
@filename = infer_filename(
|
11
|
+
@filename = filename || infer_filename(path)
|
12
12
|
@path = path
|
13
13
|
@content_type = content_type
|
14
14
|
end
|
15
15
|
|
16
16
|
def to_envelope_headers
|
17
|
-
{ type:
|
17
|
+
{ type: "attachment", filename: filename, content_type: content_type, length: payload.bytesize }
|
18
18
|
end
|
19
19
|
|
20
20
|
def payload
|
@@ -29,9 +29,7 @@ module Sentry
|
|
29
29
|
|
30
30
|
private
|
31
31
|
|
32
|
-
def infer_filename(
|
33
|
-
return filename if filename
|
34
|
-
|
32
|
+
def infer_filename(path)
|
35
33
|
if path
|
36
34
|
File.basename(path)
|
37
35
|
else
|
data/lib/sentry/backtrace.rb
CHANGED
@@ -13,10 +13,10 @@ module Sentry
|
|
13
13
|
^ \s* (?: [a-zA-Z]: | uri:classloader: )? ([^:]+ | <.*>):
|
14
14
|
(\d+)
|
15
15
|
(?: :in\s('|`)([^']+)')?$
|
16
|
-
/x
|
16
|
+
/x
|
17
17
|
|
18
18
|
# org.jruby.runtime.callsite.CachingCallSite.call(CachingCallSite.java:170)
|
19
|
-
JAVA_INPUT_FORMAT = /^(.+)\.([^\.]+)\(([^\:]+)\:(\d+)\)
|
19
|
+
JAVA_INPUT_FORMAT = /^(.+)\.([^\.]+)\(([^\:]+)\:(\d+)\)$/
|
20
20
|
|
21
21
|
# The file portion of the line (such as app/models/user.rb)
|
22
22
|
attr_reader :file
|
@@ -80,8 +80,6 @@ module Sentry
|
|
80
80
|
end
|
81
81
|
end
|
82
82
|
|
83
|
-
APP_DIRS_PATTERN = /(bin|exe|app|config|lib|test|spec)/.freeze
|
84
|
-
|
85
83
|
# holder for an Array of Backtrace::Line instances
|
86
84
|
attr_reader :lines
|
87
85
|
|
@@ -91,7 +89,7 @@ module Sentry
|
|
91
89
|
ruby_lines = backtrace_cleanup_callback.call(ruby_lines) if backtrace_cleanup_callback
|
92
90
|
|
93
91
|
in_app_pattern ||= begin
|
94
|
-
Regexp.new("^(#{project_root}/)?#{app_dirs_pattern
|
92
|
+
Regexp.new("^(#{project_root}/)?#{app_dirs_pattern}")
|
95
93
|
end
|
96
94
|
|
97
95
|
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)
|
@@ -1,11 +1,11 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require
|
4
|
-
require
|
3
|
+
require "securerandom"
|
4
|
+
require "sentry/cron/monitor_config"
|
5
5
|
|
6
6
|
module Sentry
|
7
7
|
class CheckInEvent < Event
|
8
|
-
TYPE =
|
8
|
+
TYPE = "check_in"
|
9
9
|
|
10
10
|
# uuid to identify this check-in.
|
11
11
|
# @return [String]
|
@@ -43,7 +43,7 @@ module Sentry
|
|
43
43
|
self.status = status
|
44
44
|
self.duration = duration
|
45
45
|
self.monitor_config = monitor_config
|
46
|
-
self.check_in_id = check_in_id || SecureRandom.uuid.delete(
|
46
|
+
self.check_in_id = check_in_id || SecureRandom.uuid.delete("-")
|
47
47
|
end
|
48
48
|
|
49
49
|
# @return [Hash]
|
data/lib/sentry/client.rb
CHANGED
@@ -30,7 +30,7 @@ module Sentry
|
|
30
30
|
else
|
31
31
|
@transport =
|
32
32
|
case configuration.dsn&.scheme
|
33
|
-
when
|
33
|
+
when "http", "https"
|
34
34
|
HTTPTransport.new(configuration)
|
35
35
|
else
|
36
36
|
DummyTransport.new(configuration)
|
@@ -49,7 +49,7 @@ module Sentry
|
|
49
49
|
return unless configuration.sending_allowed?
|
50
50
|
|
51
51
|
if event.is_a?(ErrorEvent) && !configuration.sample_allowed?
|
52
|
-
transport.record_lost_event(:sample_rate,
|
52
|
+
transport.record_lost_event(:sample_rate, "error")
|
53
53
|
return
|
54
54
|
end
|
55
55
|
|
@@ -64,11 +64,11 @@ module Sentry
|
|
64
64
|
if event.nil?
|
65
65
|
log_debug("Discarded event because one of the event processors returned nil")
|
66
66
|
transport.record_lost_event(:event_processor, data_category)
|
67
|
-
transport.record_lost_event(:event_processor,
|
67
|
+
transport.record_lost_event(:event_processor, "span", num: spans_before + 1) if is_transaction
|
68
68
|
return
|
69
69
|
elsif is_transaction
|
70
70
|
spans_delta = spans_before - event.spans.size
|
71
|
-
transport.record_lost_event(:event_processor,
|
71
|
+
transport.record_lost_event(:event_processor, "span", num: spans_delta) if spans_delta > 0
|
72
72
|
end
|
73
73
|
|
74
74
|
if async_block = configuration.async
|
@@ -76,7 +76,7 @@ module Sentry
|
|
76
76
|
elsif configuration.background_worker_threads != 0 && hint.fetch(:background, true)
|
77
77
|
unless dispatch_background_event(event, hint)
|
78
78
|
transport.record_lost_event(:queue_overflow, data_category)
|
79
|
-
transport.record_lost_event(:queue_overflow,
|
79
|
+
transport.record_lost_event(:queue_overflow, "span", num: spans_before + 1) if is_transaction
|
80
80
|
end
|
81
81
|
else
|
82
82
|
send_event(event, hint)
|
@@ -195,13 +195,13 @@ module Sentry
|
|
195
195
|
|
196
196
|
if event.nil?
|
197
197
|
log_debug("Discarded event because before_send_transaction returned nil")
|
198
|
-
transport.record_lost_event(:before_send,
|
199
|
-
transport.record_lost_event(:before_send,
|
198
|
+
transport.record_lost_event(:before_send, "transaction")
|
199
|
+
transport.record_lost_event(:before_send, "span", num: spans_before + 1)
|
200
200
|
return
|
201
201
|
else
|
202
202
|
spans_after = event.is_a?(TransactionEvent) ? event.spans.size : 0
|
203
203
|
spans_delta = spans_before - spans_after
|
204
|
-
transport.record_lost_event(:before_send,
|
204
|
+
transport.record_lost_event(:before_send, "span", num: spans_delta) if spans_delta > 0
|
205
205
|
end
|
206
206
|
end
|
207
207
|
|
@@ -212,7 +212,7 @@ module Sentry
|
|
212
212
|
rescue => e
|
213
213
|
log_error("Event sending failed", e, debug: configuration.debug)
|
214
214
|
transport.record_lost_event(:network_error, data_category)
|
215
|
-
transport.record_lost_event(:network_error,
|
215
|
+
transport.record_lost_event(:network_error, "span", num: spans_before + 1) if event.is_a?(TransactionEvent)
|
216
216
|
raise
|
217
217
|
end
|
218
218
|
|
data/lib/sentry/configuration.rb
CHANGED
@@ -3,7 +3,8 @@
|
|
3
3
|
require "concurrent/utility/processor_counter"
|
4
4
|
|
5
5
|
require "sentry/utils/exception_cause_chain"
|
6
|
-
require
|
6
|
+
require "sentry/utils/custom_inspection"
|
7
|
+
require "sentry/utils/env_helper"
|
7
8
|
require "sentry/dsn"
|
8
9
|
require "sentry/release_detector"
|
9
10
|
require "sentry/transport/configuration"
|
@@ -22,6 +23,8 @@ module Sentry
|
|
22
23
|
# have an `engines` dir at the root of your project, you may want
|
23
24
|
# to set this to something like /(app|config|engines|lib)/
|
24
25
|
#
|
26
|
+
# The default is value is /(bin|exe|app|config|lib|test|spec)/
|
27
|
+
#
|
25
28
|
# @return [Regexp, nil]
|
26
29
|
attr_accessor :app_dirs_pattern
|
27
30
|
|
@@ -187,6 +190,11 @@ module Sentry
|
|
187
190
|
# @return [String]
|
188
191
|
attr_accessor :project_root
|
189
192
|
|
193
|
+
# Whether to strip the load path while constructing the backtrace frame filename.
|
194
|
+
# Defaults to true.
|
195
|
+
# @return [Boolean]
|
196
|
+
attr_accessor :strip_backtrace_load_path
|
197
|
+
|
190
198
|
# Insert sentry-trace to outgoing requests' headers
|
191
199
|
# @return [Boolean]
|
192
200
|
attr_accessor :propagate_traces
|
@@ -283,6 +291,10 @@ module Sentry
|
|
283
291
|
# @return [Symbol]
|
284
292
|
attr_reader :instrumenter
|
285
293
|
|
294
|
+
# The profiler class
|
295
|
+
# @return [Class]
|
296
|
+
attr_reader :profiler_class
|
297
|
+
|
286
298
|
# Take a float between 0.0 and 1.0 as the sample rate for capturing profiles.
|
287
299
|
# Note that this rate is relative to traces_sample_rate / traces_sampler,
|
288
300
|
# i.e. the profile is sampled by this rate after the transaction is sampled.
|
@@ -302,18 +314,18 @@ module Sentry
|
|
302
314
|
# But they are mostly considered as noise and should be ignored by default
|
303
315
|
# Please see https://github.com/getsentry/sentry-ruby/pull/2026 for more information
|
304
316
|
PUMA_IGNORE_DEFAULT = [
|
305
|
-
|
306
|
-
|
307
|
-
|
317
|
+
"Puma::MiniSSL::SSLError",
|
318
|
+
"Puma::HttpParserError",
|
319
|
+
"Puma::HttpParserError501"
|
308
320
|
].freeze
|
309
321
|
|
310
322
|
# Most of these errors generate 4XX responses. In general, Sentry clients
|
311
323
|
# only automatically report 5xx responses.
|
312
324
|
IGNORE_DEFAULT = [
|
313
|
-
|
314
|
-
|
315
|
-
|
316
|
-
|
325
|
+
"Mongoid::Errors::DocumentNotFound",
|
326
|
+
"Rack::QueryParser::InvalidParameterError",
|
327
|
+
"Rack::QueryParser::ParameterTypeError",
|
328
|
+
"Sinatra::NotFound"
|
317
329
|
].freeze
|
318
330
|
|
319
331
|
RACK_ENV_WHITELIST_DEFAULT = %w[
|
@@ -323,18 +335,20 @@ module Sentry
|
|
323
335
|
].freeze
|
324
336
|
|
325
337
|
HEROKU_DYNO_METADATA_MESSAGE = "You are running on Heroku but haven't enabled Dyno Metadata. For Sentry's "\
|
326
|
-
"release detection to work correctly, please run `heroku labs:enable runtime-dyno-metadata`"
|
338
|
+
"release detection to work correctly, please run `heroku labs:enable runtime-dyno-metadata`"
|
327
339
|
|
328
|
-
LOG_PREFIX = "** [Sentry] "
|
329
|
-
MODULE_SEPARATOR = "::"
|
340
|
+
LOG_PREFIX = "** [Sentry] "
|
341
|
+
MODULE_SEPARATOR = "::"
|
330
342
|
SKIP_INSPECTION_ATTRIBUTES = [:@linecache, :@stacktrace_builder]
|
331
343
|
|
332
344
|
INSTRUMENTERS = [:sentry, :otel]
|
333
345
|
|
334
|
-
PROPAGATION_TARGETS_MATCH_ALL =
|
346
|
+
PROPAGATION_TARGETS_MATCH_ALL = /.*/
|
335
347
|
|
336
348
|
DEFAULT_PATCHES = %i[redis puma http].freeze
|
337
349
|
|
350
|
+
APP_DIRS_PATTERN = /(bin|exe|app|config|lib|test|spec)/
|
351
|
+
|
338
352
|
class << self
|
339
353
|
# Post initialization callbacks are called at the end of initialization process
|
340
354
|
# allowing extending the configuration of sentry-ruby by multiple extensions
|
@@ -349,11 +363,12 @@ module Sentry
|
|
349
363
|
end
|
350
364
|
|
351
365
|
def initialize
|
352
|
-
self.app_dirs_pattern =
|
353
|
-
self.debug =
|
366
|
+
self.app_dirs_pattern = APP_DIRS_PATTERN
|
367
|
+
self.debug = Sentry::Utils::EnvHelper.env_to_bool(ENV["SENTRY_DEBUG"])
|
354
368
|
self.background_worker_threads = (processor_count / 2.0).ceil
|
355
369
|
self.background_worker_max_queue = BackgroundWorker::DEFAULT_MAX_QUEUE
|
356
370
|
self.backtrace_cleanup_callback = nil
|
371
|
+
self.strip_backtrace_load_path = true
|
357
372
|
self.max_breadcrumbs = BreadcrumbBuffer::DEFAULT_SIZE
|
358
373
|
self.breadcrumbs_logger = []
|
359
374
|
self.context_lines = 3
|
@@ -376,8 +391,11 @@ module Sentry
|
|
376
391
|
self.auto_session_tracking = true
|
377
392
|
self.enable_backpressure_handling = false
|
378
393
|
self.trusted_proxies = []
|
379
|
-
self.dsn = ENV[
|
380
|
-
|
394
|
+
self.dsn = ENV["SENTRY_DSN"]
|
395
|
+
|
396
|
+
spotlight_env = ENV["SENTRY_SPOTLIGHT"]
|
397
|
+
spotlight_bool = Sentry::Utils::EnvHelper.env_to_bool(spotlight_env, strict: true)
|
398
|
+
self.spotlight = spotlight_bool.nil? ? (spotlight_env || false) : spotlight_bool
|
381
399
|
self.server_name = server_name_from_env
|
382
400
|
self.instrumenter = :sentry
|
383
401
|
self.trace_propagation_targets = [PROPAGATION_TARGETS_MATCH_ALL]
|
@@ -389,6 +407,8 @@ module Sentry
|
|
389
407
|
self.traces_sampler = nil
|
390
408
|
self.enable_tracing = nil
|
391
409
|
|
410
|
+
self.profiler_class = Sentry::Profiler
|
411
|
+
|
392
412
|
@transport = Transport::Configuration.new
|
393
413
|
@cron = Cron::Configuration.new
|
394
414
|
@metrics = Metrics::Configuration.new
|
@@ -484,6 +504,18 @@ module Sentry
|
|
484
504
|
@profiles_sample_rate = profiles_sample_rate
|
485
505
|
end
|
486
506
|
|
507
|
+
def profiler_class=(profiler_class)
|
508
|
+
if profiler_class == Sentry::Vernier::Profiler
|
509
|
+
begin
|
510
|
+
require "vernier"
|
511
|
+
rescue LoadError
|
512
|
+
raise ArgumentError, "Please add the 'vernier' gem to your Gemfile to use the Vernier profiler with Sentry."
|
513
|
+
end
|
514
|
+
end
|
515
|
+
|
516
|
+
@profiler_class = profiler_class
|
517
|
+
end
|
518
|
+
|
487
519
|
def sending_allowed?
|
488
520
|
spotlight || sending_to_dsn_allowed?
|
489
521
|
end
|
@@ -555,7 +587,8 @@ module Sentry
|
|
555
587
|
app_dirs_pattern: @app_dirs_pattern,
|
556
588
|
linecache: @linecache,
|
557
589
|
context_lines: @context_lines,
|
558
|
-
backtrace_cleanup_callback: @backtrace_cleanup_callback
|
590
|
+
backtrace_cleanup_callback: @backtrace_cleanup_callback,
|
591
|
+
strip_backtrace_load_path: @strip_backtrace_load_path
|
559
592
|
)
|
560
593
|
end
|
561
594
|
|
@@ -632,12 +665,12 @@ module Sentry
|
|
632
665
|
end
|
633
666
|
|
634
667
|
def environment_from_env
|
635
|
-
ENV[
|
668
|
+
ENV["SENTRY_CURRENT_ENV"] || ENV["SENTRY_ENVIRONMENT"] || ENV["RAILS_ENV"] || ENV["RACK_ENV"] || "development"
|
636
669
|
end
|
637
670
|
|
638
671
|
def server_name_from_env
|
639
672
|
if running_on_heroku?
|
640
|
-
ENV[
|
673
|
+
ENV["DYNO"]
|
641
674
|
else
|
642
675
|
# Try to resolve the hostname to an FQDN, but fall back to whatever
|
643
676
|
# the load name is.
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Sentry
|
2
4
|
module Cron
|
3
5
|
module MonitorCheckIns
|
@@ -57,7 +59,7 @@ module Sentry
|
|
57
59
|
|
58
60
|
def sentry_monitor_slug(name: self.name)
|
59
61
|
@sentry_monitor_slug ||= begin
|
60
|
-
slug = name.gsub(
|
62
|
+
slug = name.gsub("::", "-").downcase
|
61
63
|
slug[-MAX_SLUG_LENGTH..-1] || slug
|
62
64
|
end
|
63
65
|
end
|
data/lib/sentry/dsn.rb
CHANGED
@@ -4,7 +4,7 @@ require "uri"
|
|
4
4
|
|
5
5
|
module Sentry
|
6
6
|
class DSN
|
7
|
-
PORT_MAP = {
|
7
|
+
PORT_MAP = { "http" => 80, "https" => 443 }.freeze
|
8
8
|
REQUIRED_ATTRIBUTES = %w[host path public_key project_id].freeze
|
9
9
|
|
10
10
|
attr_reader :scheme, :secret_key, :port, *REQUIRED_ATTRIBUTES
|
@@ -13,7 +13,7 @@ module Sentry
|
|
13
13
|
@raw_value = dsn_string
|
14
14
|
|
15
15
|
uri = URI.parse(dsn_string)
|
16
|
-
uri_path = uri.path.split(
|
16
|
+
uri_path = uri.path.split("/")
|
17
17
|
|
18
18
|
if uri.user
|
19
19
|
# DSN-style string
|
@@ -25,7 +25,7 @@ module Sentry
|
|
25
25
|
@scheme = uri.scheme
|
26
26
|
@host = uri.host
|
27
27
|
@port = uri.port if uri.port
|
28
|
-
@path = uri_path.join(
|
28
|
+
@path = uri_path.join("/")
|
29
29
|
end
|
30
30
|
|
31
31
|
def valid?
|
@@ -0,0 +1,88 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Sentry
|
4
|
+
# @api private
|
5
|
+
class Envelope::Item
|
6
|
+
STACKTRACE_FRAME_LIMIT_ON_OVERSIZED_PAYLOAD = 500
|
7
|
+
MAX_SERIALIZED_PAYLOAD_SIZE = 1024 * 1000
|
8
|
+
|
9
|
+
SIZE_LIMITS = Hash.new(MAX_SERIALIZED_PAYLOAD_SIZE).update(
|
10
|
+
"profile" => 1024 * 1000 * 50
|
11
|
+
)
|
12
|
+
|
13
|
+
attr_reader :size_limit, :headers, :payload, :type, :data_category
|
14
|
+
|
15
|
+
# rate limits and client reports use the data_category rather than envelope item type
|
16
|
+
def self.data_category(type)
|
17
|
+
case type
|
18
|
+
when "session", "attachment", "transaction", "profile", "span" then type
|
19
|
+
when "sessions" then "session"
|
20
|
+
when "check_in" then "monitor"
|
21
|
+
when "statsd", "metric_meta" then "metric_bucket"
|
22
|
+
when "event" then "error"
|
23
|
+
when "client_report" then "internal"
|
24
|
+
else "default"
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def initialize(headers, payload)
|
29
|
+
@headers = headers
|
30
|
+
@payload = payload
|
31
|
+
@type = headers[:type] || "event"
|
32
|
+
@data_category = self.class.data_category(type)
|
33
|
+
@size_limit = SIZE_LIMITS[type]
|
34
|
+
end
|
35
|
+
|
36
|
+
def to_s
|
37
|
+
[JSON.generate(@headers), @payload.is_a?(String) ? @payload : JSON.generate(@payload)].join("\n")
|
38
|
+
end
|
39
|
+
|
40
|
+
def serialize
|
41
|
+
result = to_s
|
42
|
+
|
43
|
+
if result.bytesize > size_limit
|
44
|
+
remove_breadcrumbs!
|
45
|
+
result = to_s
|
46
|
+
end
|
47
|
+
|
48
|
+
if result.bytesize > size_limit
|
49
|
+
reduce_stacktrace!
|
50
|
+
result = to_s
|
51
|
+
end
|
52
|
+
|
53
|
+
[result, result.bytesize > size_limit]
|
54
|
+
end
|
55
|
+
|
56
|
+
def size_breakdown
|
57
|
+
payload.map do |key, value|
|
58
|
+
"#{key}: #{JSON.generate(value).bytesize}"
|
59
|
+
end.join(", ")
|
60
|
+
end
|
61
|
+
|
62
|
+
private
|
63
|
+
|
64
|
+
def remove_breadcrumbs!
|
65
|
+
if payload.key?(:breadcrumbs)
|
66
|
+
payload.delete(:breadcrumbs)
|
67
|
+
elsif payload.key?("breadcrumbs")
|
68
|
+
payload.delete("breadcrumbs")
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
def reduce_stacktrace!
|
73
|
+
if exceptions = payload.dig(:exception, :values) || payload.dig("exception", "values")
|
74
|
+
exceptions.each do |exception|
|
75
|
+
# in most cases there is only one exception (2 or 3 when have multiple causes), so we won't loop through this double condition much
|
76
|
+
traces = exception.dig(:stacktrace, :frames) || exception.dig("stacktrace", "frames")
|
77
|
+
|
78
|
+
if traces && traces.size > STACKTRACE_FRAME_LIMIT_ON_OVERSIZED_PAYLOAD
|
79
|
+
size_on_both_ends = STACKTRACE_FRAME_LIMIT_ON_OVERSIZED_PAYLOAD / 2
|
80
|
+
traces.replace(
|
81
|
+
traces[0..(size_on_both_ends - 1)] + traces[-size_on_both_ends..-1],
|
82
|
+
)
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
data/lib/sentry/envelope.rb
CHANGED
@@ -3,91 +3,6 @@
|
|
3
3
|
module Sentry
|
4
4
|
# @api private
|
5
5
|
class Envelope
|
6
|
-
class Item
|
7
|
-
STACKTRACE_FRAME_LIMIT_ON_OVERSIZED_PAYLOAD = 500
|
8
|
-
MAX_SERIALIZED_PAYLOAD_SIZE = 1024 * 1000
|
9
|
-
|
10
|
-
attr_accessor :headers, :payload
|
11
|
-
|
12
|
-
def initialize(headers, payload)
|
13
|
-
@headers = headers
|
14
|
-
@payload = payload
|
15
|
-
end
|
16
|
-
|
17
|
-
def type
|
18
|
-
@headers[:type] || 'event'
|
19
|
-
end
|
20
|
-
|
21
|
-
# rate limits and client reports use the data_category rather than envelope item type
|
22
|
-
def self.data_category(type)
|
23
|
-
case type
|
24
|
-
when 'session', 'attachment', 'transaction', 'profile', 'span' then type
|
25
|
-
when 'sessions' then 'session'
|
26
|
-
when 'check_in' then 'monitor'
|
27
|
-
when 'statsd', 'metric_meta' then 'metric_bucket'
|
28
|
-
when 'event' then 'error'
|
29
|
-
when 'client_report' then 'internal'
|
30
|
-
else 'default'
|
31
|
-
end
|
32
|
-
end
|
33
|
-
|
34
|
-
def data_category
|
35
|
-
self.class.data_category(type)
|
36
|
-
end
|
37
|
-
|
38
|
-
def to_s
|
39
|
-
[JSON.generate(@headers), @payload.is_a?(String) ? @payload : JSON.generate(@payload)].join("\n")
|
40
|
-
end
|
41
|
-
|
42
|
-
def serialize
|
43
|
-
result = to_s
|
44
|
-
|
45
|
-
if result.bytesize > MAX_SERIALIZED_PAYLOAD_SIZE
|
46
|
-
remove_breadcrumbs!
|
47
|
-
result = to_s
|
48
|
-
end
|
49
|
-
|
50
|
-
if result.bytesize > MAX_SERIALIZED_PAYLOAD_SIZE
|
51
|
-
reduce_stacktrace!
|
52
|
-
result = to_s
|
53
|
-
end
|
54
|
-
|
55
|
-
[result, result.bytesize > MAX_SERIALIZED_PAYLOAD_SIZE]
|
56
|
-
end
|
57
|
-
|
58
|
-
def size_breakdown
|
59
|
-
payload.map do |key, value|
|
60
|
-
"#{key}: #{JSON.generate(value).bytesize}"
|
61
|
-
end.join(", ")
|
62
|
-
end
|
63
|
-
|
64
|
-
private
|
65
|
-
|
66
|
-
def remove_breadcrumbs!
|
67
|
-
if payload.key?(:breadcrumbs)
|
68
|
-
payload.delete(:breadcrumbs)
|
69
|
-
elsif payload.key?("breadcrumbs")
|
70
|
-
payload.delete("breadcrumbs")
|
71
|
-
end
|
72
|
-
end
|
73
|
-
|
74
|
-
def reduce_stacktrace!
|
75
|
-
if exceptions = payload.dig(:exception, :values) || payload.dig("exception", "values")
|
76
|
-
exceptions.each do |exception|
|
77
|
-
# in most cases there is only one exception (2 or 3 when have multiple causes), so we won't loop through this double condition much
|
78
|
-
traces = exception.dig(:stacktrace, :frames) || exception.dig("stacktrace", "frames")
|
79
|
-
|
80
|
-
if traces && traces.size > STACKTRACE_FRAME_LIMIT_ON_OVERSIZED_PAYLOAD
|
81
|
-
size_on_both_ends = STACKTRACE_FRAME_LIMIT_ON_OVERSIZED_PAYLOAD / 2
|
82
|
-
traces.replace(
|
83
|
-
traces[0..(size_on_both_ends - 1)] + traces[-size_on_both_ends..-1],
|
84
|
-
)
|
85
|
-
end
|
86
|
-
end
|
87
|
-
end
|
88
|
-
end
|
89
|
-
end
|
90
|
-
|
91
6
|
attr_accessor :headers, :items
|
92
7
|
|
93
8
|
def initialize(headers = {})
|
@@ -108,3 +23,5 @@ module Sentry
|
|
108
23
|
end
|
109
24
|
end
|
110
25
|
end
|
26
|
+
|
27
|
+
require_relative "envelope/item"
|