sentry-ruby-core 5.22.4 → 5.24.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 85e7e5a5ad9a1f396ef7a106926f203df35a53b7b317f41a3b345dca0c98e9ef
4
- data.tar.gz: 7963e284f23ac79656f94eccbed48840be1746927bcae3ae18a66c60aea923c5
3
+ metadata.gz: ea57af962e29f8ae1d85f7a1cdc2106f1865e8afcdce4a2fd24b653c67ac10f5
4
+ data.tar.gz: c086418c80e60b60d1e099701fdb6b9ae1a9136bd464213dd9ff9cc17c582b75
5
5
  SHA512:
6
- metadata.gz: bcc6489dc377e0880ab1d668b01902ad03505a0eebc8331a0e5d3ce03bc86068b6ed684e84db9810ce677baefe339597b90317814f21babd423af8b8b52ab1a7
7
- data.tar.gz: 1711020af1887f806b3cc01a9e1d2540b616e5f3e5d77da85cb252e85ae90af9062de51eb9e552a434595345d0978a10b6002cd2944e0baaf4414275e58fd399
6
+ metadata.gz: 5b9d195dc52ed15d1da607ecdc532f0bf87036a3e3670753d4694919b402d38dd9200319406714d91575186287cd40abfa857408a432867cf734f6c32b6c3749
7
+ data.tar.gz: 86ad04ab139eb703950d206a1a2a029f42da4fdf43896a342fa961ec8f7cd607de27270b49ec4ba7a635e2d34018387990e1a56d26287af39bf2708aee004a23
data/Gemfile CHANGED
@@ -3,6 +3,8 @@
3
3
  source "https://rubygems.org"
4
4
  git_source(:github) { |name| "https://github.com/#{name}.git" }
5
5
 
6
+ eval_gemfile "../Gemfile"
7
+
6
8
  gem "sentry-ruby", path: "./"
7
9
 
8
10
  rack_version = ENV["RACK_VERSION"]
@@ -27,9 +29,8 @@ gem "benchmark_driver"
27
29
  gem "benchmark-ipsa"
28
30
  gem "benchmark-memory"
29
31
 
30
- gem "yard", github: "lsegal/yard"
32
+ gem "yard"
31
33
  gem "webrick"
32
34
  gem "faraday"
33
35
  gem "excon"
34
-
35
- eval_gemfile File.expand_path("../Gemfile", __dir__)
36
+ gem "webmock"
@@ -9,8 +9,7 @@ module Sentry
9
9
  include LoggingHelper
10
10
 
11
11
  attr_reader :max_queue, :number_of_threads
12
- # @deprecated Use Sentry.logger to retrieve the current logger instead.
13
- attr_reader :logger
12
+
14
13
  attr_accessor :shutdown_timeout
15
14
 
16
15
  DEFAULT_MAX_QUEUE = 30
@@ -19,7 +18,7 @@ module Sentry
19
18
  @shutdown_timeout = 1
20
19
  @number_of_threads = configuration.background_worker_threads
21
20
  @max_queue = configuration.background_worker_max_queue
22
- @logger = configuration.logger
21
+ @sdk_logger = configuration.sdk_logger
23
22
  @debug = configuration.debug
24
23
  @shutdown_callback = nil
25
24
 
@@ -6,7 +6,7 @@ module Sentry
6
6
  MAX_DOWNSAMPLE_FACTOR = 10
7
7
 
8
8
  def initialize(configuration, client, interval: DEFAULT_INTERVAL)
9
- super(configuration.logger, interval)
9
+ super(configuration.sdk_logger, interval)
10
10
  @client = client
11
11
 
12
12
  @healthy = true
@@ -16,7 +16,7 @@ module Sentry
16
16
  /x
17
17
 
18
18
  # org.jruby.runtime.callsite.CachingCallSite.call(CachingCallSite.java:170)
