sentry-ruby-core 4.8.0 → 5.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (54) hide show
  1. checksums.yaml +4 -4
  2. data/.yardopts +2 -0
  3. data/Gemfile +3 -0
  4. data/README.md +2 -0
  5. data/lib/sentry/background_worker.rb +33 -3
  6. data/lib/sentry/backtrace.rb +1 -3
  7. data/lib/sentry/breadcrumb/sentry_logger.rb +2 -0
  8. data/lib/sentry/breadcrumb.rb +24 -3
  9. data/lib/sentry/breadcrumb_buffer.rb +16 -0
  10. data/lib/sentry/client.rb +38 -2
  11. data/lib/sentry/configuration.rb +94 -41
  12. data/lib/sentry/core_ext/object/deep_dup.rb +2 -0
  13. data/lib/sentry/core_ext/object/duplicable.rb +1 -0
  14. data/lib/sentry/dsn.rb +2 -0
  15. data/lib/sentry/envelope.rb +45 -0
  16. data/lib/sentry/event.rb +55 -18
  17. data/lib/sentry/exceptions.rb +2 -0
  18. data/lib/sentry/hub.rb +38 -2
  19. data/lib/sentry/integrable.rb +2 -0
  20. data/lib/sentry/interface.rb +3 -10
  21. data/lib/sentry/interfaces/exception.rb +14 -3
  22. data/lib/sentry/interfaces/request.rb +37 -20
  23. data/lib/sentry/interfaces/single_exception.rb +2 -0
  24. data/lib/sentry/interfaces/stacktrace.rb +6 -0
  25. data/lib/sentry/interfaces/stacktrace_builder.rb +39 -10
  26. data/lib/sentry/interfaces/threads.rb +12 -2
  27. data/lib/sentry/linecache.rb +3 -0
  28. data/lib/sentry/net/http.rb +54 -65
  29. data/lib/sentry/rack/capture_exceptions.rb +28 -24
  30. data/lib/sentry/rack.rb +2 -0
  31. data/lib/sentry/rake.rb +16 -6
  32. data/lib/sentry/redis.rb +90 -0
  33. data/lib/sentry/release_detector.rb +3 -0
  34. data/lib/sentry/scope.rb +85 -6
  35. data/lib/sentry/session.rb +35 -0
  36. data/lib/sentry/session_flusher.rb +79 -0
  37. data/lib/sentry/span.rb +84 -8
  38. data/lib/sentry/transaction.rb +48 -14
  39. data/lib/sentry/transaction_event.rb +8 -0
  40. data/lib/sentry/transport/configuration.rb +3 -2
  41. data/lib/sentry/transport/dummy_transport.rb +8 -1
  42. data/lib/sentry/transport/http_transport.rb +55 -42
  43. data/lib/sentry/transport.rb +79 -37
  44. data/lib/sentry/utils/argument_checking_helper.rb +2 -0
  45. data/lib/sentry/utils/custom_inspection.rb +2 -0
  46. data/lib/sentry/utils/exception_cause_chain.rb +2 -0
  47. data/lib/sentry/utils/logging_helper.rb +6 -4
  48. data/lib/sentry/utils/real_ip.rb +2 -0
  49. data/lib/sentry/utils/request_id.rb +2 -0
  50. data/lib/sentry/version.rb +3 -1
  51. data/lib/sentry-ruby.rb +212 -41
  52. data/sentry-ruby-core.gemspec +0 -1
  53. data/sentry-ruby.gemspec +0 -1
  54. metadata +7 -16
@@ -1,9 +1,13 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "net/http"
2
4
 
3
5
  module Sentry
6
+ # @api private
4
7
  module Net
5
8
  module HTTP
6
- OP_NAME = "net.http"
9
+ OP_NAME = "http.client"
10
+ BREADCRUMB_CATEGORY = "net.http"
7
11
 
8
12
  # To explain how the entire thing works, we need to know how the original Net::HTTP#request works
9
13
  # Here's part of its definition. As you can see, it usually calls itself inside a #start block
@@ -20,90 +24,67 @@ module Sentry
20
24
  # end
21
25
  # ```
22
26
  #
