diff --git a/CHANGELOG.md b/CHANGELOG.md index dbfcdfc2f..7a53440c2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -61,6 +61,7 @@ - Unify Logs and Metrics implementations ([#2826](https://github.com/getsentry/sentry-ruby/pull/2826)) - Unify LogEventBuffer and MetricEventBuffer logic ([#2830](https://github.com/getsentry/sentry-ruby/pull/2830)) - Add maximum limits on LogEventBuffer (1k) and MetricEventBuffer (10k) for protection from memory blowup ([#2831](https://github.com/getsentry/sentry-ruby/pull/2831)) +- Lazily start LogEventBuffer and MetricEventBuffer threads ([#2832](https://github.com/getsentry/sentry-ruby/pull/2832)) ## 6.2.0 diff --git a/sentry-ruby/lib/sentry/client.rb b/sentry-ruby/lib/sentry/client.rb index e196b8a04..800668982 100644 --- a/sentry-ruby/lib/sentry/client.rb +++ b/sentry-ruby/lib/sentry/client.rb @@ -49,11 +49,11 @@ def initialize(configuration) @spotlight_transport = SpotlightTransport.new(configuration) if configuration.spotlight if configuration.enable_logs - @log_event_buffer = LogEventBuffer.new(configuration, self).start + @log_event_buffer = LogEventBuffer.new(configuration, self) end if configuration.enable_metrics - @metric_event_buffer = MetricEventBuffer.new(configuration, self).start + @metric_event_buffer = MetricEventBuffer.new(configuration, self) end end diff --git a/sentry-ruby/lib/sentry/telemetry_event_buffer.rb b/sentry-ruby/lib/sentry/telemetry_event_buffer.rb index f60c921fa..8c5ce0781 100644 --- a/sentry-ruby/lib/sentry/telemetry_event_buffer.rb +++ b/sentry-ruby/lib/sentry/telemetry_event_buffer.rb @@ -14,7 +14,7 @@ class TelemetryEventBuffer < ThreadedPeriodicWorker FLUSH_INTERVAL = 5 # seconds # @!visibility private - attr_reader :pending_items, :envelope_type, :data_category + attr_reader :pending_items, :envelope_type, :data_category, :thread def initialize(configuration, client, event_class:, max_items:, max_items_before_drop:, envelope_type:, envelope_content_type:, before_send:) super(configuration.sdk_logger, FLUSH_INTERVAL) @@ -36,11 +36,6 @@ def initialize(configuration, client, event_class:, max_items:, max_items_before log_debug("[#{self.class}] Initialized buffer with max_items=#{@max_items}, flush_interval=#{FLUSH_INTERVAL}s") end - def start - ensure_thread - self - end - def flush @mutex.synchronize do return if empty? @@ -55,12 +50,9 @@ def flush alias_method :run, :flush def add_item(item) - unless item.is_a?(@event_class) - log_debug("[#{self.class}] expected a #{@event_class}, got #{item.class}") - return - end - @mutex.synchronize do + return unless ensure_thread + if size >= @max_items_before_drop log_debug("[#{self.class}] exceeded max capacity, dropping event") @client.transport.record_lost_event(:queue_overflow, @data_category) diff --git a/sentry-ruby/spec/support/shared_examples_for_telemetry_event_buffers.rb b/sentry-ruby/spec/support/shared_examples_for_telemetry_event_buffers.rb index 575d3dcb1..12fa2d9c4 100644 --- a/sentry-ruby/spec/support/shared_examples_for_telemetry_event_buffers.rb +++ b/sentry-ruby/spec/support/shared_examples_for_telemetry_event_buffers.rb @@ -24,6 +24,18 @@ describe "#add_item" do let(:max_items) { 3 } + it "spawns only one thread" do + expect do + subject.add_item(event) + end.to change { Thread.list.count }.by(1) + + expect(subject.thread).to receive(:alive?).and_return(true) + + expect do + subject.add_item(event) + end.to change { Thread.list.count }.by(0) + end + it "does nothing when there are no pending items" do expect(client).not_to receive(:capture_envelope) @@ -156,9 +168,8 @@ it "keeps the background thread alive after an error" do subject.add_item(event) - subject.start - thread = subject.instance_variable_get(:@thread) + thread = subject.thread expect(thread).to be_alive expect { subject.flush }.not_to raise_error