19
- JAVA_INPUT_FORMAT = /^(.+)\.([^\.]+)\(([^\:]+)\:(\d+)\)$/
19
+ JAVA_INPUT_FORMAT = /^([\w$.]+)\.([\w$]+)\(([\w$.]+):(\d+)\)$/
20
20
 
21
21
  # The file portion of the line (such as app/models/user.rb)
22
22
  attr_reader :file
@@ -2,6 +2,7 @@
2
2
 
3
3
  module Sentry
4
4
  class Breadcrumb
5
+ MAX_NESTING = 10
5
6
  DATA_SERIALIZATION_ERROR_MESSAGE = "[data were removed due to serialization issues]"
6
7
 
7
8
  # @return [String, nil]
@@ -47,7 +48,7 @@ module Sentry
47
48
  # @param message [String]
48
49
  # @return [void]
49
50
  def message=(message)
50
- @message = (message || "").byteslice(0..Event::MAX_MESSAGE_SIZE_IN_BYTES)
51
+ @message = message && Utils::EncodingHelper.valid_utf_8?(message) ? message.byteslice(0..Event::MAX_MESSAGE_SIZE_IN_BYTES) : ""
51
52
  end
52
53
 
53
54
  # @param level [String]
@@ -60,16 +61,16 @@ module Sentry
60
61
 
61
62
  def serialized_data
62
63
  begin
63
- ::JSON.parse(::JSON.generate(@data))
64
+ ::JSON.parse(::JSON.generate(@data, max_nesting: MAX_NESTING))
64
65
  rescue Exception => e
65
- Sentry.logger.debug(LOGGER_PROGNAME) do
66
+ Sentry.sdk_logger.debug(LOGGER_PROGNAME) do
66
67
  <<~MSG
67
68
  can't serialize breadcrumb data because of error: #{e}
68
69
  data: #{@data}
69
70
  MSG
70
71
  end
71
72
 
72
- DATA_SERIALIZATION_ERROR_MESSAGE
73
+ { error: DATA_SERIALIZATION_ERROR_MESSAGE }
73
74
  end
74
75
  end
75
76
  end
@@ -2,6 +2,7 @@
2
2
 
3
3
  require "securerandom"
4
4
  require "sentry/cron/monitor_config"
5
+ require "sentry/utils/uuid"
5
6
 
6
7
  module Sentry
7
8
  class CheckInEvent < Event
@@ -43,7 +44,7 @@ module Sentry
43
44
  self.status = status
44
45
  self.duration = duration
45
46
  self.monitor_config = monitor_config
46
- self.check_in_id = check_in_id || SecureRandom.uuid.delete("-")
47
+ self.check_in_id = check_in_id || Utils.uuid
47
48
  end
48
49
 
49
50
  # @return [Hash]
data/lib/sentry/client.rb CHANGED
@@ -1,6 +1,8 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require "sentry/transport"
4
+ require "sentry/log_event"
5
+ require "sentry/log_event_buffer"
4
6
 
5
7
  module Sentry
6
8
  class Client
@@ -14,16 +16,16 @@ module Sentry
14
16
  # @return [SpotlightTransport, nil]
15
17
  attr_reader :spotlight_transport
16
18
 
19
+ # @!visibility private
20
+ attr_reader :log_event_buffer
21
+
17
22
  # @!macro configuration
18
23
  attr_reader :configuration
19
24
 
20
- # @deprecated Use Sentry.logger to retrieve the current logger instead.
21
- attr_reader :logger
22
-
23
25
  # @param configuration [Configuration]
24
26
  def initialize(configuration)
25
27
  @configuration = configuration
26
- @logger = configuration.logger
28
+ @sdk_logger = configuration.sdk_logger
27
29
 
28
30
  if transport_class = configuration.transport.transport_class
29
31
  @transport = transport_class.new(configuration)
@@ -38,6 +40,8 @@ module Sentry
38
40
  end
39
41
 
40
42
  @spotlight_transport = SpotlightTransport.new(configuration) if configuration.spotlight
