sentry-ruby 5.3.1 → 5.16.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +11 -0
- data/.rspec +2 -0
- data/.yardopts +2 -0
- data/CHANGELOG.md +313 -0
- data/Gemfile +26 -0
- data/Makefile +4 -0
- data/README.md +11 -8
- data/Rakefile +20 -0
- data/bin/console +18 -0
- data/bin/setup +8 -0
- data/lib/sentry/background_worker.rb +79 -0
- data/lib/sentry/backpressure_monitor.rb +75 -0
- data/lib/sentry/backtrace.rb +124 -0
- data/lib/sentry/baggage.rb +70 -0
- data/lib/sentry/breadcrumb/sentry_logger.rb +90 -0
- data/lib/sentry/breadcrumb.rb +76 -0
- data/lib/sentry/breadcrumb_buffer.rb +64 -0
- data/lib/sentry/check_in_event.rb +60 -0
- data/lib/sentry/client.rb +248 -0
- data/lib/sentry/configuration.rb +650 -0
- data/lib/sentry/core_ext/object/deep_dup.rb +61 -0
- data/lib/sentry/core_ext/object/duplicable.rb +155 -0
- data/lib/sentry/cron/configuration.rb +23 -0
- data/lib/sentry/cron/monitor_check_ins.rb +75 -0
- data/lib/sentry/cron/monitor_config.rb +53 -0
- data/lib/sentry/cron/monitor_schedule.rb +42 -0
- data/lib/sentry/dsn.rb +53 -0
- data/lib/sentry/envelope.rb +93 -0
- data/lib/sentry/error_event.rb +38 -0
- data/lib/sentry/event.rb +156 -0
- data/lib/sentry/exceptions.rb +9 -0
- data/lib/sentry/hub.rb +316 -0
- data/lib/sentry/integrable.rb +32 -0
- data/lib/sentry/interface.rb +16 -0
- data/lib/sentry/interfaces/exception.rb +43 -0
- data/lib/sentry/interfaces/request.rb +134 -0
- data/lib/sentry/interfaces/single_exception.rb +67 -0
- data/lib/sentry/interfaces/stacktrace.rb +87 -0
- data/lib/sentry/interfaces/stacktrace_builder.rb +79 -0
- data/lib/sentry/interfaces/threads.rb +42 -0
- data/lib/sentry/linecache.rb +47 -0
- data/lib/sentry/logger.rb +20 -0
- data/lib/sentry/net/http.rb +106 -0
- data/lib/sentry/profiler.rb +233 -0
- data/lib/sentry/propagation_context.rb +134 -0
- data/lib/sentry/puma.rb +32 -0
- data/lib/sentry/rack/capture_exceptions.rb +79 -0
- data/lib/sentry/rack.rb +5 -0
- data/lib/sentry/rake.rb +28 -0
- data/lib/sentry/redis.rb +108 -0
- data/lib/sentry/release_detector.rb +39 -0
- data/lib/sentry/scope.rb +360 -0
- data/lib/sentry/session.rb +33 -0
- data/lib/sentry/session_flusher.rb +90 -0
- data/lib/sentry/span.rb +273 -0
- data/lib/sentry/test_helper.rb +84 -0
- data/lib/sentry/transaction.rb +359 -0
- data/lib/sentry/transaction_event.rb +80 -0
- data/lib/sentry/transport/configuration.rb +98 -0
- data/lib/sentry/transport/dummy_transport.rb +21 -0
- data/lib/sentry/transport/http_transport.rb +206 -0
- data/lib/sentry/transport/spotlight_transport.rb +50 -0
- data/lib/sentry/transport.rb +225 -0
- data/lib/sentry/utils/argument_checking_helper.rb +19 -0
- data/lib/sentry/utils/custom_inspection.rb +14 -0
- data/lib/sentry/utils/encoding_helper.rb +22 -0
- data/lib/sentry/utils/exception_cause_chain.rb +20 -0
- data/lib/sentry/utils/logging_helper.rb +26 -0
- data/lib/sentry/utils/real_ip.rb +84 -0
- data/lib/sentry/utils/request_id.rb +18 -0
- data/lib/sentry/version.rb +5 -0
- data/lib/sentry-ruby.rb +580 -0
- data/sentry-ruby-core.gemspec +23 -0
- data/sentry-ruby.gemspec +24 -0
- metadata +75 -16
@@ -0,0 +1,79 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Sentry
|
4
|
+
module Rack
|
5
|
+
class CaptureExceptions
|
6
|
+
ERROR_EVENT_ID_KEY = "sentry.error_event_id"
|
7
|
+
|
8
|
+
def initialize(app)
|
9
|
+
@app = app
|
10
|
+
end
|
11
|
+
|
12
|
+
def call(env)
|
13
|
+
return @app.call(env) unless Sentry.initialized?
|
14
|
+
|
15
|
+
# make sure the current thread has a clean hub
|
16
|
+
Sentry.clone_hub_to_current_thread
|
17
|
+
|
18
|
+
Sentry.with_scope do |scope|
|
19
|
+
Sentry.with_session_tracking do
|
20
|
+
scope.clear_breadcrumbs
|
21
|
+
scope.set_transaction_name(env["PATH_INFO"], source: :url) if env["PATH_INFO"]
|
22
|
+
scope.set_rack_env(env)
|
23
|
+
|
24
|
+
transaction = start_transaction(env, scope)
|
25
|
+
scope.set_span(transaction) if transaction
|
26
|
+
|
27
|
+
begin
|
28
|
+
response = @app.call(env)
|
29
|
+
rescue Sentry::Error
|
30
|
+
finish_transaction(transaction, 500)
|
31
|
+
raise # Don't capture Sentry errors
|
32
|
+
rescue Exception => e
|
33
|
+
capture_exception(e, env)
|
34
|
+
finish_transaction(transaction, 500)
|
35
|
+
raise
|
36
|
+
end
|
37
|
+
|
38
|
+
exception = collect_exception(env)
|
39
|
+
capture_exception(exception, env) if exception
|
40
|
+
|
41
|
+
finish_transaction(transaction, response[0])
|
42
|
+
|
43
|
+
response
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
private
|
49
|
+
|
50
|
+
def collect_exception(env)
|
51
|
+
env['rack.exception'] || env['sinatra.error']
|
52
|
+
end
|
53
|
+
|
54
|
+
def transaction_op
|
55
|
+
"http.server".freeze
|
56
|
+
end
|
57
|
+
|
58
|
+
def capture_exception(exception, env)
|
59
|
+
Sentry.capture_exception(exception).tap do |event|
|
60
|
+
env[ERROR_EVENT_ID_KEY] = event.event_id if event
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
def start_transaction(env, scope)
|
65
|
+
options = { name: scope.transaction_name, source: scope.transaction_source, op: transaction_op }
|
66
|
+
transaction = Sentry.continue_trace(env, **options)
|
67
|
+
Sentry.start_transaction(transaction: transaction, custom_sampling_context: { env: env }, **options)
|
68
|
+
end
|
69
|
+
|
70
|
+
|
71
|
+
def finish_transaction(transaction, status_code)
|
72
|
+
return unless transaction
|
73
|
+
|
74
|
+
transaction.set_http_status(status_code)
|
75
|
+
transaction.finish
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
data/lib/sentry/rack.rb
ADDED
data/lib/sentry/rake.rb
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "rake"
|
4
|
+
require "rake/task"
|
5
|
+
|
6
|
+
module Sentry
|
7
|
+
module Rake
|
8
|
+
module Application
|
9
|
+
# @api private
|
10
|
+
def display_error_message(ex)
|
11
|
+
Sentry.capture_exception(ex) do |scope|
|
12
|
+
task_name = top_level_tasks.join(' ')
|
13
|
+
scope.set_transaction_name(task_name, source: :task)
|
14
|
+
scope.set_tag("rake_task", task_name)
|
15
|
+
end if Sentry.initialized? && !Sentry.configuration.skip_rake_integration
|
16
|
+
|
17
|
+
super
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
# @api private
|
24
|
+
module Rake
|
25
|
+
class Application
|
26
|
+
prepend(Sentry::Rake::Application)
|
27
|
+
end
|
28
|
+
end
|
data/lib/sentry/redis.rb
ADDED
@@ -0,0 +1,108 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Sentry
|
4
|
+
# @api private
|
5
|
+
class Redis
|
6
|
+
OP_NAME = "db.redis"
|
7
|
+
LOGGER_NAME = :redis_logger
|
8
|
+
|
9
|
+
def initialize(commands, host, port, db)
|
10
|
+
@commands, @host, @port, @db = commands, host, port, db
|
11
|
+
end
|
12
|
+
|
13
|
+
def instrument
|
14
|
+
return yield unless Sentry.initialized?
|
15
|
+
|
16
|
+
Sentry.with_child_span(op: OP_NAME, start_timestamp: Sentry.utc_now.to_f) do |span|
|
17
|
+
yield.tap do
|
18
|
+
record_breadcrumb
|
19
|
+
|
20
|
+
if span
|
21
|
+
span.set_description(commands_description)
|
22
|
+
span.set_data(Span::DataConventions::DB_SYSTEM, "redis")
|
23
|
+
span.set_data(Span::DataConventions::DB_NAME, db)
|
24
|
+
span.set_data(Span::DataConventions::SERVER_ADDRESS, host)
|
25
|
+
span.set_data(Span::DataConventions::SERVER_PORT, port)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
private
|
32
|
+
|
33
|
+
attr_reader :commands, :host, :port, :db
|
34
|
+
|
35
|
+
def record_breadcrumb
|
36
|
+
return unless Sentry.initialized?
|
37
|
+
return unless Sentry.configuration.breadcrumbs_logger.include?(LOGGER_NAME)
|
38
|
+
|
39
|
+
Sentry.add_breadcrumb(
|
40
|
+
Sentry::Breadcrumb.new(
|
41
|
+
level: :info,
|
42
|
+
category: OP_NAME,
|
43
|
+
type: :info,
|
44
|
+
data: {
|
45
|
+
commands: parsed_commands,
|
46
|
+
server: server_description
|
47
|
+
}
|
48
|
+
)
|
49
|
+
)
|
50
|
+
end
|
51
|
+
|
52
|
+
def commands_description
|
53
|
+
parsed_commands.map do |statement|
|
54
|
+
statement.values.join(" ").strip
|
55
|
+
end.join(", ")
|
56
|
+
end
|
57
|
+
|
58
|
+
def parsed_commands
|
59
|
+
commands.map do |statement|
|
60
|
+
command, key, *arguments = statement
|
61
|
+
command_set = { command: command.to_s.upcase }
|
62
|
+
command_set[:key] = key if Utils::EncodingHelper.valid_utf_8?(key)
|
63
|
+
|
64
|
+
if Sentry.configuration.send_default_pii
|
65
|
+
command_set[:arguments] = arguments
|
66
|
+
.select { |a| Utils::EncodingHelper.valid_utf_8?(a) }
|
67
|
+
.join(" ")
|
68
|
+
end
|
69
|
+
|
70
|
+
command_set
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
def server_description
|
75
|
+
"#{host}:#{port}/#{db}"
|
76
|
+
end
|
77
|
+
|
78
|
+
module OldClientPatch
|
79
|
+
def logging(commands, &block)
|
80
|
+
Sentry::Redis.new(commands, host, port, db).instrument { super }
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
module GlobalRedisInstrumentation
|
85
|
+
def call(command, redis_config)
|
86
|
+
Sentry::Redis
|
87
|
+
.new([command], redis_config.host, redis_config.port, redis_config.db)
|
88
|
+
.instrument { super }
|
89
|
+
end
|
90
|
+
|
91
|
+
def call_pipelined(commands, redis_config)
|
92
|
+
Sentry::Redis
|
93
|
+
.new(commands, redis_config.host, redis_config.port, redis_config.db)
|
94
|
+
.instrument { super }
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
if defined?(::Redis::Client)
|
101
|
+
if Gem::Version.new(::Redis::VERSION) < Gem::Version.new("5.0")
|
102
|
+
Sentry.register_patch(:redis, Sentry::Redis::OldClientPatch, ::Redis::Client)
|
103
|
+
elsif defined?(RedisClient)
|
104
|
+
Sentry.register_patch(:redis) do
|
105
|
+
RedisClient.register(Sentry::Redis::GlobalRedisInstrumentation)
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Sentry
|
4
|
+
# @api private
|
5
|
+
class ReleaseDetector
|
6
|
+
class << self
|
7
|
+
def detect_release(project_root:, running_on_heroku:)
|
8
|
+
detect_release_from_env ||
|
9
|
+
detect_release_from_git ||
|
10
|
+
detect_release_from_capistrano(project_root) ||
|
11
|
+
detect_release_from_heroku(running_on_heroku)
|
12
|
+
end
|
13
|
+
|
14
|
+
def detect_release_from_heroku(running_on_heroku)
|
15
|
+
return unless running_on_heroku
|
16
|
+
ENV['HEROKU_SLUG_COMMIT']
|
17
|
+
end
|
18
|
+
|
19
|
+
def detect_release_from_capistrano(project_root)
|
20
|
+
revision_file = File.join(project_root, 'REVISION')
|
21
|
+
revision_log = File.join(project_root, '..', 'revisions.log')
|
22
|
+
|
23
|
+
if File.exist?(revision_file)
|
24
|
+
File.read(revision_file).strip
|
25
|
+
elsif File.exist?(revision_log)
|
26
|
+
File.open(revision_log).to_a.last.strip.sub(/.*as release ([0-9]+).*/, '\1')
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def detect_release_from_git
|
31
|
+
Sentry.sys_command("git rev-parse HEAD") if File.directory?(".git")
|
32
|
+
end
|
33
|
+
|
34
|
+
def detect_release_from_env
|
35
|
+
ENV['SENTRY_RELEASE']
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
data/lib/sentry/scope.rb
ADDED
@@ -0,0 +1,360 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "sentry/breadcrumb_buffer"
|
4
|
+
require "sentry/propagation_context"
|
5
|
+
require "etc"
|
6
|
+
|
7
|
+
module Sentry
|
8
|
+
class Scope
|
9
|
+
include ArgumentCheckingHelper
|
10
|
+
|
11
|
+
ATTRIBUTES = [
|
12
|
+
:transaction_names,
|
13
|
+
:transaction_sources,
|
14
|
+
:contexts,
|
15
|
+
:extra,
|
16
|
+
:tags,
|
17
|
+
:user,
|
18
|
+
:level,
|
19
|
+
:breadcrumbs,
|
20
|
+
:fingerprint,
|
21
|
+
:event_processors,
|
22
|
+
:rack_env,
|
23
|
+
:span,
|
24
|
+
:session,
|
25
|
+
:propagation_context
|
26
|
+
]
|
27
|
+
|
28
|
+
attr_reader(*ATTRIBUTES)
|
29
|
+
|
30
|
+
# @param max_breadcrumbs [Integer] the maximum number of breadcrumbs to be stored in the scope.
|
31
|
+
def initialize(max_breadcrumbs: nil)
|
32
|
+
@max_breadcrumbs = max_breadcrumbs
|
33
|
+
set_default_value
|
34
|
+
end
|
35
|
+
|
36
|
+
# Resets the scope's attributes to defaults.
|
37
|
+
# @return [void]
|
38
|
+
def clear
|
39
|
+
set_default_value
|
40
|
+
end
|
41
|
+
|
42
|
+
# Applies stored attributes and event processors to the given event.
|
43
|
+
# @param event [Event]
|
44
|
+
# @param hint [Hash] the hint data that'll be passed to event processors.
|
45
|
+
# @return [Event]
|
46
|
+
def apply_to_event(event, hint = nil)
|
47
|
+
unless event.is_a?(CheckInEvent)
|
48
|
+
event.tags = tags.merge(event.tags)
|
49
|
+
event.user = user.merge(event.user)
|
50
|
+
event.extra = extra.merge(event.extra)
|
51
|
+
event.contexts = contexts.merge(event.contexts)
|
52
|
+
event.transaction = transaction_name if transaction_name
|
53
|
+
event.transaction_info = { source: transaction_source } if transaction_source
|
54
|
+
event.fingerprint = fingerprint
|
55
|
+
event.level = level
|
56
|
+
event.breadcrumbs = breadcrumbs
|
57
|
+
event.rack_env = rack_env if rack_env
|
58
|
+
end
|
59
|
+
|
60
|
+
if span
|
61
|
+
event.contexts[:trace] ||= span.get_trace_context
|
62
|
+
else
|
63
|
+
event.contexts[:trace] ||= propagation_context.get_trace_context
|
64
|
+
event.dynamic_sampling_context ||= propagation_context.get_dynamic_sampling_context
|
65
|
+
end
|
66
|
+
|
67
|
+
all_event_processors = self.class.global_event_processors + @event_processors
|
68
|
+
|
69
|
+
unless all_event_processors.empty?
|
70
|
+
all_event_processors.each do |processor_block|
|
71
|
+
event = processor_block.call(event, hint)
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
event
|
76
|
+
end
|
77
|
+
|
78
|
+
# Adds the breadcrumb to the scope's breadcrumbs buffer.
|
79
|
+
# @param breadcrumb [Breadcrumb]
|
80
|
+
# @return [void]
|
81
|
+
def add_breadcrumb(breadcrumb)
|
82
|
+
breadcrumbs.record(breadcrumb)
|
83
|
+
end
|
84
|
+
|
85
|
+
# Clears the scope's breadcrumbs buffer
|
86
|
+
# @return [void]
|
87
|
+
def clear_breadcrumbs
|
88
|
+
set_new_breadcrumb_buffer
|
89
|
+
end
|
90
|
+
|
91
|
+
# @return [Scope]
|
92
|
+
def dup
|
93
|
+
copy = super
|
94
|
+
copy.breadcrumbs = breadcrumbs.dup
|
95
|
+
copy.contexts = contexts.deep_dup
|
96
|
+
copy.extra = extra.deep_dup
|
97
|
+
copy.tags = tags.deep_dup
|
98
|
+
copy.user = user.deep_dup
|
99
|
+
copy.transaction_names = transaction_names.dup
|
100
|
+
copy.transaction_sources = transaction_sources.dup
|
101
|
+
copy.fingerprint = fingerprint.deep_dup
|
102
|
+
copy.span = span.deep_dup
|
103
|
+
copy.session = session.deep_dup
|
104
|
+
copy.propagation_context = propagation_context.deep_dup
|
105
|
+
copy
|
106
|
+
end
|
107
|
+
|
108
|
+
# Updates the scope's data from a given scope.
|
109
|
+
# @param scope [Scope]
|
110
|
+
# @return [void]
|
111
|
+
def update_from_scope(scope)
|
112
|
+
self.breadcrumbs = scope.breadcrumbs
|
113
|
+
self.contexts = scope.contexts
|
114
|
+
self.extra = scope.extra
|
115
|
+
self.tags = scope.tags
|
116
|
+
self.user = scope.user
|
117
|
+
self.transaction_names = scope.transaction_names
|
118
|
+
self.transaction_sources = scope.transaction_sources
|
119
|
+
self.fingerprint = scope.fingerprint
|
120
|
+
self.span = scope.span
|
121
|
+
self.propagation_context = scope.propagation_context
|
122
|
+
end
|
123
|
+
|
124
|
+
# Updates the scope's data from the given options.
|
125
|
+
# @param contexts [Hash]
|
126
|
+
# @param extras [Hash]
|
127
|
+
# @param tags [Hash]
|
128
|
+
# @param user [Hash]
|
129
|
+
# @param level [String, Symbol]
|
130
|
+
# @param fingerprint [Array]
|
131
|
+
# @return [void]
|
132
|
+
def update_from_options(
|
133
|
+
contexts: nil,
|
134
|
+
extra: nil,
|
135
|
+
tags: nil,
|
136
|
+
user: nil,
|
137
|
+
level: nil,
|
138
|
+
fingerprint: nil
|
139
|
+
)
|
140
|
+
self.contexts.merge!(contexts) if contexts
|
141
|
+
self.extra.merge!(extra) if extra
|
142
|
+
self.tags.merge!(tags) if tags
|
143
|
+
self.user = user if user
|
144
|
+
self.level = level if level
|
145
|
+
self.fingerprint = fingerprint if fingerprint
|
146
|
+
end
|
147
|
+
|
148
|
+
# Sets the scope's rack_env attribute.
|
149
|
+
# @param env [Hash]
|
150
|
+
# @return [Hash]
|
151
|
+
def set_rack_env(env)
|
152
|
+
env = env || {}
|
153
|
+
@rack_env = env
|
154
|
+
end
|
155
|
+
|
156
|
+
# Sets the scope's span attribute.
|
157
|
+
# @param span [Span]
|
158
|
+
# @return [Span]
|
159
|
+
def set_span(span)
|
160
|
+
check_argument_type!(span, Span)
|
161
|
+
@span = span
|
162
|
+
end
|
163
|
+
|
164
|
+
# @!macro set_user
|
165
|
+
def set_user(user_hash)
|
166
|
+
check_argument_type!(user_hash, Hash)
|
167
|
+
@user = user_hash
|
168
|
+
end
|
169
|
+
|
170
|
+
# @!macro set_extras
|
171
|
+
def set_extras(extras_hash)
|
172
|
+
check_argument_type!(extras_hash, Hash)
|
173
|
+
@extra.merge!(extras_hash)
|
174
|
+
end
|
175
|
+
|
176
|
+
# Adds a new key-value pair to current extras.
|
177
|
+
# @param key [String, Symbol]
|
178
|
+
# @param value [Object]
|
179
|
+
# @return [Hash]
|
180
|
+
def set_extra(key, value)
|
181
|
+
set_extras(key => value)
|
182
|
+
end
|
183
|
+
|
184
|
+
# @!macro set_tags
|
185
|
+
def set_tags(tags_hash)
|
186
|
+
check_argument_type!(tags_hash, Hash)
|
187
|
+
@tags.merge!(tags_hash)
|
188
|
+
end
|
189
|
+
|
190
|
+
# Adds a new key-value pair to current tags.
|
191
|
+
# @param key [String, Symbol]
|
192
|
+
# @param value [Object]
|
193
|
+
# @return [Hash]
|
194
|
+
def set_tag(key, value)
|
195
|
+
set_tags(key => value)
|
196
|
+
end
|
197
|
+
|
198
|
+
# Updates the scope's contexts attribute by merging with the old value.
|
199
|
+
# @param contexts [Hash]
|
200
|
+
# @return [Hash]
|
201
|
+
def set_contexts(contexts_hash)
|
202
|
+
check_argument_type!(contexts_hash, Hash)
|
203
|
+
contexts_hash.values.each do |val|
|
204
|
+
check_argument_type!(val, Hash)
|
205
|
+
end
|
206
|
+
|
207
|
+
@contexts.merge!(contexts_hash) do |key, old, new|
|
208
|
+
old.merge(new)
|
209
|
+
end
|
210
|
+
end
|
211
|
+
|
212
|
+
# @!macro set_context
|
213
|
+
def set_context(key, value)
|
214
|
+
check_argument_type!(value, Hash)
|
215
|
+
set_contexts(key => value)
|
216
|
+
end
|
217
|
+
|
218
|
+
# Sets the scope's level attribute.
|
219
|
+
# @param level [String, Symbol]
|
220
|
+
# @return [void]
|
221
|
+
def set_level(level)
|
222
|
+
@level = level
|
223
|
+
end
|
224
|
+
|
225
|
+
# Appends a new transaction name to the scope.
|
226
|
+
# The "transaction" here does not refer to `Transaction` objects.
|
227
|
+
# @param transaction_name [String]
|
228
|
+
# @return [void]
|
229
|
+
def set_transaction_name(transaction_name, source: :custom)
|
230
|
+
@transaction_names << transaction_name
|
231
|
+
@transaction_sources << source
|
232
|
+
end
|
233
|
+
|
234
|
+
# Sets the currently active session on the scope.
|
235
|
+
# @param session [Session, nil]
|
236
|
+
# @return [void]
|
237
|
+
def set_session(session)
|
238
|
+
@session = session
|
239
|
+
end
|
240
|
+
|
241
|
+
# Returns current transaction name.
|
242
|
+
# The "transaction" here does not refer to `Transaction` objects.
|
243
|
+
# @return [String, nil]
|
244
|
+
def transaction_name
|
245
|
+
@transaction_names.last
|
246
|
+
end
|
247
|
+
|
248
|
+
# Returns current transaction source.
|
249
|
+
# The "transaction" here does not refer to `Transaction` objects.
|
250
|
+
# @return [String, nil]
|
251
|
+
def transaction_source
|
252
|
+
@transaction_sources.last
|
253
|
+
end
|
254
|
+
|
255
|
+
# Returns the associated Transaction object.
|
256
|
+
# @return [Transaction, nil]
|
257
|
+
def get_transaction
|
258
|
+
span.transaction if span
|
259
|
+
end
|
260
|
+
|
261
|
+
# Returns the associated Span object.
|
262
|
+
# @return [Span, nil]
|
263
|
+
def get_span
|
264
|
+
span
|
265
|
+
end
|
266
|
+
|
267
|
+
# Sets the scope's fingerprint attribute.
|
268
|
+
# @param fingerprint [Array]
|
269
|
+
# @return [Array]
|
270
|
+
def set_fingerprint(fingerprint)
|
271
|
+
check_argument_type!(fingerprint, Array)
|
272
|
+
|
273
|
+
@fingerprint = fingerprint
|
274
|
+
end
|
275
|
+
|
276
|
+
# Adds a new event processor [Proc] to the scope.
|
277
|
+
# @param block [Proc]
|
278
|
+
# @return [void]
|
279
|
+
def add_event_processor(&block)
|
280
|
+
@event_processors << block
|
281
|
+
end
|
282
|
+
|
283
|
+
# Generate a new propagation context either from the incoming env headers or from scratch.
|
284
|
+
# @param env [Hash, nil]
|
285
|
+
# @return [void]
|
286
|
+
def generate_propagation_context(env = nil)
|
287
|
+
@propagation_context = PropagationContext.new(self, env)
|
288
|
+
end
|
289
|
+
|
290
|
+
protected
|
291
|
+
|
292
|
+
# for duplicating scopes internally
|
293
|
+
attr_writer(*ATTRIBUTES)
|
294
|
+
|
295
|
+
private
|
296
|
+
|
297
|
+
def set_default_value
|
298
|
+
@contexts = { :os => self.class.os_context, :runtime => self.class.runtime_context }
|
299
|
+
@extra = {}
|
300
|
+
@tags = {}
|
301
|
+
@user = {}
|
302
|
+
@level = :error
|
303
|
+
@fingerprint = []
|
304
|
+
@transaction_names = []
|
305
|
+
@transaction_sources = []
|
306
|
+
@event_processors = []
|
307
|
+
@rack_env = {}
|
308
|
+
@span = nil
|
309
|
+
@session = nil
|
310
|
+
generate_propagation_context
|
311
|
+
set_new_breadcrumb_buffer
|
312
|
+
end
|
313
|
+
|
314
|
+
def set_new_breadcrumb_buffer
|
315
|
+
@breadcrumbs = BreadcrumbBuffer.new(@max_breadcrumbs)
|
316
|
+
end
|
317
|
+
|
318
|
+
class << self
|
319
|
+
# @return [Hash]
|
320
|
+
def os_context
|
321
|
+
@os_context ||=
|
322
|
+
begin
|
323
|
+
uname = Etc.uname
|
324
|
+
{
|
325
|
+
name: uname[:sysname] || RbConfig::CONFIG["host_os"],
|
326
|
+
version: uname[:version],
|
327
|
+
build: uname[:release],
|
328
|
+
kernel_version: uname[:version],
|
329
|
+
machine: uname[:machine]
|
330
|
+
}
|
331
|
+
end
|
332
|
+
end
|
333
|
+
|
334
|
+
# @return [Hash]
|
335
|
+
def runtime_context
|
336
|
+
@runtime_context ||= {
|
337
|
+
name: RbConfig::CONFIG["ruby_install_name"],
|
338
|
+
version: RUBY_DESCRIPTION || Sentry.sys_command("ruby -v")
|
339
|
+
}
|
340
|
+
end
|
341
|
+
|
342
|
+
# Returns the global event processors array.
|
343
|
+
# @return [Array<Proc>]
|
344
|
+
def global_event_processors
|
345
|
+
@global_event_processors ||= []
|
346
|
+
end
|
347
|
+
|
348
|
+
# Adds a new global event processor [Proc].
|
349
|
+
# Sometimes we need a global event processor without needing to configure scope.
|
350
|
+
# These run before scope event processors.
|
351
|
+
#
|
352
|
+
# @param block [Proc]
|
353
|
+
# @return [void]
|
354
|
+
def add_global_event_processor(&block)
|
355
|
+
global_event_processors << block
|
356
|
+
end
|
357
|
+
end
|
358
|
+
|
359
|
+
end
|
360
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Sentry
|
4
|
+
class Session
|
5
|
+
attr_reader :started, :status, :aggregation_key
|
6
|
+
|
7
|
+
# TODO-neel add :crashed after adding handled mechanism
|
8
|
+
STATUSES = %i(ok errored exited)
|
9
|
+
AGGREGATE_STATUSES = %i(errored exited)
|
10
|
+
|
11
|
+
def initialize
|
12
|
+
@started = Sentry.utc_now
|
13
|
+
@status = :ok
|
14
|
+
|
15
|
+
# truncate seconds from the timestamp since we only care about
|
16
|
+
# minute level granularity for aggregation
|
17
|
+
@aggregation_key = Time.utc(@started.year, @started.month, @started.day, @started.hour, @started.min)
|
18
|
+
end
|
19
|
+
|
20
|
+
# TODO-neel add :crashed after adding handled mechanism
|
21
|
+
def update_from_exception(_exception = nil)
|
22
|
+
@status = :errored
|
23
|
+
end
|
24
|
+
|
25
|
+
def close
|
26
|
+
@status = :exited if @status == :ok
|
27
|
+
end
|
28
|
+
|
29
|
+
def deep_dup
|
30
|
+
dup
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|