23
- # So when the entire flow looks like this:
24
- #
25
- # 1. #request is called.
26
- # - But because the request hasn't started yet, it calls #start (which then calls #do_start)
27
- # - At this moment @sentry_span is still nil, so #set_sentry_trace_header returns early
28
- # 2. #do_start then creates a new Span and assigns it to @sentry_span
29
- # 3. #request is called for the second time.
30
- # - This time @sentry_span should present. So #set_sentry_trace_header will set the sentry-trace header on the request object
31
- # 4. Once the request finished, it
32
- # - Records a breadcrumb if http_logger is set
33
- # - Finishes the Span inside @sentry_span and clears the instance variable
34
- #
27
+ # So we're only instrumenting request when `Net::HTTP` is already started
35
28
  def request(req, body = nil, &block)
36
- set_sentry_trace_header(req)
29
+ return super unless started?
30
+
31
+ sentry_span = start_sentry_span
32
+ set_sentry_trace_header(req, sentry_span)
37
33
 
38
34
  super.tap do |res|
39
35
  record_sentry_breadcrumb(req, res)
40
- record_sentry_span(req, res)
41
- end
42
- end
43
-
44
- def do_start
45
- super.tap do
46
- start_sentry_span
47
- end
48
- end
49
-
50
- def do_finish
51
- super.tap do
52
- finish_sentry_span
36
+ record_sentry_span(req, res, sentry_span)
53
37
  end
54
38
  end
55
39
 
56
40
  private
57
41
 
58
- def set_sentry_trace_header(req)
59
- return unless @sentry_span
42
+ def set_sentry_trace_header(req, sentry_span)
43
+ return unless sentry_span
60
44
 
61
- trace = Sentry.get_current_client.generate_sentry_trace(@sentry_span)
45
+ trace = Sentry.get_current_client.generate_sentry_trace(sentry_span)
62
46
  req[SENTRY_TRACE_HEADER_NAME] = trace if trace
63
47
  end
64
48
 
65
49
  def record_sentry_breadcrumb(req, res)
66
- if Sentry.initialized? && Sentry.configuration.breadcrumbs_logger.include?(:http_logger)
67
- return if from_sentry_sdk?
68
-
69
- request_info = extract_request_info(req)
70
- crumb = Sentry::Breadcrumb.new(
71
- level: :info,
72
- category: OP_NAME,
73
- type: :info,
74
- data: {
75
- method: request_info[:method],
76
- url: request_info[:url],
77
- status: res.code.to_i
78
- }
79
- )
80
- Sentry.add_breadcrumb(crumb)
81
- end
50
+ return unless Sentry.initialized? && Sentry.configuration.breadcrumbs_logger.include?(:http_logger)
51
+ return if from_sentry_sdk?
52
+
53
+ request_info = extract_request_info(req)
54
+
55
+ crumb = Sentry::Breadcrumb.new(
56
+ level: :info,
57
+ category: BREADCRUMB_CATEGORY,
58
+ type: :info,
59
+ data: {
60
+ status: res.code.to_i,
61
+ **request_info
62
+ }
63
+ )
64
+ Sentry.add_breadcrumb(crumb)
82
65
  end
83
66
 
84
- def record_sentry_span(req, res)
85
- if Sentry.initialized? && @sentry_span
86
- request_info = extract_request_info(req)
87
- @sentry_span.set_description("#{request_info[:method]} #{request_info[:url]}")
88
- @sentry_span.set_data(:status, res.code.to_i)
89
- end
67
+ def record_sentry_span(req, res, sentry_span)
68
+ return unless Sentry.initialized? && sentry_span
69
+
70
+ request_info = extract_request_info(req)
71
+ sentry_span.set_description("#{request_info[:method]} #{request_info[:url]}")
72
+ sentry_span.set_data(:status, res.code.to_i)
73
+ finish_sentry_span(sentry_span)
90
74
  end
91
75
 
92
76
  def start_sentry_span
93
- if Sentry.initialized? && transaction = Sentry.get_current_scope.get_transaction
94
- return if from_sentry_sdk?
95
- return if transaction.sampled == false
77
+ return unless Sentry.initialized? && transaction = Sentry.get_current_scope.get_transaction
78
+ return if from_sentry_sdk?
79
+ return if transaction.sampled == false
96
80
 
97
- child_span = transaction.start_child(op: OP_NAME, start_timestamp: Sentry.utc_now.to_f)
98
- @sentry_span = child_span
99
- end
81
+ transaction.start_child(op: OP_NAME, start_timestamp: Sentry.utc_now.to_f)
100
82
  end
101
83
 