43
+
44
+ @log_event_buffer = LogEventBuffer.new(configuration, self).start
41
45
  end
42
46
 
43
47
  # Applies the given scope's data to the event and sends it to Sentry.
@@ -88,6 +92,15 @@ module Sentry
88
92
  nil
89
93
  end
90
94
 
95
+ # Buffer a log event to be sent later with other logs in a single envelope
96
+ # @param event [LogEvent] the log event to be buffered
97
+ # @return [LogEvent]
98
+ def buffer_log_event(event, scope)
99
+ return unless event.is_a?(LogEvent)
100
+ @log_event_buffer.add_event(scope.apply_to_event(event))
101
+ event
102
+ end
103
+
91
104
  # Capture an envelope directly.
92
105
  # @param envelope [Envelope] the envelope to be captured.
93
106
  # @return [void]
@@ -100,6 +113,7 @@ module Sentry
100
113
  def flush
101
114
  transport.flush if configuration.sending_to_dsn_allowed?
102
115
  spotlight_transport.flush if spotlight_transport
116
+ @log_event_buffer.flush
103
117
  end
104
118
 
105
119
  # Initializes an Event object with the given exception. Returns `nil` if the exception's class is excluded from reporting.
@@ -167,6 +181,27 @@ module Sentry
167
181
  )
168
182
  end
169
183
 
184
+ # Initializes a LogEvent object with the given message and options
185
+ #
186
+ # @param message [String] the log message
187
+ # @param level [Symbol] the log level (:trace, :debug, :info, :warn, :error, :fatal)
188
+ # @param options [Hash] additional options
189
+ # @option options [Array] :parameters Array of values to replace template tokens in the message
190
+ #
191
+ # @return [LogEvent] the created log event
192
+ def event_from_log(message, level:, **options)
193
+ return unless configuration.sending_allowed?
194
+
195
+ attributes = options.reject { |k, _| k == :level || k == :severity }
196
+
197
+ LogEvent.new(
198
+ level: level,
199
+ body: message,
200
+ timestamp: Time.now.to_f,
201
+ attributes: attributes
202
+ )
203
+ end
204
+
170
205
  # Initializes an Event object with the given Transaction object.
171
206
  # @param transaction [Transaction] the transaction to be recorded.
172
207
  # @return [TransactionEvent]
@@ -12,6 +12,8 @@ require "sentry/cron/configuration"
12
12
  require "sentry/metrics/configuration"
13
13
  require "sentry/linecache"
14
14
  require "sentry/interfaces/stacktrace_builder"
15
+ require "sentry/logger"
16
+ require "sentry/log_event_buffer"
15
17
 
16
18
  module Sentry
17
19
  class Configuration
@@ -183,7 +185,19 @@ module Sentry
183
185
  # Logger used by Sentry. In Rails, this is the Rails logger, otherwise
184
186
  # Sentry provides its own Sentry::Logger.
185
187
  # @return [Logger]
186
- attr_accessor :logger
188
+ attr_accessor :sdk_logger
189
+
190
+ # @deprecated Use {#sdk_logger=} instead.
191
+ def logger=(logger)
192
+ warn "[sentry] `config.logger=` is deprecated. Please use `config.sdk_logger=` instead."
193
+ self.sdk_logger = logger
194
+ end
195
+
196
+ # @deprecated Use {#sdk_logger} instead.
197
+ def logger
198
+ warn "[sentry] `config.logger` is deprecated. Please use `config.sdk_logger` instead."
199
+ self.sdk_logger
200
+ end
187
201
 
188
202
  # Project directory root for in_app detection. Could be Rails root, etc.
189
203
  # Set automatically for Rails.
@@ -262,8 +276,13 @@ module Sentry
262
276
  # @return [Proc]
263
277
  attr_accessor :traces_sampler
264
278
 
