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.
- checksums.yaml +4 -4
- data/.rspec +3 -1
- data/Gemfile +12 -13
- data/README.md +26 -11
- data/Rakefile +9 -11
- data/bin/console +2 -0
- data/lib/sentry/attachment.rb +40 -0
- data/lib/sentry/background_worker.rb +11 -5
- data/lib/sentry/backpressure_monitor.rb +45 -0
- data/lib/sentry/backtrace.rb +12 -9
- data/lib/sentry/baggage.rb +7 -7
- data/lib/sentry/breadcrumb/sentry_logger.rb +6 -6
- data/lib/sentry/breadcrumb.rb +13 -6
- data/lib/sentry/check_in_event.rb +61 -0
- data/lib/sentry/client.rb +214 -25
- data/lib/sentry/configuration.rb +221 -38
- data/lib/sentry/core_ext/object/deep_dup.rb +1 -1
- data/lib/sentry/cron/configuration.rb +23 -0
- data/lib/sentry/cron/monitor_check_ins.rb +77 -0
- data/lib/sentry/cron/monitor_config.rb +53 -0
- data/lib/sentry/cron/monitor_schedule.rb +42 -0
- data/lib/sentry/dsn.rb +4 -4
- data/lib/sentry/envelope/item.rb +88 -0
- data/lib/sentry/envelope.rb +2 -68
- data/lib/sentry/error_event.rb +2 -2
- data/lib/sentry/event.rb +28 -47
- 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 +9 -0
- data/lib/sentry/hub.rb +138 -6
- data/lib/sentry/integrable.rb +10 -0
- data/lib/sentry/interface.rb +1 -0
- data/lib/sentry/interfaces/exception.rb +5 -3
- data/lib/sentry/interfaces/mechanism.rb +20 -0
- data/lib/sentry/interfaces/request.rb +8 -8
- data/lib/sentry/interfaces/single_exception.rb +13 -9
- data/lib/sentry/interfaces/stacktrace.rb +3 -1
- data/lib/sentry/interfaces/stacktrace_builder.rb +23 -2
- data/lib/sentry/linecache.rb +3 -3
- data/lib/sentry/log_event.rb +206 -0
- data/lib/sentry/log_event_buffer.rb +75 -0
- data/lib/sentry/logger.rb +1 -1
- data/lib/sentry/metrics/aggregator.rb +248 -0
- data/lib/sentry/metrics/configuration.rb +47 -0
- data/lib/sentry/metrics/counter_metric.rb +25 -0
- data/lib/sentry/metrics/distribution_metric.rb +25 -0
- data/lib/sentry/metrics/gauge_metric.rb +35 -0
- data/lib/sentry/metrics/local_aggregator.rb +53 -0
- data/lib/sentry/metrics/metric.rb +19 -0
- data/lib/sentry/metrics/set_metric.rb +28 -0
- data/lib/sentry/metrics/timing.rb +51 -0
- data/lib/sentry/metrics.rb +56 -0
- data/lib/sentry/net/http.rb +27 -44
- data/lib/sentry/profiler/helpers.rb +46 -0
- data/lib/sentry/profiler.rb +41 -60
- data/lib/sentry/propagation_context.rb +135 -0
- data/lib/sentry/puma.rb +12 -5
- data/lib/sentry/rack/capture_exceptions.rb +17 -8
- data/lib/sentry/rack.rb +2 -2
- data/lib/sentry/rake.rb +4 -15
- data/lib/sentry/redis.rb +10 -4
- data/lib/sentry/release_detector.rb +5 -5
- data/lib/sentry/rspec.rb +91 -0
- data/lib/sentry/scope.rb +75 -39
- data/lib/sentry/session.rb +2 -2
- data/lib/sentry/session_flusher.rb +15 -43
- data/lib/sentry/span.rb +92 -8
- data/lib/sentry/std_lib_logger.rb +50 -0
- data/lib/sentry/structured_logger.rb +138 -0
- data/lib/sentry/test_helper.rb +42 -13
- data/lib/sentry/threaded_periodic_worker.rb +39 -0
- data/lib/sentry/transaction.rb +44 -43
- data/lib/sentry/transaction_event.rb +10 -6
- data/lib/sentry/transport/configuration.rb +73 -1
- data/lib/sentry/transport/http_transport.rb +71 -41
- data/lib/sentry/transport/spotlight_transport.rb +50 -0
- data/lib/sentry/transport.rb +53 -49
- data/lib/sentry/utils/argument_checking_helper.rb +12 -0
- 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 -7
- data/lib/sentry/utils/real_ip.rb +2 -2
- data/lib/sentry/utils/request_id.rb +1 -1
- 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 +206 -35
- data/sentry-ruby-core.gemspec +3 -1
- data/sentry-ruby.gemspec +15 -6
- metadata +61 -11
@@ -0,0 +1,135 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "securerandom"
|
4
|
+
require "sentry/baggage"
|
5
|
+
require "sentry/utils/uuid"
|
6
|
+
|
7
|
+
module Sentry
|
8
|
+
class PropagationContext
|
9
|
+
SENTRY_TRACE_REGEXP = Regexp.new(
|
10
|
+
"^[ \t]*" + # whitespace
|
11
|
+
"([0-9a-f]{32})?" + # trace_id
|
12
|
+
"-?([0-9a-f]{16})?" + # span_id
|
13
|
+
"-?([01])?" + # sampled
|
14
|
+
"[ \t]*$" # whitespace
|
15
|
+
)
|
16
|
+
|
17
|
+
# An uuid that can be used to identify a trace.
|
18
|
+
# @return [String]
|
19
|
+
attr_reader :trace_id
|
20
|
+
# An uuid that can be used to identify the span.
|
21
|
+
# @return [String]
|
22
|
+
attr_reader :span_id
|
23
|
+
# Span parent's span_id.
|
24
|
+
# @return [String, nil]
|
25
|
+
attr_reader :parent_span_id
|
26
|
+
# The sampling decision of the parent transaction.
|
27
|
+
# @return [Boolean, nil]
|
28
|
+
attr_reader :parent_sampled
|
29
|
+
# Is there an incoming trace or not?
|
30
|
+
# @return [Boolean]
|
31
|
+
attr_reader :incoming_trace
|
32
|
+
# This is only for accessing the current baggage variable.
|
33
|
+
# Please use the #get_baggage method for interfacing outside this class.
|
34
|
+
# @return [Baggage, nil]
|
35
|
+
attr_reader :baggage
|
36
|
+
|
37
|
+
def initialize(scope, env = nil)
|
38
|
+
@scope = scope
|
39
|
+
@parent_span_id = nil
|
40
|
+
@parent_sampled = nil
|
41
|
+
@baggage = nil
|
42
|
+
@incoming_trace = false
|
43
|
+
|
44
|
+
if env
|
45
|
+
sentry_trace_header = env["HTTP_SENTRY_TRACE"] || env[SENTRY_TRACE_HEADER_NAME]
|
46
|
+
baggage_header = env["HTTP_BAGGAGE"] || env[BAGGAGE_HEADER_NAME]
|
47
|
+
|
48
|
+
if sentry_trace_header
|
49
|
+
sentry_trace_data = self.class.extract_sentry_trace(sentry_trace_header)
|
50
|
+
|
51
|
+
if sentry_trace_data
|
52
|
+
@trace_id, @parent_span_id, @parent_sampled = sentry_trace_data
|
53
|
+
|
54
|
+
@baggage =
|
55
|
+
if baggage_header && !baggage_header.empty?
|
56
|
+
Baggage.from_incoming_header(baggage_header)
|
57
|
+
else
|
58
|
+
# If there's an incoming sentry-trace but no incoming baggage header,
|
59
|
+
# for instance in traces coming from older SDKs,
|
60
|
+
# baggage will be empty and frozen and won't be populated as head SDK.
|
61
|
+
Baggage.new({})
|
62
|
+
end
|
63
|
+
|
64
|
+
@baggage.freeze!
|
65
|
+
@incoming_trace = true
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
@trace_id ||= Utils.uuid
|
71
|
+
@span_id = Utils.uuid.slice(0, 16)
|
72
|
+
end
|
73
|
+
|
74
|
+
# Extract the trace_id, parent_span_id and parent_sampled values from a sentry-trace header.
|
75
|
+
#
|
76
|
+
# @param sentry_trace [String] the sentry-trace header value from the previous transaction.
|
77
|
+
# @return [Array, nil]
|
78
|
+
def self.extract_sentry_trace(sentry_trace)
|
79
|
+
match = SENTRY_TRACE_REGEXP.match(sentry_trace)
|
80
|
+
return nil if match.nil?
|
81
|
+
|
82
|
+
trace_id, parent_span_id, sampled_flag = match[1..3]
|
83
|
+
parent_sampled = sampled_flag.nil? ? nil : sampled_flag != "0"
|
84
|
+
|
85
|
+
[trace_id, parent_span_id, parent_sampled]
|
86
|
+
end
|
87
|
+
|
88
|
+
# Returns the trace context that can be used to embed in an Event.
|
89
|
+
# @return [Hash]
|
90
|
+
def get_trace_context
|
91
|
+
{
|
92
|
+
trace_id: trace_id,
|
93
|
+
span_id: span_id,
|
94
|
+
parent_span_id: parent_span_id
|
95
|
+
}
|
96
|
+
end
|
97
|
+
|
98
|
+
# Returns the sentry-trace header from the propagation context.
|
99
|
+
# @return [String]
|
100
|
+
def get_traceparent
|
101
|
+
"#{trace_id}-#{span_id}"
|
102
|
+
end
|
103
|
+
|
104
|
+
# Returns the Baggage from the propagation context or populates as head SDK if empty.
|
105
|
+
# @return [Baggage, nil]
|
106
|
+
def get_baggage
|
107
|
+
populate_head_baggage if @baggage.nil? || @baggage.mutable
|
108
|
+
@baggage
|
109
|
+
end
|
110
|
+
|
111
|
+
# Returns the Dynamic Sampling Context from the baggage.
|
112
|
+
# @return [Hash, nil]
|
113
|
+
def get_dynamic_sampling_context
|
114
|
+
get_baggage&.dynamic_sampling_context
|
115
|
+
end
|
116
|
+
|
117
|
+
private
|
118
|
+
|
119
|
+
def populate_head_baggage
|
120
|
+
return unless Sentry.initialized?
|
121
|
+
|
122
|
+
configuration = Sentry.configuration
|
123
|
+
|
124
|
+
items = {
|
125
|
+
"trace_id" => trace_id,
|
126
|
+
"environment" => configuration.environment,
|
127
|
+
"release" => configuration.release,
|
128
|
+
"public_key" => configuration.dsn&.public_key
|
129
|
+
}
|
130
|
+
|
131
|
+
items.compact!
|
132
|
+
@baggage = Baggage.new(items, mutable: false)
|
133
|
+
end
|
134
|
+
end
|
135
|
+
end
|
data/lib/sentry/puma.rb
CHANGED
@@ -1,10 +1,19 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
return unless defined?(Puma::Server)
|
4
|
+
|
3
5
|
module Sentry
|
4
6
|
module Puma
|
5
7
|
module Server
|
6
|
-
|
7
|
-
|
8
|
+
PUMA_4_AND_PRIOR = Gem::Version.new(::Puma::Const::PUMA_VERSION) < Gem::Version.new("5.0.0")
|
9
|
+
|
10
|
+
def lowlevel_error(e, env, status = 500)
|
11
|
+
result =
|
12
|
+
if PUMA_4_AND_PRIOR
|
13
|
+
super(e, env)
|
14
|
+
else
|
15
|
+
super
|
16
|
+
end
|
8
17
|
|
9
18
|
begin
|
10
19
|
Sentry.capture_exception(e) do |scope|
|
@@ -20,6 +29,4 @@ module Sentry
|
|
20
29
|
end
|
21
30
|
end
|
22
31
|
|
23
|
-
|
24
|
-
Sentry.register_patch(Sentry::Puma::Server, Puma::Server)
|
25
|
-
end
|
32
|
+
Sentry.register_patch(:puma, Sentry::Puma::Server, Puma::Server)
|
@@ -4,6 +4,8 @@ module Sentry
|
|
4
4
|
module Rack
|
5
5
|
class CaptureExceptions
|
6
6
|
ERROR_EVENT_ID_KEY = "sentry.error_event_id"
|
7
|
+
MECHANISM_TYPE = "rack"
|
8
|
+
SPAN_ORIGIN = "auto.http.rack"
|
7
9
|
|
8
10
|
def initialize(app)
|
9
11
|
@app = app
|
@@ -48,25 +50,28 @@ module Sentry
|
|
48
50
|
private
|
49
51
|
|
50
52
|
def collect_exception(env)
|
51
|
-
env[
|
53
|
+
env["rack.exception"] || env["sinatra.error"]
|
52
54
|
end
|
53
55
|
|
54
56
|
def transaction_op
|
55
|
-
"http.server"
|
57
|
+
"http.server"
|
56
58
|
end
|
57
59
|
|
58
60
|
def capture_exception(exception, env)
|
59
|
-
Sentry.capture_exception(exception).tap do |event|
|
61
|
+
Sentry.capture_exception(exception, hint: { mechanism: mechanism }).tap do |event|
|
60
62
|
env[ERROR_EVENT_ID_KEY] = event.event_id if event
|
61
63
|
end
|
62
64
|
end
|
63
65
|
|
64
66
|
def start_transaction(env, scope)
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
67
|
+
options = {
|
68
|
+
name: scope.transaction_name,
|
69
|
+
source: scope.transaction_source,
|
70
|
+
op: transaction_op,
|
71
|
+
origin: SPAN_ORIGIN
|
72
|
+
}
|
73
|
+
|
74
|
+
transaction = Sentry.continue_trace(env, **options)
|
70
75
|
Sentry.start_transaction(transaction: transaction, custom_sampling_context: { env: env }, **options)
|
71
76
|
end
|
72
77
|
|
@@ -77,6 +82,10 @@ module Sentry
|
|
77
82
|
transaction.set_http_status(status_code)
|
78
83
|
transaction.finish
|
79
84
|
end
|
85
|
+
|
86
|
+
def mechanism
|
87
|
+
Sentry::Mechanism.new(type: MECHANISM_TYPE, handled: false)
|
88
|
+
end
|
80
89
|
end
|
81
90
|
end
|
82
91
|
end
|
data/lib/sentry/rack.rb
CHANGED
data/lib/sentry/rake.rb
CHANGED
@@ -8,8 +8,10 @@ module Sentry
|
|
8
8
|
module Application
|
9
9
|
# @api private
|
10
10
|
def display_error_message(ex)
|
11
|
-
Sentry.
|
12
|
-
|
11
|
+
mechanism = Sentry::Mechanism.new(type: "rake", handled: false)
|
12
|
+
|
13
|
+
Sentry.capture_exception(ex, hint: { mechanism: mechanism }) do |scope|
|
14
|
+
task_name = top_level_tasks.join(" ")
|
13
15
|
scope.set_transaction_name(task_name, source: :task)
|
14
16
|
scope.set_tag("rake_task", task_name)
|
15
17
|
end if Sentry.initialized? && !Sentry.configuration.skip_rake_integration
|
@@ -17,15 +19,6 @@ module Sentry
|
|
17
19
|
super
|
18
20
|
end
|
19
21
|
end
|
20
|
-
|
21
|
-
module Task
|
22
|
-
# @api private
|
23
|
-
def execute(args=nil)
|
24
|
-
return super unless Sentry.initialized? && Sentry.get_current_hub
|
25
|
-
|
26
|
-
super
|
27
|
-
end
|
28
|
-
end
|
29
22
|
end
|
30
23
|
end
|
31
24
|
|
@@ -34,8 +27,4 @@ module Rake
|
|
34
27
|
class Application
|
35
28
|
prepend(Sentry::Rake::Application)
|
36
29
|
end
|
37
|
-
|
38
|
-
class Task
|
39
|
-
prepend(Sentry::Rake::Task)
|
40
|
-
end
|
41
30
|
end
|
data/lib/sentry/redis.rb
CHANGED
@@ -4,6 +4,7 @@ module Sentry
|
|
4
4
|
# @api private
|
5
5
|
class Redis
|
6
6
|
OP_NAME = "db.redis"
|
7
|
+
SPAN_ORIGIN = "auto.db.redis"
|
7
8
|
LOGGER_NAME = :redis_logger
|
8
9
|
|
9
10
|
def initialize(commands, host, port, db)
|
@@ -13,13 +14,16 @@ module Sentry
|
|
13
14
|
def instrument
|
14
15
|
return yield unless Sentry.initialized?
|
15
16
|
|
16
|
-
Sentry.with_child_span(op: OP_NAME, start_timestamp: Sentry.utc_now.to_f) do |span|
|
17
|
+
Sentry.with_child_span(op: OP_NAME, start_timestamp: Sentry.utc_now.to_f, origin: SPAN_ORIGIN) do |span|
|
17
18
|
yield.tap do
|
18
19
|
record_breadcrumb
|
19
20
|
|
20
21
|
if span
|
21
22
|
span.set_description(commands_description)
|
22
|
-
span.set_data(
|
23
|
+
span.set_data(Span::DataConventions::DB_SYSTEM, "redis")
|
24
|
+
span.set_data(Span::DataConventions::DB_NAME, db)
|
25
|
+
span.set_data(Span::DataConventions::SERVER_ADDRESS, host)
|
26
|
+
span.set_data(Span::DataConventions::SERVER_PORT, port)
|
23
27
|
end
|
24
28
|
end
|
25
29
|
end
|
@@ -96,8 +100,10 @@ end
|
|
96
100
|
|
97
101
|
if defined?(::Redis::Client)
|
98
102
|
if Gem::Version.new(::Redis::VERSION) < Gem::Version.new("5.0")
|
99
|
-
Sentry.register_patch(Sentry::Redis::OldClientPatch, ::Redis::Client)
|
103
|
+
Sentry.register_patch(:redis, Sentry::Redis::OldClientPatch, ::Redis::Client)
|
100
104
|
elsif defined?(RedisClient)
|
101
|
-
|
105
|
+
Sentry.register_patch(:redis) do
|
106
|
+
RedisClient.register(Sentry::Redis::GlobalRedisInstrumentation)
|
107
|
+
end
|
102
108
|
end
|
103
109
|
end
|
@@ -13,12 +13,12 @@ module Sentry
|
|
13
13
|
|
14
14
|
def detect_release_from_heroku(running_on_heroku)
|
15
15
|
return unless running_on_heroku
|
16
|
-
ENV[
|
16
|
+
ENV["HEROKU_SLUG_COMMIT"]
|
17
17
|
end
|
18
18
|
|
19
19
|
def detect_release_from_capistrano(project_root)
|
20
|
-
revision_file = File.join(project_root,
|
21
|
-
revision_log = File.join(project_root,
|
20
|
+
revision_file = File.join(project_root, "REVISION")
|
21
|
+
revision_log = File.join(project_root, "..", "revisions.log")
|
22
22
|
|
23
23
|
if File.exist?(revision_file)
|
24
24
|
File.read(revision_file).strip
|
@@ -28,11 +28,11 @@ module Sentry
|
|
28
28
|
end
|
29
29
|
|
30
30
|
def detect_release_from_git
|
31
|
-
Sentry.sys_command("git rev-parse
|
31
|
+
Sentry.sys_command("git rev-parse HEAD") if File.directory?(".git")
|
32
32
|
end
|
33
33
|
|
34
34
|
def detect_release_from_env
|
35
|
-
ENV[
|
35
|
+
ENV["SENTRY_RELEASE"]
|
36
36
|
end
|
37
37
|
end
|
38
38
|
end
|
data/lib/sentry/rspec.rb
ADDED
@@ -0,0 +1,91 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
RSpec::Matchers.define :include_sentry_event do |event_message = "", **opts|
|
4
|
+
match do |sentry_events|
|
5
|
+
@expected_exception = expected_exception(**opts)
|
6
|
+
@context = context(**opts)
|
7
|
+
@tags = tags(**opts)
|
8
|
+
|
9
|
+
@expected_event = expected_event(event_message)
|
10
|
+
@matched_event = find_matched_event(event_message, sentry_events)
|
11
|
+
|
12
|
+
return false unless @matched_event
|
13
|
+
|
14
|
+
[verify_context(), verify_tags()].all?
|
15
|
+
end
|
16
|
+
|
17
|
+
chain :with_context do |context|
|
18
|
+
@context = context
|
19
|
+
end
|
20
|
+
|
21
|
+
chain :with_tags do |tags|
|
22
|
+
@tags = tags
|
23
|
+
end
|
24
|
+
|
25
|
+
failure_message do |sentry_events|
|
26
|
+
info = ["Failed to find event matching:\n"]
|
27
|
+
info << " message: #{@expected_event.message.inspect}"
|
28
|
+
info << " exception: #{@expected_exception.inspect}"
|
29
|
+
info << " context: #{@context.inspect}"
|
30
|
+
info << " tags: #{@tags.inspect}"
|
31
|
+
info << "\n"
|
32
|
+
info << "Captured events:\n"
|
33
|
+
info << dump_events(sentry_events)
|
34
|
+
info.join("\n")
|
35
|
+
end
|
36
|
+
|
37
|
+
def expected_event(event_message)
|
38
|
+
if @expected_exception
|
39
|
+
Sentry.get_current_client.event_from_exception(@expected_exception)
|
40
|
+
else
|
41
|
+
Sentry.get_current_client.event_from_message(event_message)
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
def expected_exception(**opts)
|
46
|
+
opts[:exception].new(opts[:message]) if opts[:exception]
|
47
|
+
end
|
48
|
+
|
49
|
+
def context(**opts)
|
50
|
+
opts.fetch(:context, @context || {})
|
51
|
+
end
|
52
|
+
|
53
|
+
def tags(**opts)
|
54
|
+
opts.fetch(:tags, @tags || {})
|
55
|
+
end
|
56
|
+
|
57
|
+
def find_matched_event(event_message, sentry_events)
|
58
|
+
@matched_event ||= sentry_events
|
59
|
+
.find { |event|
|
60
|
+
if @expected_exception
|
61
|
+
# Is it OK that we only compare the first exception?
|
62
|
+
event_exception = event.exception.values.first
|
63
|
+
expected_event_exception = @expected_event.exception.values.first
|
64
|
+
|
65
|
+
event_exception.type == expected_event_exception.type && event_exception.value == expected_event_exception.value
|
66
|
+
else
|
67
|
+
event.message == @expected_event.message
|
68
|
+
end
|
69
|
+
}
|
70
|
+
end
|
71
|
+
|
72
|
+
def dump_events(sentry_events)
|
73
|
+
sentry_events.map(&Kernel.method(:Hash)).map do |hash|
|
74
|
+
hash.select { |k, _| [:message, :contexts, :tags, :exception].include?(k) }
|
75
|
+
end.map do |hash|
|
76
|
+
JSON.pretty_generate(hash)
|
77
|
+
end.join("\n\n")
|
78
|
+
end
|
79
|
+
|
80
|
+
def verify_context
|
81
|
+
return true if @context.empty?
|
82
|
+
|
83
|
+
@matched_event.contexts.any? { |key, value| value == @context[key] }
|
84
|
+
end
|
85
|
+
|
86
|
+
def verify_tags
|
87
|
+
return true if @tags.empty?
|
88
|
+
|
89
|
+
@tags.all? { |key, value| @matched_event.tags.include?(key) && @matched_event.tags[key] == value }
|
90
|
+
end
|
91
|
+
end
|
data/lib/sentry/scope.rb
CHANGED
@@ -1,6 +1,8 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require "sentry/breadcrumb_buffer"
|
4
|
+
require "sentry/propagation_context"
|
5
|
+
require "sentry/attachment"
|
4
6
|
require "etc"
|
5
7
|
|
6
8
|
module Sentry
|
@@ -8,8 +10,8 @@ module Sentry
|
|
8
10
|
include ArgumentCheckingHelper
|
9
11
|
|
10
12
|
ATTRIBUTES = [
|
11
|
-
:
|
12
|
-
:
|
13
|
+
:transaction_name,
|
14
|
+
:transaction_source,
|
13
15
|
:contexts,
|
14
16
|
:extra,
|
15
17
|
:tags,
|
@@ -20,7 +22,9 @@ module Sentry
|
|
20
22
|
:event_processors,
|
21
23
|
:rack_env,
|
22
24
|
:span,
|
23
|
-
:session
|
25
|
+
:session,
|
26
|
+
:attachments,
|
27
|
+
:propagation_context
|
24
28
|
]
|
25
29
|
|
26
30
|
attr_reader(*ATTRIBUTES)
|
@@ -42,21 +46,37 @@ module Sentry
|
|
42
46
|
# @param hint [Hash] the hint data that'll be passed to event processors.
|
43
47
|
# @return [Event]
|
44
48
|
def apply_to_event(event, hint = nil)
|
45
|
-
event.
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
49
|
+
unless event.is_a?(CheckInEvent) || event.is_a?(LogEvent)
|
50
|
+
event.tags = tags.merge(event.tags)
|
51
|
+
event.user = user.merge(event.user)
|
52
|
+
event.extra = extra.merge(event.extra)
|
53
|
+
event.contexts = contexts.merge(event.contexts)
|
54
|
+
event.transaction = transaction_name if transaction_name
|
55
|
+
event.transaction_info = { source: transaction_source } if transaction_source
|
56
|
+
event.fingerprint = fingerprint
|
57
|
+
event.level = level
|
58
|
+
event.breadcrumbs = breadcrumbs
|
59
|
+
event.rack_env = rack_env if rack_env
|
60
|
+
event.attachments = attachments
|
61
|
+
end
|
51
62
|
|
52
|
-
if
|
53
|
-
event.
|
63
|
+
if event.is_a?(LogEvent)
|
64
|
+
event.user = user.merge(event.user)
|
54
65
|
end
|
55
66
|
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
67
|
+
if span
|
68
|
+
event.contexts[:trace] ||= span.get_trace_context
|
69
|
+
|
70
|
+
if event.respond_to?(:dynamic_sampling_context)
|
71
|
+
event.dynamic_sampling_context ||= span.get_dynamic_sampling_context
|
72
|
+
end
|
73
|
+
else
|
74
|
+
event.contexts[:trace] ||= propagation_context.get_trace_context
|
75
|
+
|
76
|
+
if event.respond_to?(:dynamic_sampling_context)
|
77
|
+
event.dynamic_sampling_context ||= propagation_context.get_dynamic_sampling_context
|
78
|
+
end
|
79
|
+
end
|
60
80
|
|
61
81
|
all_event_processors = self.class.global_event_processors + @event_processors
|
62
82
|
|
@@ -90,11 +110,13 @@ module Sentry
|
|
90
110
|
copy.extra = extra.deep_dup
|
91
111
|
copy.tags = tags.deep_dup
|
92
112
|
copy.user = user.deep_dup
|
93
|
-
copy.
|
94
|
-
copy.
|
113
|
+
copy.transaction_name = transaction_name.dup
|
114
|
+
copy.transaction_source = transaction_source.dup
|
95
115
|
copy.fingerprint = fingerprint.deep_dup
|
96
116
|
copy.span = span.deep_dup
|
97
117
|
copy.session = session.deep_dup
|
118
|
+
copy.propagation_context = propagation_context.deep_dup
|
119
|
+
copy.attachments = attachments.dup
|
98
120
|
copy
|
99
121
|
end
|
100
122
|
|
@@ -107,10 +129,12 @@ module Sentry
|
|
107
129
|
self.extra = scope.extra
|
108
130
|
self.tags = scope.tags
|
109
131
|
self.user = scope.user
|
110
|
-
self.
|
111
|
-
self.
|
132
|
+
self.transaction_name = scope.transaction_name
|
133
|
+
self.transaction_source = scope.transaction_source
|
112
134
|
self.fingerprint = scope.fingerprint
|
113
135
|
self.span = scope.span
|
136
|
+
self.propagation_context = scope.propagation_context
|
137
|
+
self.attachments = scope.attachments
|
114
138
|
end
|
115
139
|
|
116
140
|
# Updates the scope's data from the given options.
|
@@ -120,14 +144,17 @@ module Sentry
|
|
120
144
|
# @param user [Hash]
|
121
145
|
# @param level [String, Symbol]
|
122
146
|
# @param fingerprint [Array]
|
123
|
-
# @
|
147
|
+
# @param attachments [Array<Attachment>]
|
148
|
+
# @return [Array]
|
124
149
|
def update_from_options(
|
125
150
|
contexts: nil,
|
126
151
|
extra: nil,
|
127
152
|
tags: nil,
|
128
153
|
user: nil,
|
129
154
|
level: nil,
|
130
|
-
fingerprint: nil
|
155
|
+
fingerprint: nil,
|
156
|
+
attachments: nil,
|
157
|
+
**options
|
131
158
|
)
|
132
159
|
self.contexts.merge!(contexts) if contexts
|
133
160
|
self.extra.merge!(extra) if extra
|
@@ -135,6 +162,9 @@ module Sentry
|
|
135
162
|
self.user = user if user
|
136
163
|
self.level = level if level
|
137
164
|
self.fingerprint = fingerprint if fingerprint
|
165
|
+
|
166
|
+
# Returns unsupported option keys so we can notify users.
|
167
|
+
options.keys
|
138
168
|
end
|
139
169
|
|
140
170
|
# Sets the scope's rack_env attribute.
|
@@ -219,8 +249,8 @@ module Sentry
|
|
219
249
|
# @param transaction_name [String]
|
220
250
|
# @return [void]
|
221
251
|
def set_transaction_name(transaction_name, source: :custom)
|
222
|
-
@
|
223
|
-
@
|
252
|
+
@transaction_name = transaction_name
|
253
|
+
@transaction_source = source
|
224
254
|
end
|
225
255
|
|
226
256
|
# Sets the currently active session on the scope.
|
@@ -230,18 +260,10 @@ module Sentry
|
|
230
260
|
@session = session
|
231
261
|
end
|
232
262
|
|
233
|
-
#
|
234
|
-
#
|
235
|
-
|
236
|
-
|
237
|
-
@transaction_names.last
|
238
|
-
end
|
239
|
-
|
240
|
-
# Returns current transaction source.
|
241
|
-
# The "transaction" here does not refer to `Transaction` objects.
|
242
|
-
# @return [String, nil]
|
243
|
-
def transaction_source
|
244
|
-
@transaction_sources.last
|
263
|
+
# These are high cardinality and thus bad.
|
264
|
+
# @return [Boolean]
|
265
|
+
def transaction_source_low_quality?
|
266
|
+
transaction_source == :url
|
245
267
|
end
|
246
268
|
|
247
269
|
# Returns the associated Transaction object.
|
@@ -272,6 +294,19 @@ module Sentry
|
|
272
294
|
@event_processors << block
|
273
295
|
end
|
274
296
|
|
297
|
+
# Generate a new propagation context either from the incoming env headers or from scratch.
|
298
|
+
# @param env [Hash, nil]
|
299
|
+
# @return [void]
|
300
|
+
def generate_propagation_context(env = nil)
|
301
|
+
@propagation_context = PropagationContext.new(self, env)
|
302
|
+
end
|
303
|
+
|
304
|
+
# Add a new attachment to the scope.
|
305
|
+
def add_attachment(**opts)
|
306
|
+
attachments << (attachment = Attachment.new(**opts))
|
307
|
+
attachment
|
308
|
+
end
|
309
|
+
|
275
310
|
protected
|
276
311
|
|
277
312
|
# for duplicating scopes internally
|
@@ -280,18 +315,20 @@ module Sentry
|
|
280
315
|
private
|
281
316
|
|
282
317
|
def set_default_value
|
283
|
-
@contexts = { :
|
318
|
+
@contexts = { os: self.class.os_context, runtime: self.class.runtime_context }
|
284
319
|
@extra = {}
|
285
320
|
@tags = {}
|
286
321
|
@user = {}
|
287
322
|
@level = :error
|
288
323
|
@fingerprint = []
|
289
|
-
@
|
290
|
-
@
|
324
|
+
@transaction_name = nil
|
325
|
+
@transaction_source = nil
|
291
326
|
@event_processors = []
|
292
327
|
@rack_env = {}
|
293
328
|
@span = nil
|
294
329
|
@session = nil
|
330
|
+
@attachments = []
|
331
|
+
generate_propagation_context
|
295
332
|
set_new_breadcrumb_buffer
|
296
333
|
end
|
297
334
|
|
@@ -339,6 +376,5 @@ module Sentry
|
|
339
376
|
global_event_processors << block
|
340
377
|
end
|
341
378
|
end
|
342
|
-
|
343
379
|
end
|
344
380
|
end
|
data/lib/sentry/session.rb
CHANGED
@@ -5,8 +5,8 @@ module Sentry
|
|
5
5
|
attr_reader :started, :status, :aggregation_key
|
6
6
|
|
7
7
|
# TODO-neel add :crashed after adding handled mechanism
|
8
|
-
STATUSES = %i
|
9
|
-
AGGREGATE_STATUSES = %i
|
8
|
+
STATUSES = %i[ok errored exited]
|
9
|
+
AGGREGATE_STATUSES = %i[errored exited]
|
10
10
|
|
11
11
|
def initialize
|
12
12
|
@started = Sentry.utc_now
|