102
- def finish_sentry_span
103
- if Sentry.initialized? && @sentry_span
104
- @sentry_span.set_timestamp(Sentry.utc_now.to_f)
105
- @sentry_span = nil
106
- end
84
+ def finish_sentry_span(sentry_span)
85
+ return unless Sentry.initialized? && sentry_span
86
+
87
+ sentry_span.set_timestamp(Sentry.utc_now.to_f)
107
88
  end
108
89
 
109
90
  def from_sentry_sdk?
@@ -112,9 +93,17 @@ module Sentry
112
93
  end
113
94
 
114
95
  def extract_request_info(req)
115
- uri = req.uri
96
+ uri = req.uri || URI.parse("#{use_ssl? ? 'https' : 'http'}://#{address}#{req.path}")
116
97
  url = "#{uri.scheme}://#{uri.host}#{uri.path}" rescue uri.to_s
117
- { method: req.method, url: url }
98
+
99
+ result = { method: req.method, url: url }
100
+
101
+ if Sentry.configuration.send_default_pii
102
+ result[:url] = result[:url] + "?#{uri.query}"
103
+ result[:body] = req.body
104
+ end
105
+
106
+ result
118
107
  end
119
108
  end
120
109
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Sentry
2
4
  module Rack
3
5
  class CaptureExceptions
@@ -12,30 +14,32 @@ module Sentry
12
14
  Sentry.clone_hub_to_current_thread
13
15
 
14
16
  Sentry.with_scope do |scope|
15
- scope.clear_breadcrumbs
16
- scope.set_transaction_name(env["PATH_INFO"]) if env["PATH_INFO"]
17
- scope.set_rack_env(env)
18
-
19
- transaction = start_transaction(env, scope)
20
- scope.set_span(transaction) if transaction
21
-
22
- begin
23
- response = @app.call(env)
24
- rescue Sentry::Error
25
- finish_transaction(transaction, 500)
26
- raise # Don't capture Sentry errors
27
- rescue Exception => e
28
- capture_exception(e)
29
- finish_transaction(transaction, 500)
30
- raise
17
+ Sentry.with_session_tracking do
18
+ scope.clear_breadcrumbs
19
+ scope.set_transaction_name(env["PATH_INFO"]) if env["PATH_INFO"]
20
+ scope.set_rack_env(env)
21
+
22
+ transaction = start_transaction(env, scope)
23
+ scope.set_span(transaction) if transaction
24
+
25
+ begin
26
+ response = @app.call(env)
27
+ rescue Sentry::Error
28
+ finish_transaction(transaction, 500)
29
+ raise # Don't capture Sentry errors
30
+ rescue Exception => e
31
+ capture_exception(e)
32
+ finish_transaction(transaction, 500)
33
+ raise
34
+ end
35
+
36
+ exception = collect_exception(env)
37
+ capture_exception(exception) if exception
38
+
39
+ finish_transaction(transaction, response[0])
40
+
41
+ response
31
42
  end
32
-
33
- exception = collect_exception(env)
34
- capture_exception(exception) if exception
35
-
36
- finish_transaction(transaction, response[0])
37
-
38
- response
39
43
  end
40
44
  end
41
45
 
@@ -57,7 +61,7 @@ module Sentry
57
61
  sentry_trace = env["HTTP_SENTRY_TRACE"]
58
62
  options = { name: scope.transaction_name, op: transaction_op }
59
63
  transaction = Sentry::Transaction.from_sentry_trace(sentry_trace, **options) if sentry_trace
60
- Sentry.start_transaction(transaction: transaction, **options)
64
+ Sentry.start_transaction(transaction: transaction, custom_sampling_context: { env: env }, **options)
61
65
  end
62
66
 
63
67
 
data/lib/sentry/rack.rb CHANGED
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'rack'
2
4
 
3
5
  require 'sentry/rack/capture_exceptions'
data/lib/sentry/rake.rb CHANGED
@@ -1,11 +1,14 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "rake"
2
4
  require "rake/task"
3
5
 
4
6
  module Sentry
5
7
  module Rake
6
8
  module Application
9
+ # @api private
7
10
  def display_error_message(ex)
8
- Sentry.capture_exception(ex, hint: { background: false }) do |scope|
11
+ Sentry.capture_exception(ex) do |scope|
9
12
  task_name = top_level_tasks.join(' ')
10
13
  scope.set_transaction_name(task_name)