279
+ # Enable Structured Logging
280
+ # @return [Boolean]
281
+ attr_accessor :enable_logs
282
+
265
283
  # Easier way to use performance tracing
266
284
  # If set to true, will set traces_sample_rate to 1.0
285
+ # @deprecated It will be removed in the next major release.
267
286
  # @return [Boolean, nil]
268
287
  attr_reader :enable_tracing
269
288
 
@@ -306,6 +325,10 @@ module Sentry
306
325
  # @return [Array<Symbol>]
307
326
  attr_accessor :enabled_patches
308
327
 
328
+ # Maximum number of log events to buffer before sending
329
+ # @return [Integer]
330
+ attr_accessor :max_log_events
331
+
309
332
  # these are not config options
310
333
  # @!visibility private
311
334
  attr_reader :errors, :gem_specs
@@ -418,7 +441,7 @@ module Sentry
418
441
  self.excluded_exceptions = IGNORE_DEFAULT + PUMA_IGNORE_DEFAULT
419
442
  self.inspect_exception_causes_for_exclusion = true
420
443
  self.linecache = ::Sentry::LineCache.new
421
- self.logger = ::Sentry::Logger.new(STDOUT)
444
+ self.sdk_logger = ::Sentry::Logger.new(STDOUT)
422
445
  self.project_root = Dir.pwd
423
446
  self.propagate_traces = true
424
447
 
@@ -445,6 +468,7 @@ module Sentry
445
468
  self.rack_env_whitelist = RACK_ENV_WHITELIST_DEFAULT
446
469
  self.traces_sampler = nil
447
470
  self.enable_tracing = nil
471
+ self.enable_logs = false
448
472
 
449
473
  self.profiler_class = Sentry::Profiler
450
474
 
@@ -454,6 +478,8 @@ module Sentry
454
478
  @gem_specs = Hash[Gem::Specification.map { |spec| [spec.name, spec.version.to_s] }] if Gem::Specification.respond_to?(:map)
455
479
 
456
480
  run_post_initialization_callbacks
481
+
482
+ self.max_log_events = LogEventBuffer::DEFAULT_MAX_EVENTS
457
483
  end
458
484
 
459
485
  def validate
@@ -542,6 +568,12 @@ module Sentry
542
568
  end
543
569
 
544
570
  def enable_tracing=(enable_tracing)
571
+ unless enable_tracing.nil?
572
+ log_warn <<~MSG
573
+ `enable_tracing` is now deprecated in favor of `traces_sample_rate = 1.0`.
574
+ MSG
575
+ end
576
+
545
577
  @enable_tracing = enable_tracing
546
578
  @traces_sample_rate ||= 1.0 if enable_tracing
547
579
  end
@@ -15,7 +15,7 @@ module Sentry
15
15
  # rate limits and client reports use the data_category rather than envelope item type
16
16
  def self.data_category(type)
17
17
  case type
18
- when "session", "attachment", "transaction", "profile", "span" then type
18
+ when "session", "attachment", "transaction", "profile", "span", "log" then type
19
19
  when "sessions" then "session"
20
20
  when "check_in" then "monitor"
21
21
  when "statsd", "metric_meta" then "metric_bucket"
data/lib/sentry/event.rb CHANGED
@@ -7,6 +7,7 @@ require "sentry/backtrace"
7
7
  require "sentry/utils/real_ip"
8
8
  require "sentry/utils/request_id"
9
9
  require "sentry/utils/custom_inspection"
10
+ require "sentry/utils/uuid"
10
11
 
11
12
  module Sentry
12
13
  # This is an abstract class that defines the shared attributes of an event.
@@ -50,7 +51,7 @@ module Sentry
50
51
  # @param message [String, nil]
51
52
  def initialize(configuration:, integration_meta: nil, message: nil)
52
53
  # Set some simple default values
53
- @event_id = SecureRandom.uuid.delete("-")
54
+ @event_id = Utils.uuid
54
55
  @timestamp = Sentry.utc_now.iso8601