11
14
  scope.set_tag("rake_task", task_name)
@@ -16,16 +19,23 @@ module Sentry
16
19
  end
17
20
 
18
21
  module Task
22
+ # @api private
19
23
  def execute(args=nil)
20
24
  return super unless Sentry.initialized? && Sentry.get_current_hub
21
25
 
22
- Sentry.get_current_hub.with_background_worker_disabled do
23
- super
24
- end
26
+ super
25
27
  end
26
28
  end
27
29
  end
28
30
  end
29
31
 
30
- Rake::Application.prepend(Sentry::Rake::Application)
31
- Rake::Task.prepend(Sentry::Rake::Task)
32
+ # @api private
33
+ module Rake
34
+ class Application
35
+ prepend(Sentry::Rake::Application)
36
+ end
37
+
38
+ class Task
39
+ prepend(Sentry::Rake::Task)
40
+ end
41
+ end
@@ -0,0 +1,90 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Sentry
4
+ # @api private
5
+ class Redis
6
+ OP_NAME = "db.redis.command"
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
+ record_span do
17
+ yield.tap do
18
+ record_breadcrumb
19
+ end
20
+ end
21
+ end
22
+
23
+ private
24
+
25
+ attr_reader :commands, :host, :port, :db
26
+
27
+ def record_span
28
+ return yield unless (transaction = Sentry.get_current_scope.get_transaction) && transaction.sampled
29
+
30
+ sentry_span = transaction.start_child(op: OP_NAME, start_timestamp: Sentry.utc_now.to_f)
31
+
32
+ yield.tap do
33
+ sentry_span.set_description(commands_description)
34
+ sentry_span.set_data(:server, server_description)
35
+ sentry_span.set_timestamp(Sentry.utc_now.to_f)
36
+ end
37
+ end
38
+
39
+ def record_breadcrumb
40
+ return unless Sentry.configuration.breadcrumbs_logger.include?(LOGGER_NAME)
41
+
42
+ Sentry.add_breadcrumb(
43
+ Sentry::Breadcrumb.new(
44
+ level: :info,
45
+ category: OP_NAME,
46
+ type: :info,
47
+ data: {
48
+ commands: parsed_commands,
49
+ server: server_description
50
+ }
51
+ )
52
+ )
53
+ end
54
+
55
+ def commands_description
56
+ parsed_commands.map do |statement|
57
+ statement.values.join(" ").strip
58
+ end.join(", ")
59
+ end
60
+
61
+ def parsed_commands
62
+ commands.map do |statement|
63
+ command, key, *arguments = statement
64
+
65
+ { command: command.to_s.upcase, key: key }.tap do |command_set|
66
+ command_set[:arguments] = arguments.join(" ") if Sentry.configuration.send_default_pii
67
+ end
68
+ end
69
+ end
70
+
71
+ def server_description
72
+ "#{host}:#{port}/#{db}"
73
+ end
74
+
75
+ module Client
76
+ def logging(commands, &block)
77
+ Sentry::Redis.new(commands, host, port, db).instrument do
78
+ super
79
+ end
80
+ end
81
+ end
82
+ end
83
+ end
84
+
85
+ if defined?(::Redis::Client)
86
+ Sentry.register_patch do
87
+ patch = Sentry::Redis::Client
88
+ Redis::Client.prepend(patch) unless Redis::Client.ancestors.include?(patch)
89
+ end
90
+ end
@@ -1,4 +1,7 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Sentry
4
+ # @api private
2
5
  class ReleaseDetector
3
6
  class << self
4
7
  def detect_release(project_root:, running_on_heroku:)
data/lib/sentry/scope.rb CHANGED
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "sentry/breadcrumb_buffer"
2
4
  require "etc"
3
5
 
@@ -5,19 +7,26 @@ module Sentry
5
7
  class Scope
6
8
  include ArgumentCheckingHelper
7
9
 
8
- ATTRIBUTES = [:transaction_names, :contexts, :extra, :tags, :user, :level, :breadcrumbs, :fingerprint, :event_processors, :rack_env, :span]
10
+ ATTRIBUTES = [:transaction_names, :contexts, :extra, :tags, :user, :level, :breadcrumbs, :fingerprint, :event_processors, :rack_env, :span, :session]
9
11
 
10
12
  attr_reader(*ATTRIBUTES)
11
13
 