55
56
  @platform = :ruby
56
57
  @type = self.class::TYPE
data/lib/sentry/hub.rb CHANGED
@@ -8,12 +8,42 @@ module Sentry
8
8
  class Hub
9
9
  include ArgumentCheckingHelper
10
10
 
11
+ MUTEX = Mutex.new
12
+
11
13
  attr_reader :last_event_id
12
14
 
15
+ attr_reader :current_profiler
16
+
13
17
  def initialize(client, scope)
14
18
  first_layer = Layer.new(client, scope)
15
19
  @stack = [first_layer]
16
20
  @last_event_id = nil
21
+ @current_profiler = {}
22
+ end
23
+
24
+ # This is an internal private method
25
+ # @api private
26
+ def start_profiler!(transaction)
27
+ MUTEX.synchronize do
28
+ transaction.start_profiler!
29
+ @current_profiler[transaction.__id__] = transaction.profiler
30
+ end
31
+ end
32
+
33
+ # This is an internal private method
34
+ # @api private
35
+ def stop_profiler!(transaction)
36
+ MUTEX.synchronize do
37
+ @current_profiler.delete(transaction.__id__)&.stop
38
+ end
39
+ end
40
+
41
+ # This is an internal private method
42
+ # @api private
43
+ def profiler_running?
44
+ MUTEX.synchronize do
45
+ !@current_profiler.empty?
46
+ end
17
47
  end
18
48
 
19
49
  def new_from_top
@@ -96,7 +126,7 @@ module Sentry
96
126
  sampling_context.merge!(custom_sampling_context)
97
127
  transaction.set_initial_sample_decision(sampling_context: sampling_context)
98
128
 
99
- transaction.start_profiler!
129
+ start_profiler!(transaction)
100
130
 
101
131
  transaction
102
132
  end
@@ -186,6 +216,16 @@ module Sentry
186
216
  event.check_in_id
187
217
  end
188
218
 
219
+ def capture_log_event(message, **options)
220
+ return unless current_client
221
+
222
+ event = current_client.event_from_log(message, **options)
223
+
224
+ return unless event
225
+
226
+ current_client.buffer_log_event(event, current_scope)
227
+ end
228
+
189
229
  def capture_event(event, **options, &block)
190
230
  check_argument_type!(event, Sentry::Event)
191
231
 
@@ -99,7 +99,7 @@ module Sentry
99
99
  # Rails adds objects to the Rack env that can sometimes raise exceptions
100
100
  # when `to_s` is called.
101
101
  # See: https://github.com/rails/rails/blob/master/actionpack/lib/action_dispatch/middleware/remote_ip.rb#L134
102
- Sentry.logger.warn(LOGGER_PROGNAME) { "Error raised while formatting headers: #{e.message}" }
102
+ Sentry.sdk_logger.warn(LOGGER_PROGNAME) { "Error raised while formatting headers: #{e.message}" }
103
103
  next
104
104
  end
105
105
  end
@@ -29,9 +29,9 @@ module Sentry
29
29
 
30
30
  def getlines(path)
31
31
  @cache[path] ||= begin
32
- IO.readlines(path)
33
- rescue
34
- nil
32
+ File.open(path, "r", &:readlines)
33
+ rescue
34
+ nil
35
35
  end
36
36
  end
37
37
 