14
+ # @param max_breadcrumbs [Integer] the maximum number of breadcrumbs to be stored in the scope.
12
15
  def initialize(max_breadcrumbs: nil)
13
16
  @max_breadcrumbs = max_breadcrumbs
14
17
  set_default_value
15
18
  end
16
19
 
20
+ # Resets the scope's attributes to defaults.
21
+ # @return [void]
17
22
  def clear
18
23
  set_default_value
19
24
  end
20
25
 
26
+ # Applies stored attributes and event processors to the given event.
27
+ # @param event [Event]
28
+ # @param hint [Hash] the hint data that'll be passed to event processors.
29
+ # @return [Event]
21
30
  def apply_to_event(event, hint = nil)
22
31
  event.tags = tags.merge(event.tags)
23
32
  event.user = user.merge(event.user)
@@ -43,14 +52,20 @@ module Sentry
43
52
  event
44
53
  end
45
54
 
55
+ # Adds the breadcrumb to the scope's breadcrumbs buffer.
56
+ # @param breadcrumb [Breadcrumb]
57
+ # @return [void]
46
58
  def add_breadcrumb(breadcrumb)
47
59
  breadcrumbs.record(breadcrumb)
48
60
  end
49
61
 
62
+ # Clears the scope's breadcrumbs buffer
63
+ # @return [void]
50
64
  def clear_breadcrumbs
51
65
  set_new_breadcrumb_buffer
52
66
  end
53
67
 
68
+ # @return [Scope]
54
69
  def dup
55
70
  copy = super
56
71
  copy.breadcrumbs = breadcrumbs.dup
@@ -61,9 +76,13 @@ module Sentry
61
76
  copy.transaction_names = transaction_names.deep_dup
62
77
  copy.fingerprint = fingerprint.deep_dup
63
78
  copy.span = span.deep_dup
79
+ copy.session = session.deep_dup
64
80
  copy
65
81
  end
66
82
 
83
+ # Updates the scope's data from a given scope.
84
+ # @param scope [Scope]
85
+ # @return [void]
67
86
  def update_from_scope(scope)
68
87
  self.breadcrumbs = scope.breadcrumbs
69
88
  self.contexts = scope.contexts
@@ -75,6 +94,14 @@ module Sentry
75
94
  self.span = scope.span
76
95
  end
77
96
 