@@ -0,0 +1,159 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Sentry
4
+ # Event type that represents a log entry with its attributes
5
+ #
6
+ # @see https://develop.sentry.dev/sdk/telemetry/logs/#log-envelope-item-payload
7
+ class LogEvent < Event
8
+ TYPE = "log"
9
+
10
+ DEFAULT_PARAMETERS = [].freeze
11
+ DEFAULT_ATTRIBUTES = {}.freeze
12
+ DEFAULT_CONTEXT = {}.freeze
13
+
14
+ SERIALIZEABLE_ATTRIBUTES = %i[
15
+ level
16
+ body
17
+ timestamp
18
+ trace_id
19
+ attributes
20
+ ]
21
+
22
+ SENTRY_ATTRIBUTES = {
23
+ "sentry.trace.parent_span_id" => :parent_span_id,
24
+ "sentry.environment" => :environment,
25
+ "sentry.release" => :release,
26
+ "sentry.address" => :server_name,
27
+ "sentry.sdk.name" => :sdk_name,
28
+ "sentry.sdk.version" => :sdk_version,
29
+ "sentry.message.template" => :template
30
+ }
31
+
32
+ LEVELS = %i[trace debug info warn error fatal].freeze
33
+
34
+ attr_accessor :level, :body, :template, :attributes
35
+
36
+ def initialize(configuration: Sentry.configuration, **options)
37
+ super(configuration: configuration)
38
+
39
+ @type = TYPE
40
+ @level = options.fetch(:level)
41
+ @body = options[:body]
42
+ @template = @body if is_template?
43
+ @attributes = options[:attributes] || DEFAULT_ATTRIBUTES
44
+ @contexts = DEFAULT_CONTEXT
45
+ end
46
+
47
+ def to_hash
48
+ SERIALIZEABLE_ATTRIBUTES.each_with_object({}) do |name, memo|
49
+ memo[name] = serialize(name)
50
+ end
51
+ end
52
+
53
+ private
54
+
55
+ def serialize(name)
56
+ serializer = :"serialize_#{name}"
57
+
58
+ if respond_to?(serializer, true)
59
+ __send__(serializer)
60
+ else
61
+ public_send(name)
62
+ end
63
+ end
64
+
65
+ def serialize_level
66
+ level.to_s
67
+ end
68
+
69
+ def serialize_sdk_name
70
+ Sentry.sdk_meta["name"]
71
+ end
72
+
73
+ def serialize_sdk_version
74
+ Sentry.sdk_meta["version"]
75
+ end
76
+
77
+ def serialize_timestamp
78
+ Time.parse(timestamp).to_f
79
+ end
80
+
81
+ def serialize_trace_id
82
+ contexts.dig(:trace, :trace_id)
83
+ end
84
+
85
+ def serialize_parent_span_id
86
+ contexts.dig(:trace, :parent_span_id)
87
+ end
88
+
89
+ def serialize_body
90
+ if parameters.empty?
91
+ body
92
+ elsif parameters.is_a?(Hash)
93
+ body % parameters
94
+ else
95
+ sprintf(body, *parameters)
96
+ end
97
+ end
98
+
99
+ def serialize_attributes
100
+ hash = attributes.each_with_object({}) do |(key, value), memo|
101
+ memo[key] = attribute_hash(value)
102
+ end
103
+
104
+ SENTRY_ATTRIBUTES.each do |key, name|
105
+ if (value = serialize(name))
106
+ hash[key] = attribute_hash(value)
107
+ end
108
+ end
109
+
110
+ hash
111
+ end
112
+
113
+ def attribute_hash(value)
114
+ { value: value, type: value_type(value) }
115
+ end
116
+
117
+ def value_type(value)
118
+ case value
119
+ when Integer
120
+ "integer"
121
+ when TrueClass, FalseClass
122
+ "boolean"
123
+ when Float
124
+ "double"
125
+ else
126
+ "string"
127
+ end
128
+ end
129
+
130
+ def parameters
131
+ @parameters ||= begin
132
+ return DEFAULT_PARAMETERS unless template
133
+
134
+ parameters = template_tokens.empty? ?
135
+ attributes.fetch(:parameters, DEFAULT_PARAMETERS) : attributes.slice(*template_tokens)
136
+
137
+ if parameters.is_a?(Hash)
138
+ parameters.each do |key, value|
139
+ attributes["sentry.message.parameter.#{key}"] = value
140
+ end
141
+ else
142
+ parameters.each_with_index do |param, index|
143
+ attributes["sentry.message.parameter.#{index}"] = param
144
+ end
145
+ end
146
+ end
147
+ end
148
+
149
+ TOKEN_REGEXP = /%\{(\w+)\}/
150
+
151
+ def template_tokens
152
+ @template_tokens ||= body.scan(TOKEN_REGEXP).flatten.map(&:to_sym)
153
+ end
154
+
155
+ def is_template?
156
+ body.include?("%s") || TOKEN_REGEXP.match?(body)
157
+ end
158
+ end
159
+ end
@@ -0,0 +1,97 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "sentry/threaded_periodic_worker"
4
+
5
+ module Sentry
6
+ # LogEventBuffer buffers log events and sends them to Sentry in a single envelope.
7
+ #
8
+ # This is used internally by the `Sentry::Client`.
9
+ #
10
+ # @!visibility private
11
+ class LogEventBuffer < ThreadedPeriodicWorker
12
+ FLUSH_INTERVAL = 5 # seconds
13
+ DEFAULT_MAX_EVENTS = 100
14
+
15
+ # @!visibility private
16
+ attr_reader :pending_events
17
+
18
+ def initialize(configuration, client)
19
+ super(configuration.sdk_logger, FLUSH_INTERVAL)
20
+
21
+ @client = client
22
+ @pending_events = []
23
+ @max_events = configuration.max_log_events || DEFAULT_MAX_EVENTS
24
+ @dsn = configuration.dsn
25
+ @sdk = Sentry.sdk_meta
26
+ @mutex = Mutex.new
27
+
28
+ log_debug("[Logging] Initialized buffer with max_events=#{@max_events}, flush_interval=#{FLUSH_INTERVAL}s")
29
+ end
30
+
31
+ def start
32
+ ensure_thread
33
+ self
34
+ end
35
+
36
+ def flush
37
+ @mutex.synchronize do
38
+ return if empty?
39
+
40
+ log_debug("[LogEventBuffer] flushing #{size} log events")
41
+
42
+ send_events
43
+ end
44
+
45
+ log_debug("[LogEventBuffer] flushed #{size} log events")
46
+
47
+ self
48
+ end
49
+ alias_method :run, :flush
50
+
51
+ def add_event(event)
52
+ raise ArgumentError, "expected a LogEvent, got #{event.class}" unless event.is_a?(LogEvent)
53
+
54
+ @mutex.synchronize do
55
+ @pending_events << event
56
+ send_events if size >= @max_events
57
+ end
58
+
59
+ self
60
+ end
61
+
62
+ def empty?
63
+ @pending_events.empty?
64
+ end
65
+
66
+ def size
67
+ @pending_events.size
68
+ end
69
+
70
+ private
71
+
72
+ def send_events
73
+ @client.send_envelope(to_envelope)
74
+ @pending_events.clear
75
+ end
76
+
77
+ def to_envelope
78
+ envelope = Envelope.new(
79
+ event_id: SecureRandom.uuid.delete("-"),
80
+ sent_at: Sentry.utc_now.iso8601,
81
+ dsn: @dsn,
82
+ sdk: @sdk
83
+ )
84
+
85
+ envelope.add_item(
86
+ {
87
+ type: "log",
88
+ item_count: size,
89
+ content_type: "application/vnd.sentry.items.log+json"
90
+ },
91
+ { items: @pending_events.map(&:to_hash) }
92
+ )
93
+
94
+ envelope
95
+ end
96
+ end
97
+ end
@@ -34,7 +34,7 @@ module Sentry
34
34
  attr_reader :client, :thread, :buckets, :flush_shift, :code_locations
35
35
 
36
36
  def initialize(configuration, client)
37
- super(configuration.logger, FLUSH_INTERVAL)
37
+ super(configuration.sdk_logger, FLUSH_INTERVAL)
38
38
  @client = client
39
39
  @before_emit = configuration.metrics.before_emit
40
40
  @enable_code_locations = configuration.metrics.enable_code_locations