97
+ # Updates the scope's data from the given options.
98
+ # @param contexts [Hash]
99
+ # @param extras [Hash]
100
+ # @param tags [Hash]
101
+ # @param user [Hash]
102
+ # @param level [String, Symbol]
103
+ # @param fingerprint [Array]
104
+ # @return [void]
78
105
  def update_from_options(
79
106
  contexts: nil,
80
107
  extra: nil,
@@ -91,75 +118,125 @@ module Sentry
91
118
  self.fingerprint = fingerprint if fingerprint
92
119
  end
93
120
 
121
+ # Sets the scope's rack_env attribute.
122
+ # @param env [Hash]
123
+ # @return [Hash]
94
124
  def set_rack_env(env)
95
125
  env = env || {}
96
126
  @rack_env = env
97
127
  end
98
128
 
129
+ # Sets the scope's span attribute.
130
+ # @param span [Span]
131
+ # @return [Span]
99
132
  def set_span(span)
100
133
  check_argument_type!(span, Span)
101
134
  @span = span
102
135
  end
103
136
 
137
+ # @!macro set_user
104
138
  def set_user(user_hash)
105
139
  check_argument_type!(user_hash, Hash)
106
140
  @user = user_hash
107
141
  end
108
142
 
143
+ # @!macro set_extras
109
144
  def set_extras(extras_hash)
110
145
  check_argument_type!(extras_hash, Hash)
111
146
  @extra.merge!(extras_hash)
112
147
  end
113
148
 
149
+ # Adds a new key-value pair to current extras.
150
+ # @param key [String, Symbol]
151
+ # @param value [Object]
152
+ # @return [Hash]
114
153
  def set_extra(key, value)
115
- @extra.merge!(key => value)
154
+ set_extras(key => value)
116
155
  end
117
156
 
157
+ # @!macro set_tags
118
158
  def set_tags(tags_hash)
119
159
  check_argument_type!(tags_hash, Hash)
120
160
  @tags.merge!(tags_hash)
121
161
  end
122
162
 
163
+ # Adds a new key-value pair to current tags.
164
+ # @param key [String, Symbol]
165
+ # @param value [Object]
166
+ # @return [Hash]
123
167
  def set_tag(key, value)
124
- @tags.merge!(key => value)
168
+ set_tags(key => value)
125
169
  end
126
170
 
171
+ # Updates the scope's contexts attribute by merging with the old value.
172
+ # @param contexts [Hash]
173
+ # @return [Hash]
127
174
  def set_contexts(contexts_hash)
128
175
  check_argument_type!(contexts_hash, Hash)
129
- @contexts.merge!(contexts_hash)
176
+ @contexts.merge!(contexts_hash) do |key, old, new|
177
+ old.merge(new)
178
+ end
130
179
  end
131
180
 
181
+ # @!macro set_context
132
182
  def set_context(key, value)
133
183
  check_argument_type!(value, Hash)
134
- @contexts.merge!(key => value)
184
+ set_contexts(key => value)
135
185
  end
136
186
 
187
+ # Sets the scope's level attribute.
188
+ # @param level [String, Symbol]
189
+ # @return [void]
137
190
  def set_level(level)
138
191
  @level = level
139
192
  end
140
193
 
194
+ # Appends a new transaction name to the scope.
195
+ # The "transaction" here does not refer to `Transaction` objects.
196
+ # @param transaction_name [String]
197
+ # @return [void]
141
198
  def set_transaction_name(transaction_name)
142
199
  @transaction_names << transaction_name
143
200
  end
144
201
 
202
+ # Sets the currently active session on the scope.
203
+ # @param session [Session, nil]
204
+ # @return [void]
205
+ def set_session(session)
206
+ @session = session
207
+ end
208
+
209
+ # Returns current transaction name.
210
+ # The "transaction" here does not refer to `Transaction` objects.
211
+ # @return [String, nil]
145
212
  def transaction_name
146
213
  @transaction_names.last
147
214
  end
148
215
 
216
+ # Returns the associated Transaction object.
217
+ # @return [Transaction, nil]
149
218
  def get_transaction
150
219
  span.transaction if span
151
220
  end
152
221
 
222
+ # Returns the associated Span object.
223
+ # @return [Span, nil]
153
224
  def get_span
154
225
  span
155
226
  end
156
227
 
228
+ # Sets the scope's fingerprint attribute.
229
+ # @param fingerprint [Array]
230
+ # @return [Array]
157
231
  def set_fingerprint(fingerprint)
158
232
  check_argument_type!(fingerprint, Array)
159
233
 
160
234
  @fingerprint = fingerprint
161
235
  end
162
236
 
237
+ # Adds a new event processor [Proc] to the scope.
238
+ # @param block [Proc]
239
+ # @return [void]
163
240
  def add_event_processor(&block)
164
241
  @event_processors << block
165
242
  end
@@ -182,6 +259,7 @@ module Sentry
182
259
  @event_processors = []
183
260
  @rack_env = {}
184
261
  @span = nil
262
+ @session = nil
185
263
  set_new_breadcrumb_buffer
186
264
  end
187
265
 
@@ -189,8 +267,8 @@ module Sentry
189
267
  @breadcrumbs = BreadcrumbBuffer.new(@max_breadcrumbs)
190
268
  end
191
269
 
192
-
193
270
  class << self
271
+ # @return [Hash]
194
272
  def os_context
195
273
  @os_context ||=
196
274
  begin
@@ -204,6 +282,7 @@ module Sentry
204
282
  end
205
283
  end
206
284
 
285
+ # @return [Hash]
207
286
  def runtime_context
208
287
  @runtime_context ||= {
209
288
  name: RbConfig::CONFIG["ruby_install_name"],
@@ -0,0 +1,35 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Sentry
4
+ class Session
5
+ attr_reader :started, :status
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
+ end
15
+
16
+ # TODO-neel add :crashed after adding handled mechanism
17
+ def update_from_exception(_exception = nil)
18
+ @status = :errored
19
+ end
20
+
21
+ def close
22
+ @status = :exited if @status == :ok
23
+ end
24
+
25
+ # truncate seconds from the timestamp since we only care about
26
+ # minute level granularity for aggregation
27
+ def aggregation_key
28
+ Time.utc(started.year, started.month, started.day, started.hour, started.min)
29
+ end
30
+
31
+ def deep_dup
32
+ dup
33
+ end
34
+ end
35
+ end