From 72639dfac88c2eeb8a4484cdcd9bea2264a99022 Mon Sep 17 00:00:00 2001 From: Giancarlo Buenaflor Date: Tue, 16 Dec 2025 18:28:47 +0100 Subject: [PATCH 01/30] feat(telemetry): Enhance telemetry processing with buffer registration and mock implementation - Updated `DefaultTelemetryProcessor` to include a method for registering telemetry buffers. - Refactored the constructor to accept a logger callback instead of Sentry options. - Introduced `MockTelemetryBuffer` for testing purposes, allowing simulation of buffer behavior. - Added comprehensive tests for the `DefaultTelemetryProcessor`, covering initialization, item addition, and buffer flushing. --- packages/dart/lib/src/sentry_client.dart | 1 + .../telemetry_processor.dart | 26 +--- .../test/mocks/mock_telemetry_buffer.dart | 24 ++++ .../telemetry_processor_test.dart | 136 ++++++++++++++++++ 4 files changed, 168 insertions(+), 19 deletions(-) create mode 100644 packages/dart/test/mocks/mock_telemetry_buffer.dart create mode 100644 packages/dart/test/telemetry_processing/telemetry_processor_test.dart diff --git a/packages/dart/lib/src/sentry_client.dart b/packages/dart/lib/src/sentry_client.dart index b53eb998ac..146301f9f6 100644 --- a/packages/dart/lib/src/sentry_client.dart +++ b/packages/dart/lib/src/sentry_client.dart @@ -78,6 +78,7 @@ class SentryClient { if (options.enableLogs) { options.logBatcher = SentryLogBatcher(options); } + // TODO(next-pr): wire up telemetry processor and remove log batcher return SentryClient._(options); } diff --git a/packages/dart/lib/src/telemetry_processing/telemetry_processor.dart b/packages/dart/lib/src/telemetry_processing/telemetry_processor.dart index 7c13e820bc..8186b4380a 100644 --- a/packages/dart/lib/src/telemetry_processing/telemetry_processor.dart +++ b/packages/dart/lib/src/telemetry_processing/telemetry_processor.dart @@ -9,30 +9,18 @@ import 'telemetry_item.dart'; /// Manages buffering and sending of telemetry data to Sentry. abstract class TelemetryProcessor { void add(T item); + void registerBuffer(TelemetryBuffer buffer); FutureOr flush(); } class DefaultTelemetryProcessor implements TelemetryProcessor { - final SentryOptions _options; + final SdkLogCallback _logger; final Map _buffers = {}; @visibleForTesting Map get buffers => _buffers; - DefaultTelemetryProcessor._(this._options); - - factory DefaultTelemetryProcessor(SentryOptions options) { - final processor = DefaultTelemetryProcessor._(options); - - // TODO(next-pr): register buffers for span and log - - options.log( - SentryLevel.debug, - 'DefaultTelemetryProcessor: Successfully initialized', - ); - - return processor; - } + DefaultTelemetryProcessor(this._logger); @override void add(T item) { @@ -40,17 +28,17 @@ class DefaultTelemetryProcessor implements TelemetryProcessor { if (buffer != null) { buffer.add(item); } else { - _options.log( + _logger( SentryLevel.warning, 'DefaultTelemetryProcessor: No buffer registered for telemetry type \'$T\' - item was dropped', ); } } - @visibleForTesting + @override void registerBuffer(TelemetryBuffer buffer) { _buffers[T] = buffer; - _options.log( + _logger( SentryLevel.debug, 'DefaultTelemetryProcessor: Registered buffer for telemetry type \'$T\'', ); @@ -58,7 +46,7 @@ class DefaultTelemetryProcessor implements TelemetryProcessor { @override FutureOr flush() { - _options.log( + _logger( SentryLevel.debug, 'DefaultTelemetryProcessor: Flushing ${_buffers.length} buffer(s)', ); diff --git a/packages/dart/test/mocks/mock_telemetry_buffer.dart b/packages/dart/test/mocks/mock_telemetry_buffer.dart new file mode 100644 index 0000000000..75e8b3c437 --- /dev/null +++ b/packages/dart/test/mocks/mock_telemetry_buffer.dart @@ -0,0 +1,24 @@ +import 'dart:async'; + +import 'package:sentry/src/telemetry_processing/telemetry_buffer.dart'; +import 'package:sentry/src/telemetry_processing/telemetry_item.dart'; + +class MockTelemetryBuffer extends TelemetryBuffer { + final List addedItems = []; + int flushCallCount = 0; + final bool asyncFlush; + + MockTelemetryBuffer({this.asyncFlush = false}); + + @override + void add(T item) => addedItems.add(item); + + @override + FutureOr flush() { + flushCallCount++; + if (asyncFlush) { + return Future.value(); + } + return null; + } +} diff --git a/packages/dart/test/telemetry_processing/telemetry_processor_test.dart b/packages/dart/test/telemetry_processing/telemetry_processor_test.dart new file mode 100644 index 0000000000..344c062853 --- /dev/null +++ b/packages/dart/test/telemetry_processing/telemetry_processor_test.dart @@ -0,0 +1,136 @@ +import 'dart:async'; + +import 'package:sentry/sentry.dart'; +import 'package:sentry/src/protocol/simple_span.dart'; +import 'package:sentry/src/telemetry_processing/telemetry_processor.dart'; +import 'package:test/test.dart'; + +import '../mocks/mock_hub.dart'; +import '../mocks/mock_telemetry_buffer.dart'; +import '../test_utils.dart'; + +void main() { + group('DefaultTelemetryProcessor', () { + late Fixture fixture; + + setUp(() { + fixture = Fixture(); + }); + + group('initialization', () { + test( + 'registers in-memory span buffer when traceLifeCycle is set to streaming', + () { + // TODO(next-pr): add test + }); + + test('registers in-memory log buffer when enableLogs is true', () { + // TODO(next-pr): add test + }); + + test('does NOT register log buffer when enableLogs is false', () { + // TODO(next-pr): add test + }); + }); + + group('add', () { + test('routes telemetry items to correct buffer', () { + final processor = fixture.getSut(); + final mockLogBuffer = MockTelemetryBuffer(); + final mockSpanBuffer = MockTelemetryBuffer(); + processor.registerBuffer(mockLogBuffer); + processor.registerBuffer(mockSpanBuffer); + + final log = fixture.createLog(); + processor.add(log); + + final span = fixture.createSpan(); + span.end(); + processor.add(span); + + expect(mockLogBuffer.addedItems.length, 1); + expect(mockLogBuffer.addedItems.first, log); + expect(mockSpanBuffer.addedItems.length, 1); + expect(mockSpanBuffer.addedItems.first, span); + }); + + test('does not throw when no buffer registered for type', () { + final processor = fixture.getSut(); + processor.buffers.clear(); + + final log = fixture.createLog(); + processor.add(log); + + // Nothing to assert on - just verifying no exception thrown + }); + + // Note: Mismatch between buffer generic type and TelemetryType is now + // impossible - the type is inferred from the generic parameter T. + }); + + group('flush', () { + test('flushes all registered buffers', () async { + final processor = fixture.getSut(); + final mockSpanBuffer = MockTelemetryBuffer(); + final mockLogBuffer = MockTelemetryBuffer(); + processor.registerBuffer(mockSpanBuffer); + processor.registerBuffer(mockLogBuffer); + + await processor.flush(); + + expect(mockSpanBuffer.flushCallCount, 1); + expect(mockLogBuffer.flushCallCount, 1); + }); + + test('returns sync (null) when all buffers flush synchronously', () { + final processor = fixture.getSut(); + final mockBuffer = MockTelemetryBuffer(asyncFlush: false); + processor.registerBuffer(mockBuffer); + + final result = processor.flush(); + + expect(result, isNull); + }); + + test('returns Future when at least one buffer flushes asynchronously', + () async { + final processor = fixture.getSut(); + final mockBuffer = MockTelemetryBuffer(asyncFlush: true); + processor.registerBuffer(mockBuffer); + + final result = processor.flush(); + + expect(result, isA()); + await result; + }); + }); + }); +} + +class Fixture { + final hub = MockHub(); + + late SentryOptions options; + + Fixture() { + options = defaultTestOptions(); + } + + DefaultTelemetryProcessor getSut({bool enableLogs = false}) { + options.enableLogs = enableLogs; + return DefaultTelemetryProcessor(options.log); + } + + SimpleSpan createSpan({String name = 'test-span'}) { + return SimpleSpan(name: name, hub: hub); + } + + SentryLog createLog({String body = 'test log'}) { + return SentryLog( + timestamp: DateTime.now().toUtc(), + level: SentryLogLevel.info, + body: body, + attributes: {}, + ); + } +} From d14838ac51e53f87ec2eb4beb96278cf1e7a4442 Mon Sep 17 00:00:00 2001 From: Giancarlo Buenaflor Date: Tue, 16 Dec 2025 18:31:05 +0100 Subject: [PATCH 02/30] refactor(tests): Remove unused initialization tests from telemetry processor tests - Deleted the initialization test group in `telemetry_processor_test.dart` as the tests were marked with TODOs and not implemented. This cleanup improves the clarity and focus of the test suite. --- .../telemetry_processor_test.dart | 16 ---------------- 1 file changed, 16 deletions(-) diff --git a/packages/dart/test/telemetry_processing/telemetry_processor_test.dart b/packages/dart/test/telemetry_processing/telemetry_processor_test.dart index 344c062853..7e56797a96 100644 --- a/packages/dart/test/telemetry_processing/telemetry_processor_test.dart +++ b/packages/dart/test/telemetry_processing/telemetry_processor_test.dart @@ -17,22 +17,6 @@ void main() { fixture = Fixture(); }); - group('initialization', () { - test( - 'registers in-memory span buffer when traceLifeCycle is set to streaming', - () { - // TODO(next-pr): add test - }); - - test('registers in-memory log buffer when enableLogs is true', () { - // TODO(next-pr): add test - }); - - test('does NOT register log buffer when enableLogs is false', () { - // TODO(next-pr): add test - }); - }); - group('add', () { test('routes telemetry items to correct buffer', () { final processor = fixture.getSut(); From 02b1d34e2164748465119e6cf9de1a5fb1c6bc70 Mon Sep 17 00:00:00 2001 From: Giancarlo Buenaflor Date: Tue, 16 Dec 2025 21:09:27 +0100 Subject: [PATCH 03/30] feat(telemetry): Integrate telemetry processing into SentryOptions - Added a `telemetryProcessor` field to `SentryOptions`, initialized with a `NoOpTelemetryProcessor`. - Enhanced `DefaultTelemetryProcessor` to manage span and log buffers based on Sentry options. - Implemented methods for adding spans and logs, along with flushing buffers for telemetry data transmission. - Introduced a `NoOpTelemetryProcessor` for scenarios where telemetry is not enabled. --- packages/dart/lib/src/sentry_options.dart | 4 + .../telemetry_processor.dart | 125 +++++++++++++----- 2 files changed, 98 insertions(+), 31 deletions(-) diff --git a/packages/dart/lib/src/sentry_options.dart b/packages/dart/lib/src/sentry_options.dart index ba92e6df89..9cff6a0488 100644 --- a/packages/dart/lib/src/sentry_options.dart +++ b/packages/dart/lib/src/sentry_options.dart @@ -12,6 +12,7 @@ import 'noop_client.dart'; import 'platform/platform.dart'; import 'sentry_exception_factory.dart'; import 'sentry_stack_trace_factory.dart'; +import 'telemetry_processing/telemetry_processor.dart'; import 'transport/noop_transport.dart'; import 'version.dart'; import 'sentry_log_batcher.dart'; @@ -543,6 +544,9 @@ class SentryOptions { @internal SentryLogBatcher logBatcher = NoopLogBatcher(); + @internal + TelemetryProcessor telemetryProcessor = NoOpTelemetryProcessor(); + SentryOptions({String? dsn, Platform? platform, RuntimeChecker? checker}) { this.dsn = dsn; if (platform != null) { diff --git a/packages/dart/lib/src/telemetry_processing/telemetry_processor.dart b/packages/dart/lib/src/telemetry_processing/telemetry_processor.dart index 8186b4380a..69ba1ff8c2 100644 --- a/packages/dart/lib/src/telemetry_processing/telemetry_processor.dart +++ b/packages/dart/lib/src/telemetry_processing/telemetry_processor.dart @@ -4,65 +4,128 @@ import 'package:meta/meta.dart'; import '../../sentry.dart'; import 'telemetry_buffer.dart'; -import 'telemetry_item.dart'; /// Manages buffering and sending of telemetry data to Sentry. abstract class TelemetryProcessor { - void add(T item); - void registerBuffer(TelemetryBuffer buffer); + void addSpan(Span span); + void addLog(SentryLog log); FutureOr flush(); } +/// Manages buffering and sending of telemetry data to Sentry. +/// +/// Creates and manages buffers internally based on [SentryOptions] configuration. +/// Buffers are only created when their respective features are enabled. class DefaultTelemetryProcessor implements TelemetryProcessor { + final SentryOptions _options; final SdkLogCallback _logger; - final Map _buffers = {}; + /// Buffer for span telemetry data. + /// + /// Only created if tracing is enabled in options. + @visibleForTesting + TelemetryBuffer? spanBuffer; + + /// Buffer for log telemetry data. + /// + /// Only created if logging is enabled in options. @visibleForTesting - Map get buffers => _buffers; + TelemetryBuffer? logBuffer; + + DefaultTelemetryProcessor(this._options, this._logger) { + _initBuffers(); + } + + void _initBuffers() { + // TODO(next-pr): add span first flag + spanBuffer = createSpanBuffer(); + _logger(SentryLevel.debug, 'TelemetryProcessor: Span buffer initialized'); - DefaultTelemetryProcessor(this._logger); + if (_options.enableLogs) { + logBuffer = createLogBuffer(); + _logger(SentryLevel.debug, 'TelemetryProcessor: Log buffer initialized'); + } + } + /// Creates the span buffer. + /// + /// Can be overridden in subclasses or tests to provide a custom buffer. + @visibleForTesting + TelemetryBuffer createSpanBuffer() { + throw UnimplementedError(); + } + + /// Creates the log buffer. + /// + /// Can be overridden in subclasses or tests to provide a custom buffer. + @visibleForTesting + TelemetryBuffer createLogBuffer() { + throw UnimplementedError(); + } + + /// Adds a span to the buffer for later transmission. + /// + /// If no span buffer is registered, the span is dropped + /// and a warning is logged. @override - void add(T item) { - final buffer = _buffers[T]; + void addSpan(Span span) { + final buffer = spanBuffer; if (buffer != null) { - buffer.add(item); + buffer.add(span); } else { _logger( SentryLevel.warning, - 'DefaultTelemetryProcessor: No buffer registered for telemetry type \'$T\' - item was dropped', + 'TelemetryProcessor: No span buffer registered - span was dropped', ); } } + /// Adds a log to the buffer for later transmission. + /// + /// If no log buffer is registered, the log is dropped + /// and a warning is logged. @override - void registerBuffer(TelemetryBuffer buffer) { - _buffers[T] = buffer; - _logger( - SentryLevel.debug, - 'DefaultTelemetryProcessor: Registered buffer for telemetry type \'$T\'', - ); + void addLog(SentryLog log) { + final buffer = logBuffer; + if (buffer != null) { + buffer.add(log); + } else { + _logger( + SentryLevel.warning, + 'TelemetryProcessor: No log buffer registered - log was dropped', + ); + } } + /// Flushes all buffers, sending any pending telemetry data. + /// + /// Returns a [Future] that completes when all buffers have been flushed. + /// Returns immediately if no buffers need flushing. @override FutureOr flush() { - _logger( - SentryLevel.debug, - 'DefaultTelemetryProcessor: Flushing ${_buffers.length} buffer(s)', - ); - - final results = _buffers.values.map((buffer) => buffer.flush()).toList(); - - final futures = >[]; - for (final result in results) { - if (result is Future) { - futures.add(result); - } - } + _logger(SentryLevel.debug, 'TelemetryProcessor: Flushing buffers'); - // If all are sync, preserve sync behavior (no Future allocation). - if (futures.isEmpty) return null; + final results = >[ + spanBuffer?.flush(), + logBuffer?.flush(), + ].whereType>().toList(); + + final futures = results.whereType>().toList(); + if (futures.isEmpty) { + return null; + } return Future.wait(futures).then((_) {}); } } + +class NoOpTelemetryProcessor implements TelemetryProcessor { + @override + void addSpan(Span span) {} + + @override + void addLog(SentryLog log) {} + + @override + FutureOr flush() {} +} From f80d9baea8c95cce43eeb5cc137facf01503dda5 Mon Sep 17 00:00:00 2001 From: Giancarlo Buenaflor Date: Tue, 16 Dec 2025 21:17:20 +0100 Subject: [PATCH 04/30] refactor(telemetry): Simplify telemetry buffer handling in DefaultTelemetryProcessor - Removed unnecessary comments regarding buffer creation based on options. - Updated tests to reflect changes in method names for adding spans and logs. - Enhanced test coverage for handling cases where buffers may not be registered, ensuring no exceptions are thrown. - Introduced a test subclass to facilitate mock buffer creation for testing purposes. --- .../telemetry_processor.dart | 4 - .../telemetry_processor_test.dart | 101 +++++++++++++----- 2 files changed, 77 insertions(+), 28 deletions(-) diff --git a/packages/dart/lib/src/telemetry_processing/telemetry_processor.dart b/packages/dart/lib/src/telemetry_processing/telemetry_processor.dart index 69ba1ff8c2..1decfbefec 100644 --- a/packages/dart/lib/src/telemetry_processing/telemetry_processor.dart +++ b/packages/dart/lib/src/telemetry_processing/telemetry_processor.dart @@ -21,14 +21,10 @@ class DefaultTelemetryProcessor implements TelemetryProcessor { final SdkLogCallback _logger; /// Buffer for span telemetry data. - /// - /// Only created if tracing is enabled in options. @visibleForTesting TelemetryBuffer? spanBuffer; /// Buffer for log telemetry data. - /// - /// Only created if logging is enabled in options. @visibleForTesting TelemetryBuffer? logBuffer; diff --git a/packages/dart/test/telemetry_processing/telemetry_processor_test.dart b/packages/dart/test/telemetry_processing/telemetry_processor_test.dart index 7e56797a96..35cb745a71 100644 --- a/packages/dart/test/telemetry_processing/telemetry_processor_test.dart +++ b/packages/dart/test/telemetry_processing/telemetry_processor_test.dart @@ -2,6 +2,7 @@ import 'dart:async'; import 'package:sentry/sentry.dart'; import 'package:sentry/src/protocol/simple_span.dart'; +import 'package:sentry/src/telemetry_processing/telemetry_buffer.dart'; import 'package:sentry/src/telemetry_processing/telemetry_processor.dart'; import 'package:test/test.dart'; @@ -17,39 +18,65 @@ void main() { fixture = Fixture(); }); - group('add', () { - test('routes telemetry items to correct buffer', () { + group('addSpan', () { + test('routes span to span buffer', () { final processor = fixture.getSut(); - final mockLogBuffer = MockTelemetryBuffer(); final mockSpanBuffer = MockTelemetryBuffer(); - processor.registerBuffer(mockLogBuffer); - processor.registerBuffer(mockSpanBuffer); - - final log = fixture.createLog(); - processor.add(log); + processor.spanBuffer = mockSpanBuffer; final span = fixture.createSpan(); span.end(); - processor.add(span); + processor.addSpan(span); - expect(mockLogBuffer.addedItems.length, 1); - expect(mockLogBuffer.addedItems.first, log); expect(mockSpanBuffer.addedItems.length, 1); expect(mockSpanBuffer.addedItems.first, span); }); - test('does not throw when no buffer registered for type', () { + test('handles subtypes correctly (SimpleSpan -> Span buffer)', () { final processor = fixture.getSut(); - processor.buffers.clear(); + final mockSpanBuffer = MockTelemetryBuffer(); + processor.spanBuffer = mockSpanBuffer; + + final simpleSpan = fixture.createSpan(); + simpleSpan.end(); + processor.addSpan(simpleSpan); + + expect(mockSpanBuffer.addedItems.length, 1); + expect(mockSpanBuffer.addedItems.first, isA()); + }); + + test('does not throw when no span buffer registered', () { + final processor = fixture.getSut(); + processor.spanBuffer = null; + + final span = fixture.createSpan(); + span.end(); + processor.addSpan(span); + + // Nothing to assert - just verifying no exception thrown + }); + }); + + group('addLog', () { + test('routes log to log buffer', () { + final processor = fixture.getSut(enableLogs: true); + final mockLogBuffer = MockTelemetryBuffer(); + processor.logBuffer = mockLogBuffer; final log = fixture.createLog(); - processor.add(log); + processor.addLog(log); - // Nothing to assert on - just verifying no exception thrown + expect(mockLogBuffer.addedItems.length, 1); + expect(mockLogBuffer.addedItems.first, log); }); - // Note: Mismatch between buffer generic type and TelemetryType is now - // impossible - the type is inferred from the generic parameter T. + test('does not throw when no log buffer registered', () { + final processor = fixture.getSut(); + processor.logBuffer = null; + + final log = fixture.createLog(); + processor.addLog(log); + }); }); group('flush', () { @@ -57,8 +84,8 @@ void main() { final processor = fixture.getSut(); final mockSpanBuffer = MockTelemetryBuffer(); final mockLogBuffer = MockTelemetryBuffer(); - processor.registerBuffer(mockSpanBuffer); - processor.registerBuffer(mockLogBuffer); + processor.spanBuffer = mockSpanBuffer; + processor.logBuffer = mockLogBuffer; await processor.flush(); @@ -66,10 +93,22 @@ void main() { expect(mockLogBuffer.flushCallCount, 1); }); + test('flushes only span buffer when log buffer is null', () async { + final processor = fixture.getSut(); + final mockSpanBuffer = MockTelemetryBuffer(); + processor.spanBuffer = mockSpanBuffer; + processor.logBuffer = null; + + await processor.flush(); + + expect(mockSpanBuffer.flushCallCount, 1); + }); + test('returns sync (null) when all buffers flush synchronously', () { final processor = fixture.getSut(); - final mockBuffer = MockTelemetryBuffer(asyncFlush: false); - processor.registerBuffer(mockBuffer); + final mockSpanBuffer = MockTelemetryBuffer(asyncFlush: false); + processor.spanBuffer = mockSpanBuffer; + processor.logBuffer = null; final result = processor.flush(); @@ -79,8 +118,9 @@ void main() { test('returns Future when at least one buffer flushes asynchronously', () async { final processor = fixture.getSut(); - final mockBuffer = MockTelemetryBuffer(asyncFlush: true); - processor.registerBuffer(mockBuffer); + final mockSpanBuffer = MockTelemetryBuffer(asyncFlush: true); + processor.spanBuffer = mockSpanBuffer; + processor.logBuffer = null; final result = processor.flush(); @@ -102,7 +142,7 @@ class Fixture { DefaultTelemetryProcessor getSut({bool enableLogs = false}) { options.enableLogs = enableLogs; - return DefaultTelemetryProcessor(options.log); + return _TestTelemetryProcessor(options, options.log); } SimpleSpan createSpan({String name = 'test-span'}) { @@ -118,3 +158,16 @@ class Fixture { ); } } + +/// Test subclass that overrides buffer creation to avoid UnimplementedError. +/// TODO(next-pr): can be removed when we have the default in-memory buffers +class _TestTelemetryProcessor extends DefaultTelemetryProcessor { + _TestTelemetryProcessor(super.options, super.logger); + + @override + TelemetryBuffer createSpanBuffer() => MockTelemetryBuffer(); + + @override + TelemetryBuffer createLogBuffer() => + MockTelemetryBuffer(); +} From 388409ca7bb2d5ae959f74145a0c61781084731f Mon Sep 17 00:00:00 2001 From: Giancarlo Buenaflor Date: Tue, 16 Dec 2025 21:21:55 +0100 Subject: [PATCH 05/30] feat(telemetry): Implement in-memory telemetry buffer for span and log processing - Introduced `InMemoryTelemetryBuffer` class for managing telemetry items with time and size-based flushing. - Updated `DefaultTelemetryProcessor` to utilize `InMemoryTelemetryBuffer` for span and log buffering. - Removed obsolete buffer creation methods to streamline buffer initialization. - Adjusted tests to instantiate `DefaultTelemetryProcessor` directly, enhancing clarity and consistency. --- .../telemetry_buffer.dart | 14 +++++++++++++ .../telemetry_processor.dart | 20 ++----------------- .../telemetry_processor_test.dart | 15 +------------- 3 files changed, 17 insertions(+), 32 deletions(-) diff --git a/packages/dart/lib/src/telemetry_processing/telemetry_buffer.dart b/packages/dart/lib/src/telemetry_processing/telemetry_buffer.dart index 7dd894c312..31a00e8ff5 100644 --- a/packages/dart/lib/src/telemetry_processing/telemetry_buffer.dart +++ b/packages/dart/lib/src/telemetry_processing/telemetry_buffer.dart @@ -14,3 +14,17 @@ class EncodedTelemetryItem { EncodedTelemetryItem(this.item, this.encoded); } + +/// In-memory buffer with time and size-based flushing. +class InMemoryTelemetryBuffer + extends TelemetryBuffer { + @override + void add(T item) { + // TODO(next-pr) + } + + @override + FutureOr flush() { + // TODO(next-pr) + } +} diff --git a/packages/dart/lib/src/telemetry_processing/telemetry_processor.dart b/packages/dart/lib/src/telemetry_processing/telemetry_processor.dart index 1decfbefec..e30a337c45 100644 --- a/packages/dart/lib/src/telemetry_processing/telemetry_processor.dart +++ b/packages/dart/lib/src/telemetry_processing/telemetry_processor.dart @@ -34,31 +34,15 @@ class DefaultTelemetryProcessor implements TelemetryProcessor { void _initBuffers() { // TODO(next-pr): add span first flag - spanBuffer = createSpanBuffer(); + spanBuffer = InMemoryTelemetryBuffer(); _logger(SentryLevel.debug, 'TelemetryProcessor: Span buffer initialized'); if (_options.enableLogs) { - logBuffer = createLogBuffer(); + logBuffer = InMemoryTelemetryBuffer(); _logger(SentryLevel.debug, 'TelemetryProcessor: Log buffer initialized'); } } - /// Creates the span buffer. - /// - /// Can be overridden in subclasses or tests to provide a custom buffer. - @visibleForTesting - TelemetryBuffer createSpanBuffer() { - throw UnimplementedError(); - } - - /// Creates the log buffer. - /// - /// Can be overridden in subclasses or tests to provide a custom buffer. - @visibleForTesting - TelemetryBuffer createLogBuffer() { - throw UnimplementedError(); - } - /// Adds a span to the buffer for later transmission. /// /// If no span buffer is registered, the span is dropped diff --git a/packages/dart/test/telemetry_processing/telemetry_processor_test.dart b/packages/dart/test/telemetry_processing/telemetry_processor_test.dart index 35cb745a71..97afb14ea8 100644 --- a/packages/dart/test/telemetry_processing/telemetry_processor_test.dart +++ b/packages/dart/test/telemetry_processing/telemetry_processor_test.dart @@ -142,7 +142,7 @@ class Fixture { DefaultTelemetryProcessor getSut({bool enableLogs = false}) { options.enableLogs = enableLogs; - return _TestTelemetryProcessor(options, options.log); + return DefaultTelemetryProcessor(options, options.log); } SimpleSpan createSpan({String name = 'test-span'}) { @@ -158,16 +158,3 @@ class Fixture { ); } } - -/// Test subclass that overrides buffer creation to avoid UnimplementedError. -/// TODO(next-pr): can be removed when we have the default in-memory buffers -class _TestTelemetryProcessor extends DefaultTelemetryProcessor { - _TestTelemetryProcessor(super.options, super.logger); - - @override - TelemetryBuffer createSpanBuffer() => MockTelemetryBuffer(); - - @override - TelemetryBuffer createLogBuffer() => - MockTelemetryBuffer(); -} From ca184fcb7465256d5f7b994143a89621a8e8e9e7 Mon Sep 17 00:00:00 2001 From: Giancarlo Buenaflor Date: Tue, 16 Dec 2025 21:25:01 +0100 Subject: [PATCH 06/30] fix(span): Ensure child span inherits traceId from parent correctly - Updated the SimpleSpan constructor to inherit traceId from the parent span if available, ensuring consistent trace propagation. - Removed the condition that set 'is_segment' to true when there is no parent span, simplifying the span representation. - Added a test to verify that child spans correctly inherit the traceId from their parent, even after resetting the propagation context. --- .../dart/lib/src/protocol/simple_span.dart | 3 +-- packages/dart/test/span_test.dart | 19 +++++++++++++++++++ 2 files changed, 20 insertions(+), 2 deletions(-) diff --git a/packages/dart/lib/src/protocol/simple_span.dart b/packages/dart/lib/src/protocol/simple_span.dart index 49a78b9fa4..5590250136 100644 --- a/packages/dart/lib/src/protocol/simple_span.dart +++ b/packages/dart/lib/src/protocol/simple_span.dart @@ -24,7 +24,7 @@ class SimpleSpan implements Span { _startTimestamp = DateTime.now().toUtc(), _name = name { _segmentSpan = parentSpan?.segmentSpan ?? this; - _traceId = _hub.scope.propagationContext.traceId; + _traceId = parentSpan?.traceId ?? _hub.scope.propagationContext.traceId; } @override @@ -92,7 +92,6 @@ class SimpleSpan implements Span { _endTimestamp == null ? null : toUnixSeconds(_endTimestamp!), 'start_timestamp': toUnixSeconds(_startTimestamp), if (parentSpan != null) 'parent_span_id': parentSpan?.spanId.toString(), - if (parentSpan == null) 'is_segment': true, if (_attributes.isNotEmpty) 'attributes': _attributes.map((key, value) => MapEntry(key, value.toJson())), diff --git a/packages/dart/test/span_test.dart b/packages/dart/test/span_test.dart index 55bcaa27a7..79ed43bc69 100644 --- a/packages/dart/test/span_test.dart +++ b/packages/dart/test/span_test.dart @@ -207,6 +207,25 @@ void main() { expect(child.traceId, equals(parent.traceId)); }); + test( + 'child span inherits traceId from parent even after propagation context reset', + () { + final hub = fixture.getHub(); + final parent = SimpleSpan(name: 'parent', parentSpan: null, hub: hub); + final parentTraceId = parent.traceId; + + // Reset the propagation context - this would change the scope's traceId + hub.scope.propagationContext.resetTrace(); + final newPropagationTraceId = hub.scope.propagationContext.traceId; + + // Create child span after reset + final child = SimpleSpan(name: 'child', parentSpan: parent, hub: hub); + + // Child should inherit from parent, not from the new propagation context + expect(child.traceId, equals(parentTraceId)); + expect(child.traceId, isNot(equals(newPropagationTraceId))); + }); + test('traceId is set at construction time', () { final hub = fixture.getHub(); final originalTraceId = hub.scope.propagationContext.traceId; From 534aee1dc631146277ebe511afdc4017be043e6d Mon Sep 17 00:00:00 2001 From: Giancarlo Buenaflor Date: Tue, 16 Dec 2025 21:45:49 +0100 Subject: [PATCH 07/30] fix(noop_span): Correct segmentSpan implementation to return the current instance - Updated the segmentSpan getter in NoOpSpan to return the current instance instead of a new NoOpSpan, ensuring proper span behavior and consistency in span hierarchy. --- packages/dart/lib/src/protocol/noop_span.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/dart/lib/src/protocol/noop_span.dart b/packages/dart/lib/src/protocol/noop_span.dart index d42c2ce7a9..ec7b7e52be 100644 --- a/packages/dart/lib/src/protocol/noop_span.dart +++ b/packages/dart/lib/src/protocol/noop_span.dart @@ -44,7 +44,7 @@ class NoOpSpan implements Span { Map toJson() => {}; @override - Span get segmentSpan => NoOpSpan(); + Span get segmentSpan => this; @override SentryId get traceId => SentryId.empty(); From 59927dcccf02f1535a2f3b21d6d544f2aa825ce5 Mon Sep 17 00:00:00 2001 From: Giancarlo Buenaflor Date: Tue, 16 Dec 2025 22:56:53 +0100 Subject: [PATCH 08/30] Formatting --- packages/dart/test/span_test.dart | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/packages/dart/test/span_test.dart b/packages/dart/test/span_test.dart index 79ed43bc69..7e31c38919 100644 --- a/packages/dart/test/span_test.dart +++ b/packages/dart/test/span_test.dart @@ -181,8 +181,8 @@ void main() { final child = SimpleSpan(name: 'child', parentSpan: root, hub: hub); final grandchild = SimpleSpan(name: 'grandchild', parentSpan: child, hub: hub); - final greatGrandchild = - SimpleSpan(name: 'great-grandchild', parentSpan: grandchild, hub: hub); + final greatGrandchild = SimpleSpan( + name: 'great-grandchild', parentSpan: grandchild, hub: hub); expect(grandchild.segmentSpan, same(root)); expect(greatGrandchild.segmentSpan, same(root)); @@ -322,7 +322,8 @@ void main() { expect(json['end_timestamp'], isNull); }); - test('timestamps are serialized as unix seconds with microsecond precision', + test( + 'timestamps are serialized as unix seconds with microsecond precision', () { final hub = fixture.getMockHub(); final span = SimpleSpan(name: 'test-span', parentSpan: null, hub: hub); @@ -341,7 +342,8 @@ void main() { test('serializes updated name', () { final hub = fixture.getMockHub(); - final span = SimpleSpan(name: 'original-name', parentSpan: null, hub: hub); + final span = + SimpleSpan(name: 'original-name', parentSpan: null, hub: hub); span.name = 'updated-name'; span.end(); From ed407b1dfa7998f36590cfc498a52cf0c4733193 Mon Sep 17 00:00:00 2001 From: Giancarlo Buenaflor Date: Wed, 17 Dec 2025 12:18:02 +0100 Subject: [PATCH 09/30] feat(telemetry): Enhance DefaultTelemetryProcessor with customizable buffer factories - Introduced `TelemetryBufferFactory` type for creating telemetry buffers, allowing for custom buffer implementations. - Updated `DefaultTelemetryProcessor` constructor to accept optional buffer factory parameters for spans and logs, defaulting to `InMemoryTelemetryBuffer`. - Modified tests to utilize mock buffers, improving test flexibility and clarity in buffer handling. --- .../telemetry_processor.dart | 25 +++++++++-- .../telemetry_processor_test.dart | 41 +++++++++++-------- 2 files changed, 45 insertions(+), 21 deletions(-) diff --git a/packages/dart/lib/src/telemetry_processing/telemetry_processor.dart b/packages/dart/lib/src/telemetry_processing/telemetry_processor.dart index e30a337c45..d7f67a73f9 100644 --- a/packages/dart/lib/src/telemetry_processing/telemetry_processor.dart +++ b/packages/dart/lib/src/telemetry_processing/telemetry_processor.dart @@ -4,6 +4,11 @@ import 'package:meta/meta.dart'; import '../../sentry.dart'; import 'telemetry_buffer.dart'; +import 'telemetry_item.dart'; + +/// Factory function for creating telemetry buffers. +typedef TelemetryBufferFactory = TelemetryBuffer + Function(); /// Manages buffering and sending of telemetry data to Sentry. abstract class TelemetryProcessor { @@ -19,6 +24,8 @@ abstract class TelemetryProcessor { class DefaultTelemetryProcessor implements TelemetryProcessor { final SentryOptions _options; final SdkLogCallback _logger; + final TelemetryBufferFactory _spanBufferFactory; + final TelemetryBufferFactory _logBufferFactory; /// Buffer for span telemetry data. @visibleForTesting @@ -28,17 +35,29 @@ class DefaultTelemetryProcessor implements TelemetryProcessor { @visibleForTesting TelemetryBuffer? logBuffer; - DefaultTelemetryProcessor(this._options, this._logger) { + /// Creates a telemetry processor with optional custom buffer factories. + /// + /// If [spanBufferFactory] or [logBufferFactory] are not provided, + /// defaults to [InMemoryTelemetryBuffer]. + DefaultTelemetryProcessor( + this._options, + this._logger, { + TelemetryBufferFactory? spanBufferFactory, + TelemetryBufferFactory? logBufferFactory, + }) : _spanBufferFactory = + spanBufferFactory ?? InMemoryTelemetryBuffer.new, + _logBufferFactory = + logBufferFactory ?? InMemoryTelemetryBuffer.new { _initBuffers(); } void _initBuffers() { // TODO(next-pr): add span first flag - spanBuffer = InMemoryTelemetryBuffer(); + spanBuffer = _spanBufferFactory(); _logger(SentryLevel.debug, 'TelemetryProcessor: Span buffer initialized'); if (_options.enableLogs) { - logBuffer = InMemoryTelemetryBuffer(); + logBuffer = _logBufferFactory(); _logger(SentryLevel.debug, 'TelemetryProcessor: Log buffer initialized'); } } diff --git a/packages/dart/test/telemetry_processing/telemetry_processor_test.dart b/packages/dart/test/telemetry_processing/telemetry_processor_test.dart index 97afb14ea8..969738b239 100644 --- a/packages/dart/test/telemetry_processing/telemetry_processor_test.dart +++ b/packages/dart/test/telemetry_processing/telemetry_processor_test.dart @@ -2,7 +2,6 @@ import 'dart:async'; import 'package:sentry/sentry.dart'; import 'package:sentry/src/protocol/simple_span.dart'; -import 'package:sentry/src/telemetry_processing/telemetry_buffer.dart'; import 'package:sentry/src/telemetry_processing/telemetry_processor.dart'; import 'package:test/test.dart'; @@ -20,9 +19,8 @@ void main() { group('addSpan', () { test('routes span to span buffer', () { - final processor = fixture.getSut(); final mockSpanBuffer = MockTelemetryBuffer(); - processor.spanBuffer = mockSpanBuffer; + final processor = fixture.getSut(spanBuffer: mockSpanBuffer); final span = fixture.createSpan(); span.end(); @@ -33,9 +31,8 @@ void main() { }); test('handles subtypes correctly (SimpleSpan -> Span buffer)', () { - final processor = fixture.getSut(); final mockSpanBuffer = MockTelemetryBuffer(); - processor.spanBuffer = mockSpanBuffer; + final processor = fixture.getSut(spanBuffer: mockSpanBuffer); final simpleSpan = fixture.createSpan(); simpleSpan.end(); @@ -59,9 +56,9 @@ void main() { group('addLog', () { test('routes log to log buffer', () { - final processor = fixture.getSut(enableLogs: true); final mockLogBuffer = MockTelemetryBuffer(); - processor.logBuffer = mockLogBuffer; + final processor = + fixture.getSut(enableLogs: true, logBuffer: mockLogBuffer); final log = fixture.createLog(); processor.addLog(log); @@ -81,11 +78,13 @@ void main() { group('flush', () { test('flushes all registered buffers', () async { - final processor = fixture.getSut(); final mockSpanBuffer = MockTelemetryBuffer(); final mockLogBuffer = MockTelemetryBuffer(); - processor.spanBuffer = mockSpanBuffer; - processor.logBuffer = mockLogBuffer; + final processor = fixture.getSut( + enableLogs: true, + spanBuffer: mockSpanBuffer, + logBuffer: mockLogBuffer, + ); await processor.flush(); @@ -94,9 +93,8 @@ void main() { }); test('flushes only span buffer when log buffer is null', () async { - final processor = fixture.getSut(); final mockSpanBuffer = MockTelemetryBuffer(); - processor.spanBuffer = mockSpanBuffer; + final processor = fixture.getSut(spanBuffer: mockSpanBuffer); processor.logBuffer = null; await processor.flush(); @@ -105,9 +103,8 @@ void main() { }); test('returns sync (null) when all buffers flush synchronously', () { - final processor = fixture.getSut(); final mockSpanBuffer = MockTelemetryBuffer(asyncFlush: false); - processor.spanBuffer = mockSpanBuffer; + final processor = fixture.getSut(spanBuffer: mockSpanBuffer); processor.logBuffer = null; final result = processor.flush(); @@ -117,9 +114,8 @@ void main() { test('returns Future when at least one buffer flushes asynchronously', () async { - final processor = fixture.getSut(); final mockSpanBuffer = MockTelemetryBuffer(asyncFlush: true); - processor.spanBuffer = mockSpanBuffer; + final processor = fixture.getSut(spanBuffer: mockSpanBuffer); processor.logBuffer = null; final result = processor.flush(); @@ -140,9 +136,18 @@ class Fixture { options = defaultTestOptions(); } - DefaultTelemetryProcessor getSut({bool enableLogs = false}) { + DefaultTelemetryProcessor getSut({ + bool enableLogs = false, + MockTelemetryBuffer? spanBuffer, + MockTelemetryBuffer? logBuffer, + }) { options.enableLogs = enableLogs; - return DefaultTelemetryProcessor(options, options.log); + return DefaultTelemetryProcessor( + options, + options.log, + spanBufferFactory: spanBuffer != null ? () => spanBuffer : null, + logBufferFactory: logBuffer != null ? () => logBuffer : null, + ); } SimpleSpan createSpan({String name = 'test-span'}) { From b4dc2a17c16b28b2ef049bb04016e474ca4de262 Mon Sep 17 00:00:00 2001 From: Giancarlo Buenaflor Date: Wed, 17 Dec 2025 12:19:27 +0100 Subject: [PATCH 10/30] refactor(span): Update SimpleSpan to use configurable clock for timestamps - Changed the initialization of _startTimestamp to use a configurable clock from the Hub options instead of the current UTC time. - Updated the _endTimestamp assignment to also utilize the Hub's clock, ensuring consistent time handling across spans. --- packages/dart/lib/src/protocol/simple_span.dart | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/dart/lib/src/protocol/simple_span.dart b/packages/dart/lib/src/protocol/simple_span.dart index 5590250136..f545e514fb 100644 --- a/packages/dart/lib/src/protocol/simple_span.dart +++ b/packages/dart/lib/src/protocol/simple_span.dart @@ -3,10 +3,10 @@ import '../../sentry.dart'; class SimpleSpan implements Span { final SpanId _spanId; final Hub _hub; - final DateTime _startTimestamp; @override final Span? parentSpan; final Map _attributes = {}; + late final DateTime _startTimestamp; late final Span _segmentSpan; late final SentryId _traceId; @@ -21,10 +21,10 @@ class SimpleSpan implements Span { Hub? hub, }) : _spanId = SpanId.newId(), _hub = hub ?? HubAdapter(), - _startTimestamp = DateTime.now().toUtc(), _name = name { _segmentSpan = parentSpan?.segmentSpan ?? this; _traceId = parentSpan?.traceId ?? _hub.scope.propagationContext.traceId; + _startTimestamp = _hub.options.clock(); } @override @@ -72,7 +72,7 @@ class SimpleSpan implements Span { if (_isFinished) { return; } - _endTimestamp = (endTimestamp ?? DateTime.now()).toUtc(); + _endTimestamp = (endTimestamp ?? _hub.options.clock()); _isFinished = true; _hub.captureSpan(this); } From 01c771b13ffb1f633d0d243d26e86a2ca4430f60 Mon Sep 17 00:00:00 2001 From: Giancarlo Buenaflor Date: Wed, 17 Dec 2025 13:07:34 +0100 Subject: [PATCH 11/30] refactor(telemetry): Simplify DefaultTelemetryProcessor by removing buffer factory parameters - Removed the optional buffer factory parameters from the DefaultTelemetryProcessor constructor, directly accepting span and log buffers instead. - Streamlined the addSpan and addLog methods to utilize a common _add method for handling telemetry items. - Updated tests to reflect changes in the DefaultTelemetryProcessor instantiation, enhancing clarity in buffer management. --- .../telemetry_processor.dart | 63 ++++++------------- .../telemetry_processor_test.dart | 5 +- 2 files changed, 21 insertions(+), 47 deletions(-) diff --git a/packages/dart/lib/src/telemetry_processing/telemetry_processor.dart b/packages/dart/lib/src/telemetry_processing/telemetry_processor.dart index d7f67a73f9..f966f2b1ac 100644 --- a/packages/dart/lib/src/telemetry_processing/telemetry_processor.dart +++ b/packages/dart/lib/src/telemetry_processing/telemetry_processor.dart @@ -22,10 +22,7 @@ abstract class TelemetryProcessor { /// Creates and manages buffers internally based on [SentryOptions] configuration. /// Buffers are only created when their respective features are enabled. class DefaultTelemetryProcessor implements TelemetryProcessor { - final SentryOptions _options; final SdkLogCallback _logger; - final TelemetryBufferFactory _spanBufferFactory; - final TelemetryBufferFactory _logBufferFactory; /// Buffer for span telemetry data. @visibleForTesting @@ -35,65 +32,43 @@ class DefaultTelemetryProcessor implements TelemetryProcessor { @visibleForTesting TelemetryBuffer? logBuffer; - /// Creates a telemetry processor with optional custom buffer factories. - /// - /// If [spanBufferFactory] or [logBufferFactory] are not provided, - /// defaults to [InMemoryTelemetryBuffer]. + /// Creates a telemetry processor. DefaultTelemetryProcessor( - this._options, this._logger, { - TelemetryBufferFactory? spanBufferFactory, - TelemetryBufferFactory? logBufferFactory, - }) : _spanBufferFactory = - spanBufferFactory ?? InMemoryTelemetryBuffer.new, - _logBufferFactory = - logBufferFactory ?? InMemoryTelemetryBuffer.new { - _initBuffers(); - } - - void _initBuffers() { - // TODO(next-pr): add span first flag - spanBuffer = _spanBufferFactory(); - _logger(SentryLevel.debug, 'TelemetryProcessor: Span buffer initialized'); - - if (_options.enableLogs) { - logBuffer = _logBufferFactory(); - _logger(SentryLevel.debug, 'TelemetryProcessor: Log buffer initialized'); - } - } + this.spanBuffer, + this.logBuffer, + }); /// Adds a span to the buffer for later transmission. /// /// If no span buffer is registered, the span is dropped /// and a warning is logged. @override - void addSpan(Span span) { - final buffer = spanBuffer; - if (buffer != null) { - buffer.add(span); - } else { - _logger( - SentryLevel.warning, - 'TelemetryProcessor: No span buffer registered - span was dropped', - ); - } - } + void addSpan(Span span) => _add(span); /// Adds a log to the buffer for later transmission. /// /// If no log buffer is registered, the log is dropped /// and a warning is logged. @override - void addLog(SentryLog log) { - final buffer = logBuffer; - if (buffer != null) { - buffer.add(log); - } else { + void addLog(SentryLog log) => _add(log); + + void _add(TelemetryItem item) { + final buffer = switch (item) { + Span() => spanBuffer, + SentryLog() => logBuffer, + _ => null, + }; + + if (buffer == null) { _logger( SentryLevel.warning, - 'TelemetryProcessor: No log buffer registered - log was dropped', + 'TelemetryProcessor: No buffer registered for ${item.runtimeType} - item was dropped', ); + return; } + + buffer.add(item); } /// Flushes all buffers, sending any pending telemetry data. diff --git a/packages/dart/test/telemetry_processing/telemetry_processor_test.dart b/packages/dart/test/telemetry_processing/telemetry_processor_test.dart index 969738b239..2093f13c41 100644 --- a/packages/dart/test/telemetry_processing/telemetry_processor_test.dart +++ b/packages/dart/test/telemetry_processing/telemetry_processor_test.dart @@ -143,10 +143,9 @@ class Fixture { }) { options.enableLogs = enableLogs; return DefaultTelemetryProcessor( - options, options.log, - spanBufferFactory: spanBuffer != null ? () => spanBuffer : null, - logBufferFactory: logBuffer != null ? () => logBuffer : null, + spanBuffer: spanBuffer, + logBuffer: logBuffer, ); } From b868f54610a568ed272e8a023ccdea5b71df914e Mon Sep 17 00:00:00 2001 From: Giancarlo Buenaflor Date: Wed, 17 Dec 2025 13:08:15 +0100 Subject: [PATCH 12/30] refactor(telemetry): Remove unused telemetry item import from NoOpSpan - Eliminated the import of `telemetry_item.dart` in `noop_span.dart` as it is no longer needed. - Streamlined the `NoOpSpan` class to focus on its core functionality without unnecessary dependencies. --- packages/dart/lib/src/protocol/noop_span.dart | 1 - .../lib/src/telemetry_processing/telemetry_processor.dart | 4 ---- 2 files changed, 5 deletions(-) diff --git a/packages/dart/lib/src/protocol/noop_span.dart b/packages/dart/lib/src/protocol/noop_span.dart index ec7b7e52be..72dd188ff8 100644 --- a/packages/dart/lib/src/protocol/noop_span.dart +++ b/packages/dart/lib/src/protocol/noop_span.dart @@ -1,5 +1,4 @@ import '../../sentry.dart'; -import '../telemetry_processing/telemetry_item.dart'; class NoOpSpan implements Span { const NoOpSpan(); diff --git a/packages/dart/lib/src/telemetry_processing/telemetry_processor.dart b/packages/dart/lib/src/telemetry_processing/telemetry_processor.dart index f966f2b1ac..5d1c59ae26 100644 --- a/packages/dart/lib/src/telemetry_processing/telemetry_processor.dart +++ b/packages/dart/lib/src/telemetry_processing/telemetry_processor.dart @@ -6,10 +6,6 @@ import '../../sentry.dart'; import 'telemetry_buffer.dart'; import 'telemetry_item.dart'; -/// Factory function for creating telemetry buffers. -typedef TelemetryBufferFactory = TelemetryBuffer - Function(); - /// Manages buffering and sending of telemetry data to Sentry. abstract class TelemetryProcessor { void addSpan(Span span); From 874c684ed688718f99a08037c17dbe72f16e5d00 Mon Sep 17 00:00:00 2001 From: Giancarlo Buenaflor Date: Wed, 17 Dec 2025 13:13:45 +0100 Subject: [PATCH 13/30] refactor(telemetry): Replace TelemetryItem with SentryEncodable interface - Updated SentryLog and Span classes to implement the new SentryEncodable interface instead of the deprecated TelemetryItem. - Refactored TelemetryBuffer and related classes to work with SentryEncodable, enhancing type safety and consistency across telemetry processing. - Introduced SentryEncodable interface to define a common method for JSON serialization, streamlining the encoding process for telemetry items. --- packages/dart/lib/src/protocol/sentry_log.dart | 4 ++-- packages/dart/lib/src/protocol/span.dart | 4 ++-- .../{telemetry_item.dart => sentry_encodable.dart} | 2 +- .../src/telemetry_processing/telemetry_buffer.dart | 14 ++++++++------ .../telemetry_processing/telemetry_processor.dart | 4 ++-- .../dart/test/mocks/mock_telemetry_buffer.dart | 5 +++-- 6 files changed, 18 insertions(+), 15 deletions(-) rename packages/dart/lib/src/telemetry_processing/{telemetry_item.dart => sentry_encodable.dart} (71%) diff --git a/packages/dart/lib/src/protocol/sentry_log.dart b/packages/dart/lib/src/protocol/sentry_log.dart index dfc8571df7..911b9eb027 100644 --- a/packages/dart/lib/src/protocol/sentry_log.dart +++ b/packages/dart/lib/src/protocol/sentry_log.dart @@ -1,9 +1,9 @@ -import '../telemetry_processing/telemetry_item.dart'; +import '../telemetry_processing/sentry_encodable.dart'; import 'sentry_attribute.dart'; import 'sentry_id.dart'; import 'sentry_log_level.dart'; -class SentryLog implements TelemetryItem { +class SentryLog implements SentryEncodable { DateTime timestamp; SentryId traceId; SentryLogLevel level; diff --git a/packages/dart/lib/src/protocol/span.dart b/packages/dart/lib/src/protocol/span.dart index f3af83d51b..836872c49b 100644 --- a/packages/dart/lib/src/protocol/span.dart +++ b/packages/dart/lib/src/protocol/span.dart @@ -1,12 +1,12 @@ import 'package:meta/meta.dart'; import '../../sentry.dart'; -import '../telemetry_processing/telemetry_item.dart'; +import '../telemetry_processing/sentry_encodable.dart'; // Span specs: https://develop.sentry.dev/sdk/telemetry/spans/span-api/ /// Represents a basic telemetry span. -abstract class Span implements TelemetryItem { +abstract class Span implements SentryEncodable { @internal const Span(); diff --git a/packages/dart/lib/src/telemetry_processing/telemetry_item.dart b/packages/dart/lib/src/telemetry_processing/sentry_encodable.dart similarity index 71% rename from packages/dart/lib/src/telemetry_processing/telemetry_item.dart rename to packages/dart/lib/src/telemetry_processing/sentry_encodable.dart index 2faef1e6f9..cd0570fd0a 100644 --- a/packages/dart/lib/src/telemetry_processing/telemetry_item.dart +++ b/packages/dart/lib/src/telemetry_processing/sentry_encodable.dart @@ -1,6 +1,6 @@ import 'package:meta/meta.dart'; -abstract class TelemetryItem { +abstract class SentryEncodable { @internal Map toJson(); } diff --git a/packages/dart/lib/src/telemetry_processing/telemetry_buffer.dart b/packages/dart/lib/src/telemetry_processing/telemetry_buffer.dart index 31a00e8ff5..f2e5e1ef66 100644 --- a/packages/dart/lib/src/telemetry_processing/telemetry_buffer.dart +++ b/packages/dart/lib/src/telemetry_processing/telemetry_buffer.dart @@ -1,22 +1,24 @@ import 'dart:async'; -import 'telemetry_item.dart'; +import 'sentry_encodable.dart'; -abstract class TelemetryBuffer { +abstract class TelemetryBuffer { void add(T item); FutureOr flush(); } -/// Holds both raw item and encoded bytes for size tracking and grouping. -class EncodedTelemetryItem { +/// Represents an item that is being hold in a buffer. +/// +/// Contains both raw item and encoded bytes for size tracking and grouping. +class BufferedItem { final T item; final List encoded; - EncodedTelemetryItem(this.item, this.encoded); + BufferedItem(this.item, this.encoded); } /// In-memory buffer with time and size-based flushing. -class InMemoryTelemetryBuffer +class InMemoryTelemetryBuffer extends TelemetryBuffer { @override void add(T item) { diff --git a/packages/dart/lib/src/telemetry_processing/telemetry_processor.dart b/packages/dart/lib/src/telemetry_processing/telemetry_processor.dart index 5d1c59ae26..f8b0a87d68 100644 --- a/packages/dart/lib/src/telemetry_processing/telemetry_processor.dart +++ b/packages/dart/lib/src/telemetry_processing/telemetry_processor.dart @@ -4,7 +4,7 @@ import 'package:meta/meta.dart'; import '../../sentry.dart'; import 'telemetry_buffer.dart'; -import 'telemetry_item.dart'; +import 'sentry_encodable.dart'; /// Manages buffering and sending of telemetry data to Sentry. abstract class TelemetryProcessor { @@ -49,7 +49,7 @@ class DefaultTelemetryProcessor implements TelemetryProcessor { @override void addLog(SentryLog log) => _add(log); - void _add(TelemetryItem item) { + void _add(SentryEncodable item) { final buffer = switch (item) { Span() => spanBuffer, SentryLog() => logBuffer, diff --git a/packages/dart/test/mocks/mock_telemetry_buffer.dart b/packages/dart/test/mocks/mock_telemetry_buffer.dart index 75e8b3c437..bfcfb65abd 100644 --- a/packages/dart/test/mocks/mock_telemetry_buffer.dart +++ b/packages/dart/test/mocks/mock_telemetry_buffer.dart @@ -1,9 +1,10 @@ import 'dart:async'; +import 'package:sentry/src/telemetry_processing/sentry_encodable.dart'; import 'package:sentry/src/telemetry_processing/telemetry_buffer.dart'; -import 'package:sentry/src/telemetry_processing/telemetry_item.dart'; -class MockTelemetryBuffer extends TelemetryBuffer { +class MockTelemetryBuffer + extends TelemetryBuffer { final List addedItems = []; int flushCallCount = 0; final bool asyncFlush; From eedfd0b0e4e8174be3c4e8b6e408f91c7d5afb14 Mon Sep 17 00:00:00 2001 From: Giancarlo Buenaflor Date: Wed, 17 Dec 2025 13:16:41 +0100 Subject: [PATCH 14/30] docs(telemetry): Add documentation for SentryEncodable and TelemetryBuffer - Introduced a description for the SentryEncodable interface, clarifying its purpose for JSON serialization. - Added documentation for the TelemetryBuffer class, explaining its functionality in batching telemetry items for efficient transmission to Sentry. --- .../lib/src/telemetry_processing/sentry_encodable.dart | 2 ++ .../lib/src/telemetry_processing/telemetry_buffer.dart | 7 +++++++ 2 files changed, 9 insertions(+) diff --git a/packages/dart/lib/src/telemetry_processing/sentry_encodable.dart b/packages/dart/lib/src/telemetry_processing/sentry_encodable.dart index cd0570fd0a..e49325543a 100644 --- a/packages/dart/lib/src/telemetry_processing/sentry_encodable.dart +++ b/packages/dart/lib/src/telemetry_processing/sentry_encodable.dart @@ -1,6 +1,8 @@ import 'package:meta/meta.dart'; +/// Interface for objects that can be serialized to JSON for Sentry transmission. abstract class SentryEncodable { + /// Converts this object to a JSON-compatible map. @internal Map toJson(); } diff --git a/packages/dart/lib/src/telemetry_processing/telemetry_buffer.dart b/packages/dart/lib/src/telemetry_processing/telemetry_buffer.dart index f2e5e1ef66..6982ebc18e 100644 --- a/packages/dart/lib/src/telemetry_processing/telemetry_buffer.dart +++ b/packages/dart/lib/src/telemetry_processing/telemetry_buffer.dart @@ -2,8 +2,15 @@ import 'dart:async'; import 'sentry_encodable.dart'; +/// A buffer that batches telemetry items for efficient transmission to Sentry. +/// +/// Collects items of type [T] and sends them in batches rather than +/// individually, reducing network overhead. abstract class TelemetryBuffer { + /// Adds an item to the buffer. void add(T item); + + /// Manually sends all buffered items to Sentry and clears the buffer. FutureOr flush(); } From 13955bd6d53acd668388ea0b81e8f95326aef4b2 Mon Sep 17 00:00:00 2001 From: Giancarlo Buenaflor Date: Wed, 17 Dec 2025 13:19:54 +0100 Subject: [PATCH 15/30] refactor(span): Improve traceId inheritance logic in SimpleSpan constructor - Updated the SimpleSpan constructor to conditionally inherit traceId from the parent span only if it is not empty, enhancing trace propagation accuracy. - Simplified the logic for determining the traceId, ensuring clearer and more reliable span behavior. --- packages/dart/lib/src/protocol/simple_span.dart | 4 +++- .../lib/src/telemetry_processing/telemetry_processor.dart | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/packages/dart/lib/src/protocol/simple_span.dart b/packages/dart/lib/src/protocol/simple_span.dart index f545e514fb..01ba105817 100644 --- a/packages/dart/lib/src/protocol/simple_span.dart +++ b/packages/dart/lib/src/protocol/simple_span.dart @@ -23,8 +23,10 @@ class SimpleSpan implements Span { _hub = hub ?? HubAdapter(), _name = name { _segmentSpan = parentSpan?.segmentSpan ?? this; - _traceId = parentSpan?.traceId ?? _hub.scope.propagationContext.traceId; _startTimestamp = _hub.options.clock(); + _traceId = (parentSpan != null && parentSpan!.traceId != SentryId.empty()) + ? parentSpan!.traceId + : _hub.scope.propagationContext.traceId; } @override diff --git a/packages/dart/lib/src/telemetry_processing/telemetry_processor.dart b/packages/dart/lib/src/telemetry_processing/telemetry_processor.dart index f8b0a87d68..3e0a4815b5 100644 --- a/packages/dart/lib/src/telemetry_processing/telemetry_processor.dart +++ b/packages/dart/lib/src/telemetry_processing/telemetry_processor.dart @@ -78,7 +78,7 @@ class DefaultTelemetryProcessor implements TelemetryProcessor { final results = >[ spanBuffer?.flush(), logBuffer?.flush(), - ].whereType>().toList(); + ]; final futures = results.whereType>().toList(); if (futures.isEmpty) { From b5220899ba43d244d9084ece13c635d63aadca80 Mon Sep 17 00:00:00 2001 From: Giancarlo Buenaflor Date: Wed, 17 Dec 2025 13:22:25 +0100 Subject: [PATCH 16/30] fix(span): Ensure endTimestamp is stored in UTC format in SimpleSpan - Updated the assignment of _endTimestamp in SimpleSpan to convert endTimestamp to UTC if provided, ensuring consistent timestamp handling across spans. --- packages/dart/lib/src/protocol/simple_span.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/dart/lib/src/protocol/simple_span.dart b/packages/dart/lib/src/protocol/simple_span.dart index 01ba105817..3c61d1af44 100644 --- a/packages/dart/lib/src/protocol/simple_span.dart +++ b/packages/dart/lib/src/protocol/simple_span.dart @@ -74,7 +74,7 @@ class SimpleSpan implements Span { if (_isFinished) { return; } - _endTimestamp = (endTimestamp ?? _hub.options.clock()); + _endTimestamp = (endTimestamp?.toUtc() ?? _hub.options.clock()); _isFinished = true; _hub.captureSpan(this); } From 8ea876ad46ae9315a51a0d6c36c600a1dbd3c600 Mon Sep 17 00:00:00 2001 From: Giancarlo Buenaflor Date: Wed, 17 Dec 2025 13:31:55 +0100 Subject: [PATCH 17/30] feat(telemetry): Prevent NoOpSpan and UnsetSpan from being added to the buffer - Updated the addSpan method in DefaultTelemetryProcessor to ignore NoOpSpan and UnsetSpan instances, ensuring they are not added to the telemetry buffer. - Added unit tests to verify that NoOpSpan and UnsetSpan cannot be added to the buffer, enhancing the robustness of span handling. --- .../telemetry_processor.dart | 14 ++++--- .../telemetry_processor_test.dart | 39 +++++++++++++------ 2 files changed, 35 insertions(+), 18 deletions(-) diff --git a/packages/dart/lib/src/telemetry_processing/telemetry_processor.dart b/packages/dart/lib/src/telemetry_processing/telemetry_processor.dart index 3e0a4815b5..d2885aece3 100644 --- a/packages/dart/lib/src/telemetry_processing/telemetry_processor.dart +++ b/packages/dart/lib/src/telemetry_processing/telemetry_processor.dart @@ -3,6 +3,8 @@ import 'dart:async'; import 'package:meta/meta.dart'; import '../../sentry.dart'; +import '../protocol/noop_span.dart'; +import '../protocol/unset_span.dart'; import 'telemetry_buffer.dart'; import 'sentry_encodable.dart'; @@ -14,9 +16,6 @@ abstract class TelemetryProcessor { } /// Manages buffering and sending of telemetry data to Sentry. -/// -/// Creates and manages buffers internally based on [SentryOptions] configuration. -/// Buffers are only created when their respective features are enabled. class DefaultTelemetryProcessor implements TelemetryProcessor { final SdkLogCallback _logger; @@ -37,14 +36,17 @@ class DefaultTelemetryProcessor implements TelemetryProcessor { /// Adds a span to the buffer for later transmission. /// - /// If no span buffer is registered, the span is dropped + /// If no span buffer is set, the span is dropped /// and a warning is logged. + /// + /// If span is [NoOpSpan] or [UnsetSpan] it is not added to the buffer. @override - void addSpan(Span span) => _add(span); + void addSpan(Span span) => + (span is NoOpSpan || span is UnsetSpan) ? null : _add(span); /// Adds a log to the buffer for later transmission. /// - /// If no log buffer is registered, the log is dropped + /// If no log buffer is set, the log is dropped /// and a warning is logged. @override void addLog(SentryLog log) => _add(log); diff --git a/packages/dart/test/telemetry_processing/telemetry_processor_test.dart b/packages/dart/test/telemetry_processing/telemetry_processor_test.dart index 2093f13c41..1a164d1cd0 100644 --- a/packages/dart/test/telemetry_processing/telemetry_processor_test.dart +++ b/packages/dart/test/telemetry_processing/telemetry_processor_test.dart @@ -1,7 +1,9 @@ import 'dart:async'; import 'package:sentry/sentry.dart'; +import 'package:sentry/src/protocol/noop_span.dart'; import 'package:sentry/src/protocol/simple_span.dart'; +import 'package:sentry/src/protocol/unset_span.dart'; import 'package:sentry/src/telemetry_processing/telemetry_processor.dart'; import 'package:test/test.dart'; @@ -30,18 +32,6 @@ void main() { expect(mockSpanBuffer.addedItems.first, span); }); - test('handles subtypes correctly (SimpleSpan -> Span buffer)', () { - final mockSpanBuffer = MockTelemetryBuffer(); - final processor = fixture.getSut(spanBuffer: mockSpanBuffer); - - final simpleSpan = fixture.createSpan(); - simpleSpan.end(); - processor.addSpan(simpleSpan); - - expect(mockSpanBuffer.addedItems.length, 1); - expect(mockSpanBuffer.addedItems.first, isA()); - }); - test('does not throw when no span buffer registered', () { final processor = fixture.getSut(); processor.spanBuffer = null; @@ -52,6 +42,26 @@ void main() { // Nothing to assert - just verifying no exception thrown }); + + test('NoOpSpan cannot be added to buffer', () { + final mockSpanBuffer = MockTelemetryBuffer(); + final processor = fixture.getSut(spanBuffer: mockSpanBuffer); + + const noOpSpan = NoOpSpan(); + processor.addSpan(noOpSpan); + + expect(mockSpanBuffer.addedItems, isEmpty); + }); + + test('UnsetSpan cannot be added to buffer', () { + final mockSpanBuffer = MockTelemetryBuffer(); + final processor = fixture.getSut(spanBuffer: mockSpanBuffer); + + const noOpSpan = UnsetSpan(); + processor.addSpan(noOpSpan); + + expect(mockSpanBuffer.addedItems, isEmpty); + }); }); group('addLog', () { @@ -153,6 +163,11 @@ class Fixture { return SimpleSpan(name: name, hub: hub); } + SimpleSpan createChildSpan( + {required Span parent, String name = 'child-span'}) { + return SimpleSpan(name: name, parentSpan: parent, hub: hub); + } + SentryLog createLog({String body = 'test log'}) { return SentryLog( timestamp: DateTime.now().toUtc(), From d54ae8b871c324bfc5b75ae2bf1a31753a8710be Mon Sep 17 00:00:00 2001 From: Giancarlo Buenaflor Date: Wed, 17 Dec 2025 13:33:14 +0100 Subject: [PATCH 18/30] docs(telemetry): Enhance documentation for TelemetryProcessor methods - Added documentation comments for the addSpan, addLog, and flush methods in the TelemetryProcessor interface, clarifying their functionality and usage. - Improved code readability and maintainability by providing clear descriptions of method behaviors and expected outcomes. --- .../telemetry_processing/telemetry_processor.dart | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) diff --git a/packages/dart/lib/src/telemetry_processing/telemetry_processor.dart b/packages/dart/lib/src/telemetry_processing/telemetry_processor.dart index d2885aece3..a3787c9636 100644 --- a/packages/dart/lib/src/telemetry_processing/telemetry_processor.dart +++ b/packages/dart/lib/src/telemetry_processing/telemetry_processor.dart @@ -10,8 +10,13 @@ import 'sentry_encodable.dart'; /// Manages buffering and sending of telemetry data to Sentry. abstract class TelemetryProcessor { + /// Adds a span to the buffer for later transmission. void addSpan(Span span); + + /// Adds a log to the buffer for later transmission. void addLog(SentryLog log); + + /// Flushes all buffers, sending any pending telemetry data. FutureOr flush(); } @@ -34,20 +39,10 @@ class DefaultTelemetryProcessor implements TelemetryProcessor { this.logBuffer, }); - /// Adds a span to the buffer for later transmission. - /// - /// If no span buffer is set, the span is dropped - /// and a warning is logged. - /// - /// If span is [NoOpSpan] or [UnsetSpan] it is not added to the buffer. @override void addSpan(Span span) => (span is NoOpSpan || span is UnsetSpan) ? null : _add(span); - /// Adds a log to the buffer for later transmission. - /// - /// If no log buffer is set, the log is dropped - /// and a warning is logged. @override void addLog(SentryLog log) => _add(log); From 9434be49ab3e02f31dd8906939e7983306f3a09f Mon Sep 17 00:00:00 2001 From: Giancarlo Buenaflor Date: Wed, 17 Dec 2025 13:33:46 +0100 Subject: [PATCH 19/30] docs(telemetry): Remove outdated flush method documentation in DefaultTelemetryProcessor - Deleted the documentation comments for the flush method in DefaultTelemetryProcessor, as they were no longer relevant. - This change helps maintain clarity and accuracy in the codebase by ensuring that documentation reflects the current implementation. --- .../lib/src/telemetry_processing/telemetry_processor.dart | 4 ---- 1 file changed, 4 deletions(-) diff --git a/packages/dart/lib/src/telemetry_processing/telemetry_processor.dart b/packages/dart/lib/src/telemetry_processing/telemetry_processor.dart index a3787c9636..415f49c79f 100644 --- a/packages/dart/lib/src/telemetry_processing/telemetry_processor.dart +++ b/packages/dart/lib/src/telemetry_processing/telemetry_processor.dart @@ -64,10 +64,6 @@ class DefaultTelemetryProcessor implements TelemetryProcessor { buffer.add(item); } - /// Flushes all buffers, sending any pending telemetry data. - /// - /// Returns a [Future] that completes when all buffers have been flushed. - /// Returns immediately if no buffers need flushing. @override FutureOr flush() { _logger(SentryLevel.debug, 'TelemetryProcessor: Flushing buffers'); From cc9815b790e6a7a840c628763a67a8f2b9413c75 Mon Sep 17 00:00:00 2001 From: Giancarlo Buenaflor Date: Wed, 17 Dec 2025 13:38:28 +0100 Subject: [PATCH 20/30] docs(telemetry): Remove outdated constructor documentation in DefaultTelemetryProcessor - Deleted the documentation comment for the constructor in DefaultTelemetryProcessor, as it was no longer relevant. - This change helps maintain clarity and accuracy in the codebase by ensuring that documentation reflects the current implementation. --- .../dart/lib/src/telemetry_processing/telemetry_processor.dart | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/dart/lib/src/telemetry_processing/telemetry_processor.dart b/packages/dart/lib/src/telemetry_processing/telemetry_processor.dart index 415f49c79f..70e43952e8 100644 --- a/packages/dart/lib/src/telemetry_processing/telemetry_processor.dart +++ b/packages/dart/lib/src/telemetry_processing/telemetry_processor.dart @@ -32,7 +32,6 @@ class DefaultTelemetryProcessor implements TelemetryProcessor { @visibleForTesting TelemetryBuffer? logBuffer; - /// Creates a telemetry processor. DefaultTelemetryProcessor( this._logger, { this.spanBuffer, From bcde33e4e85a3bf3ea178a28e4d3e679dcd65d24 Mon Sep 17 00:00:00 2001 From: Giancarlo Buenaflor Date: Wed, 17 Dec 2025 13:46:20 +0100 Subject: [PATCH 21/30] refactor(telemetry): Remove SentryEncodable interface and simplify related classes - Eliminated the SentryEncodable interface, removing its implementation from SentryLog and Span classes. - Updated TelemetryBuffer and its subclasses to no longer depend on SentryEncodable, enhancing type flexibility. - Adjusted related methods to accommodate the removal of the interface, streamlining the telemetry processing codebase. --- packages/dart/lib/src/protocol/sentry_log.dart | 4 +--- packages/dart/lib/src/protocol/simple_span.dart | 1 - packages/dart/lib/src/protocol/span.dart | 6 ++++-- .../src/telemetry_processing/sentry_encodable.dart | 8 -------- .../src/telemetry_processing/telemetry_buffer.dart | 14 ++++++++------ .../telemetry_processing/telemetry_processor.dart | 3 +-- .../dart/test/mocks/mock_telemetry_buffer.dart | 4 +--- 7 files changed, 15 insertions(+), 25 deletions(-) delete mode 100644 packages/dart/lib/src/telemetry_processing/sentry_encodable.dart diff --git a/packages/dart/lib/src/protocol/sentry_log.dart b/packages/dart/lib/src/protocol/sentry_log.dart index 911b9eb027..6612b8d700 100644 --- a/packages/dart/lib/src/protocol/sentry_log.dart +++ b/packages/dart/lib/src/protocol/sentry_log.dart @@ -1,9 +1,8 @@ -import '../telemetry_processing/sentry_encodable.dart'; import 'sentry_attribute.dart'; import 'sentry_id.dart'; import 'sentry_log_level.dart'; -class SentryLog implements SentryEncodable { +class SentryLog { DateTime timestamp; SentryId traceId; SentryLogLevel level; @@ -22,7 +21,6 @@ class SentryLog implements SentryEncodable { this.severityNumber, }) : traceId = traceId ?? SentryId.empty(); - @override Map toJson() { return { 'timestamp': timestamp.toIso8601String(), diff --git a/packages/dart/lib/src/protocol/simple_span.dart b/packages/dart/lib/src/protocol/simple_span.dart index 3c61d1af44..816fe54619 100644 --- a/packages/dart/lib/src/protocol/simple_span.dart +++ b/packages/dart/lib/src/protocol/simple_span.dart @@ -79,7 +79,6 @@ class SimpleSpan implements Span { _hub.captureSpan(this); } - @override Map toJson() { double toUnixSeconds(DateTime timestamp) => timestamp.microsecondsSinceEpoch / 1000000; diff --git a/packages/dart/lib/src/protocol/span.dart b/packages/dart/lib/src/protocol/span.dart index 836872c49b..b1c59cc7af 100644 --- a/packages/dart/lib/src/protocol/span.dart +++ b/packages/dart/lib/src/protocol/span.dart @@ -1,12 +1,11 @@ import 'package:meta/meta.dart'; import '../../sentry.dart'; -import '../telemetry_processing/sentry_encodable.dart'; // Span specs: https://develop.sentry.dev/sdk/telemetry/spans/span-api/ /// Represents a basic telemetry span. -abstract class Span implements SentryEncodable { +abstract class Span { @internal const Span(); @@ -60,4 +59,7 @@ abstract class Span implements SentryEncodable { @internal bool get isFinished; + + @internal + Map toJson(); } diff --git a/packages/dart/lib/src/telemetry_processing/sentry_encodable.dart b/packages/dart/lib/src/telemetry_processing/sentry_encodable.dart deleted file mode 100644 index e49325543a..0000000000 --- a/packages/dart/lib/src/telemetry_processing/sentry_encodable.dart +++ /dev/null @@ -1,8 +0,0 @@ -import 'package:meta/meta.dart'; - -/// Interface for objects that can be serialized to JSON for Sentry transmission. -abstract class SentryEncodable { - /// Converts this object to a JSON-compatible map. - @internal - Map toJson(); -} diff --git a/packages/dart/lib/src/telemetry_processing/telemetry_buffer.dart b/packages/dart/lib/src/telemetry_processing/telemetry_buffer.dart index 6982ebc18e..93914775ba 100644 --- a/packages/dart/lib/src/telemetry_processing/telemetry_buffer.dart +++ b/packages/dart/lib/src/telemetry_processing/telemetry_buffer.dart @@ -1,12 +1,10 @@ import 'dart:async'; -import 'sentry_encodable.dart'; - /// A buffer that batches telemetry items for efficient transmission to Sentry. /// /// Collects items of type [T] and sends them in batches rather than /// individually, reducing network overhead. -abstract class TelemetryBuffer { +abstract class TelemetryBuffer { /// Adds an item to the buffer. void add(T item); @@ -17,7 +15,7 @@ abstract class TelemetryBuffer { /// Represents an item that is being hold in a buffer. /// /// Contains both raw item and encoded bytes for size tracking and grouping. -class BufferedItem { +class BufferedItem { final T item; final List encoded; @@ -25,10 +23,14 @@ class BufferedItem { } /// In-memory buffer with time and size-based flushing. -class InMemoryTelemetryBuffer - extends TelemetryBuffer { +class InMemoryTelemetryBuffer extends TelemetryBuffer { + final Map Function(T) serializer; + + InMemoryTelemetryBuffer({required this.serializer}); + @override void add(T item) { + final serializedItem = serializer(item); // TODO(next-pr) } diff --git a/packages/dart/lib/src/telemetry_processing/telemetry_processor.dart b/packages/dart/lib/src/telemetry_processing/telemetry_processor.dart index 70e43952e8..cbfea2151a 100644 --- a/packages/dart/lib/src/telemetry_processing/telemetry_processor.dart +++ b/packages/dart/lib/src/telemetry_processing/telemetry_processor.dart @@ -6,7 +6,6 @@ import '../../sentry.dart'; import '../protocol/noop_span.dart'; import '../protocol/unset_span.dart'; import 'telemetry_buffer.dart'; -import 'sentry_encodable.dart'; /// Manages buffering and sending of telemetry data to Sentry. abstract class TelemetryProcessor { @@ -45,7 +44,7 @@ class DefaultTelemetryProcessor implements TelemetryProcessor { @override void addLog(SentryLog log) => _add(log); - void _add(SentryEncodable item) { + void _add(dynamic item) { final buffer = switch (item) { Span() => spanBuffer, SentryLog() => logBuffer, diff --git a/packages/dart/test/mocks/mock_telemetry_buffer.dart b/packages/dart/test/mocks/mock_telemetry_buffer.dart index bfcfb65abd..4f7a397e6b 100644 --- a/packages/dart/test/mocks/mock_telemetry_buffer.dart +++ b/packages/dart/test/mocks/mock_telemetry_buffer.dart @@ -1,10 +1,8 @@ import 'dart:async'; -import 'package:sentry/src/telemetry_processing/sentry_encodable.dart'; import 'package:sentry/src/telemetry_processing/telemetry_buffer.dart'; -class MockTelemetryBuffer - extends TelemetryBuffer { +class MockTelemetryBuffer extends TelemetryBuffer { final List addedItems = []; int flushCallCount = 0; final bool asyncFlush; From ed1ce35f524aa085f6c4574614f41d8bc46f0389 Mon Sep 17 00:00:00 2001 From: Giancarlo Buenaflor Date: Wed, 17 Dec 2025 14:42:39 +0100 Subject: [PATCH 22/30] refactor(telemetry): Rename BufferedItem to EncodedItem and update related types - Renamed BufferedItem class to EncodedItem to better reflect its purpose of pairing items with their encoded bytes for size tracking and transmission. - Updated InMemoryTelemetryBuffer to use an ItemEncoder type instead of a serializer function, enhancing clarity in item encoding. - Adjusted the add method to utilize the new encoder, streamlining the telemetry processing workflow. --- .../telemetry_processing/telemetry_buffer.dart | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/packages/dart/lib/src/telemetry_processing/telemetry_buffer.dart b/packages/dart/lib/src/telemetry_processing/telemetry_buffer.dart index 93914775ba..c2fd92cd8d 100644 --- a/packages/dart/lib/src/telemetry_processing/telemetry_buffer.dart +++ b/packages/dart/lib/src/telemetry_processing/telemetry_buffer.dart @@ -12,25 +12,25 @@ abstract class TelemetryBuffer { FutureOr flush(); } -/// Represents an item that is being hold in a buffer. -/// -/// Contains both raw item and encoded bytes for size tracking and grouping. -class BufferedItem { +/// Pairs an item with its encoded bytes for size tracking and transmission. +class EncodedItem { final T item; final List encoded; - BufferedItem(this.item, this.encoded); + EncodedItem(this.item, this.encoded); } +typedef ItemEncoder = List> Function(T item); + /// In-memory buffer with time and size-based flushing. class InMemoryTelemetryBuffer extends TelemetryBuffer { - final Map Function(T) serializer; + final ItemEncoder encoder; - InMemoryTelemetryBuffer({required this.serializer}); + InMemoryTelemetryBuffer({required this.encoder}); @override void add(T item) { - final serializedItem = serializer(item); + final encodedItems = encoder(item); // TODO(next-pr) } From a12ff235b69300803827cc7863c91a2ce14c7efe Mon Sep 17 00:00:00 2001 From: Giancarlo Buenaflor Date: Wed, 17 Dec 2025 14:48:43 +0100 Subject: [PATCH 23/30] refactor(span): Simplify traceId assignment in SimpleSpan constructor - Updated the traceId assignment logic in the SimpleSpan constructor to enhance clarity by removing unnecessary null checks. - Added an override for the toJson method, ensuring proper JSON serialization of the SimpleSpan instance. --- packages/dart/lib/src/protocol/simple_span.dart | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/dart/lib/src/protocol/simple_span.dart b/packages/dart/lib/src/protocol/simple_span.dart index 816fe54619..3d7d86c202 100644 --- a/packages/dart/lib/src/protocol/simple_span.dart +++ b/packages/dart/lib/src/protocol/simple_span.dart @@ -24,7 +24,7 @@ class SimpleSpan implements Span { _name = name { _segmentSpan = parentSpan?.segmentSpan ?? this; _startTimestamp = _hub.options.clock(); - _traceId = (parentSpan != null && parentSpan!.traceId != SentryId.empty()) + _traceId = parentSpan != null ? parentSpan!.traceId : _hub.scope.propagationContext.traceId; } @@ -79,6 +79,7 @@ class SimpleSpan implements Span { _hub.captureSpan(this); } + @override Map toJson() { double toUnixSeconds(DateTime timestamp) => timestamp.microsecondsSinceEpoch / 1000000; From 4d50af0c9ccb2e12b2b1fb0d22be5407457ed302 Mon Sep 17 00:00:00 2001 From: Giancarlo Buenaflor Date: Wed, 17 Dec 2025 15:00:37 +0100 Subject: [PATCH 24/30] refactor(telemetry): Integrate telemetry processing into SentryClient - Added telemetry processing capabilities to SentryClient by introducing DefaultTelemetryProcessor and InMemoryTelemetryBuffer for log and span handling. - Updated the constructor to initialize the telemetry processor, preparing for future removal of the log batcher. - Renamed EncodedItem to BufferedItem to better represent its role in telemetry data management. --- packages/dart/lib/src/sentry_client.dart | 10 +++++++++- .../lib/src/telemetry_processing/telemetry_buffer.dart | 10 +++++----- 2 files changed, 14 insertions(+), 6 deletions(-) diff --git a/packages/dart/lib/src/sentry_client.dart b/packages/dart/lib/src/sentry_client.dart index 146301f9f6..07a639cdf6 100644 --- a/packages/dart/lib/src/sentry_client.dart +++ b/packages/dart/lib/src/sentry_client.dart @@ -18,6 +18,8 @@ import 'sentry_exception_factory.dart'; import 'sentry_options.dart'; import 'sentry_stack_trace_factory.dart'; import 'sentry_trace_context_header.dart'; +import 'telemetry_processing/telemetry_buffer.dart'; +import 'telemetry_processing/telemetry_processor.dart'; import 'transport/client_report_transport.dart'; import 'transport/data_category.dart'; import 'transport/http_transport.dart'; @@ -28,6 +30,7 @@ import 'type_check_hint.dart'; import 'utils/isolate_utils.dart'; import 'utils/regex_utils.dart'; import 'utils/stacktrace_utils.dart'; +import 'utils.dart'; import 'sentry_log_batcher.dart'; import 'version.dart'; @@ -78,7 +81,12 @@ class SentryClient { if (options.enableLogs) { options.logBatcher = SentryLogBatcher(options); } - // TODO(next-pr): wire up telemetry processor and remove log batcher + options.telemetryProcessor = DefaultTelemetryProcessor(options.log, + logBuffer: InMemoryTelemetryBuffer( + encoder: (item) => utf8JsonEncoder.convert(item.toJson())), + spanBuffer: InMemoryTelemetryBuffer( + encoder: (item) => utf8JsonEncoder.convert(item.toJson()))); + // TODO(next-pr): remove log batcher return SentryClient._(options); } diff --git a/packages/dart/lib/src/telemetry_processing/telemetry_buffer.dart b/packages/dart/lib/src/telemetry_processing/telemetry_buffer.dart index c2fd92cd8d..2145d3cef0 100644 --- a/packages/dart/lib/src/telemetry_processing/telemetry_buffer.dart +++ b/packages/dart/lib/src/telemetry_processing/telemetry_buffer.dart @@ -13,24 +13,24 @@ abstract class TelemetryBuffer { } /// Pairs an item with its encoded bytes for size tracking and transmission. -class EncodedItem { +class BufferedItem { final T item; final List encoded; - EncodedItem(this.item, this.encoded); + BufferedItem(this.item, this.encoded); } -typedef ItemEncoder = List> Function(T item); +typedef ItemEncoder = List Function(T item); /// In-memory buffer with time and size-based flushing. class InMemoryTelemetryBuffer extends TelemetryBuffer { - final ItemEncoder encoder; + final ItemEncoder encoder; InMemoryTelemetryBuffer({required this.encoder}); @override void add(T item) { - final encodedItems = encoder(item); + final itemToSend = BufferedItem(item, encoder(item)); // TODO(next-pr) } From 43a8d5a846be2c245985bebf6ac6142ec02e10ea Mon Sep 17 00:00:00 2001 From: Giancarlo Buenaflor Date: Wed, 17 Dec 2025 15:07:03 +0100 Subject: [PATCH 25/30] refactor(telemetry): Implement JsonEncodable interface for telemetry classes - Introduced JsonEncodable interface to standardize JSON serialization across telemetry-related classes. - Updated SentryLog and Span classes to implement the new interface, ensuring consistent toJson method implementation. - Simplified InMemoryTelemetryBuffer by removing the encoder parameter, directly utilizing the toJson method for item encoding. --- packages/dart/lib/src/protocol/sentry_log.dart | 4 +++- packages/dart/lib/src/protocol/span.dart | 4 +++- packages/dart/lib/src/sentry_client.dart | 6 ++---- .../src/telemetry_processing/json_encodable.dart | 3 +++ .../telemetry_processing/telemetry_buffer.dart | 15 ++++++++------- 5 files changed, 19 insertions(+), 13 deletions(-) create mode 100644 packages/dart/lib/src/telemetry_processing/json_encodable.dart diff --git a/packages/dart/lib/src/protocol/sentry_log.dart b/packages/dart/lib/src/protocol/sentry_log.dart index 6612b8d700..eb33430c78 100644 --- a/packages/dart/lib/src/protocol/sentry_log.dart +++ b/packages/dart/lib/src/protocol/sentry_log.dart @@ -1,8 +1,9 @@ +import '../telemetry_processing/json_encodable.dart'; import 'sentry_attribute.dart'; import 'sentry_id.dart'; import 'sentry_log_level.dart'; -class SentryLog { +class SentryLog implements JsonEncodable { DateTime timestamp; SentryId traceId; SentryLogLevel level; @@ -21,6 +22,7 @@ class SentryLog { this.severityNumber, }) : traceId = traceId ?? SentryId.empty(); + @override Map toJson() { return { 'timestamp': timestamp.toIso8601String(), diff --git a/packages/dart/lib/src/protocol/span.dart b/packages/dart/lib/src/protocol/span.dart index b1c59cc7af..b7b3be4480 100644 --- a/packages/dart/lib/src/protocol/span.dart +++ b/packages/dart/lib/src/protocol/span.dart @@ -1,11 +1,12 @@ import 'package:meta/meta.dart'; import '../../sentry.dart'; +import '../telemetry_processing/json_encodable.dart'; // Span specs: https://develop.sentry.dev/sdk/telemetry/spans/span-api/ /// Represents a basic telemetry span. -abstract class Span { +abstract class Span implements JsonEncodable { @internal const Span(); @@ -61,5 +62,6 @@ abstract class Span { bool get isFinished; @internal + @override Map toJson(); } diff --git a/packages/dart/lib/src/sentry_client.dart b/packages/dart/lib/src/sentry_client.dart index 07a639cdf6..d827f2e40a 100644 --- a/packages/dart/lib/src/sentry_client.dart +++ b/packages/dart/lib/src/sentry_client.dart @@ -82,10 +82,8 @@ class SentryClient { options.logBatcher = SentryLogBatcher(options); } options.telemetryProcessor = DefaultTelemetryProcessor(options.log, - logBuffer: InMemoryTelemetryBuffer( - encoder: (item) => utf8JsonEncoder.convert(item.toJson())), - spanBuffer: InMemoryTelemetryBuffer( - encoder: (item) => utf8JsonEncoder.convert(item.toJson()))); + logBuffer: InMemoryTelemetryBuffer(), + spanBuffer: InMemoryTelemetryBuffer()); // TODO(next-pr): remove log batcher return SentryClient._(options); } diff --git a/packages/dart/lib/src/telemetry_processing/json_encodable.dart b/packages/dart/lib/src/telemetry_processing/json_encodable.dart new file mode 100644 index 0000000000..3e85e51e8d --- /dev/null +++ b/packages/dart/lib/src/telemetry_processing/json_encodable.dart @@ -0,0 +1,3 @@ +abstract interface class JsonEncodable { + Map toJson(); +} diff --git a/packages/dart/lib/src/telemetry_processing/telemetry_buffer.dart b/packages/dart/lib/src/telemetry_processing/telemetry_buffer.dart index 2145d3cef0..e4918bf337 100644 --- a/packages/dart/lib/src/telemetry_processing/telemetry_buffer.dart +++ b/packages/dart/lib/src/telemetry_processing/telemetry_buffer.dart @@ -1,5 +1,8 @@ import 'dart:async'; +import '../../sentry.dart'; +import 'json_encodable.dart'; + /// A buffer that batches telemetry items for efficient transmission to Sentry. /// /// Collects items of type [T] and sends them in batches rather than @@ -20,17 +23,15 @@ class BufferedItem { BufferedItem(this.item, this.encoded); } -typedef ItemEncoder = List Function(T item); - /// In-memory buffer with time and size-based flushing. -class InMemoryTelemetryBuffer extends TelemetryBuffer { - final ItemEncoder encoder; - - InMemoryTelemetryBuffer({required this.encoder}); +class InMemoryTelemetryBuffer + extends TelemetryBuffer { + InMemoryTelemetryBuffer(); @override void add(T item) { - final itemToSend = BufferedItem(item, encoder(item)); + final encoded = utf8JsonEncoder.convert(item.toJson()); + final itemToSend = BufferedItem(item, encoded); // TODO(next-pr) } From a072baa69f617e9066113d882118c7cee5d48bbb Mon Sep 17 00:00:00 2001 From: Giancarlo Buenaflor Date: Wed, 17 Dec 2025 15:17:51 +0100 Subject: [PATCH 26/30] refactor(telemetry): Update telemetry buffer implementation and enhance SentryClient tests - Removed unused import from sentry_client.dart to clean up the code. - Updated InMemoryTelemetryBuffer's add method to use a temporary variable for BufferedItem, improving clarity. - Enhanced SentryClient tests by adding a new group to verify the default telemetry processor initialization, ensuring proper setup during client instantiation. --- packages/dart/lib/src/sentry_client.dart | 1 - .../telemetry_processing/telemetry_buffer.dart | 6 +++--- packages/dart/test/sentry_client_test.dart | 18 ++++++++++++++++++ 3 files changed, 21 insertions(+), 4 deletions(-) diff --git a/packages/dart/lib/src/sentry_client.dart b/packages/dart/lib/src/sentry_client.dart index d827f2e40a..167b7f2f4a 100644 --- a/packages/dart/lib/src/sentry_client.dart +++ b/packages/dart/lib/src/sentry_client.dart @@ -30,7 +30,6 @@ import 'type_check_hint.dart'; import 'utils/isolate_utils.dart'; import 'utils/regex_utils.dart'; import 'utils/stacktrace_utils.dart'; -import 'utils.dart'; import 'sentry_log_batcher.dart'; import 'version.dart'; diff --git a/packages/dart/lib/src/telemetry_processing/telemetry_buffer.dart b/packages/dart/lib/src/telemetry_processing/telemetry_buffer.dart index e4918bf337..fe8f3f7ff8 100644 --- a/packages/dart/lib/src/telemetry_processing/telemetry_buffer.dart +++ b/packages/dart/lib/src/telemetry_processing/telemetry_buffer.dart @@ -31,12 +31,12 @@ class InMemoryTelemetryBuffer @override void add(T item) { final encoded = utf8JsonEncoder.convert(item.toJson()); - final itemToSend = BufferedItem(item, encoded); - // TODO(next-pr) + final _ = BufferedItem(item, encoded); + // TODO(next-pr): finish this impl } @override FutureOr flush() { - // TODO(next-pr) + // TODO(next-pr): finish this impl } } diff --git a/packages/dart/test/sentry_client_test.dart b/packages/dart/test/sentry_client_test.dart index 534f665774..d4654f8c70 100644 --- a/packages/dart/test/sentry_client_test.dart +++ b/packages/dart/test/sentry_client_test.dart @@ -11,6 +11,7 @@ import 'package:sentry/src/platform/mock_platform.dart'; import 'package:sentry/src/sentry_item_type.dart'; import 'package:sentry/src/sentry_stack_trace_factory.dart'; import 'package:sentry/src/sentry_tracer.dart'; +import 'package:sentry/src/telemetry_processing/telemetry_processor.dart'; import 'package:sentry/src/transport/client_report_transport.dart'; import 'package:sentry/src/transport/data_category.dart'; import 'package:sentry/src/transport/noop_transport.dart'; @@ -1715,6 +1716,23 @@ void main() { }); }); + group('SentryClient telemetryProcessor', () { + late Fixture fixture; + + setUp(() { + fixture = Fixture(); + }); + + test('sets default telemetry processor when client is initialized', () { + expect(fixture.options.telemetryProcessor, isA()); + + fixture.getSut(); + + expect( + fixture.options.telemetryProcessor, isA()); + }); + }); + group('SentryClient captureLog', () { late Fixture fixture; From 1fb4a80ba60240efac3b97c8816429ceda62fbd0 Mon Sep 17 00:00:00 2001 From: Giancarlo Buenaflor Date: Wed, 17 Dec 2025 16:37:44 +0100 Subject: [PATCH 27/30] refactor(telemetry): Rename flush methods to clear for clarity - Updated TelemetryBuffer and its implementations to rename the flush method to clear, reflecting its functionality of sending and clearing buffered items. - Adjusted SentryClient to include a TODO for future telemetry processor integration. - Enhanced documentation to clarify the purpose of the clear method in telemetry processing. --- packages/dart/lib/src/sentry_client.dart | 1 + .../telemetry_buffer.dart | 6 ++--- .../telemetry_processor.dart | 22 +++++++++---------- 3 files changed, 15 insertions(+), 14 deletions(-) diff --git a/packages/dart/lib/src/sentry_client.dart b/packages/dart/lib/src/sentry_client.dart index 167b7f2f4a..3d9cc8b136 100644 --- a/packages/dart/lib/src/sentry_client.dart +++ b/packages/dart/lib/src/sentry_client.dart @@ -594,6 +594,7 @@ class SentryClient { } FutureOr close() { + // TODO(next-pr): replace with telemetry processor final flush = _options.logBatcher.flush(); if (flush is Future) { return flush.then((_) => _options.httpClient.close()); diff --git a/packages/dart/lib/src/telemetry_processing/telemetry_buffer.dart b/packages/dart/lib/src/telemetry_processing/telemetry_buffer.dart index fe8f3f7ff8..66faafbf9a 100644 --- a/packages/dart/lib/src/telemetry_processing/telemetry_buffer.dart +++ b/packages/dart/lib/src/telemetry_processing/telemetry_buffer.dart @@ -11,8 +11,8 @@ abstract class TelemetryBuffer { /// Adds an item to the buffer. void add(T item); - /// Manually sends all buffered items to Sentry and clears the buffer. - FutureOr flush(); + /// When executed immediately sends all buffered items to Sentry and clears the buffer. + FutureOr clear(); } /// Pairs an item with its encoded bytes for size tracking and transmission. @@ -36,7 +36,7 @@ class InMemoryTelemetryBuffer } @override - FutureOr flush() { + FutureOr clear() { // TODO(next-pr): finish this impl } } diff --git a/packages/dart/lib/src/telemetry_processing/telemetry_processor.dart b/packages/dart/lib/src/telemetry_processing/telemetry_processor.dart index cbfea2151a..db3782ce84 100644 --- a/packages/dart/lib/src/telemetry_processing/telemetry_processor.dart +++ b/packages/dart/lib/src/telemetry_processing/telemetry_processor.dart @@ -9,14 +9,14 @@ import 'telemetry_buffer.dart'; /// Manages buffering and sending of telemetry data to Sentry. abstract class TelemetryProcessor { - /// Adds a span to the buffer for later transmission. + /// Adds a span to the buffer. void addSpan(Span span); - /// Adds a log to the buffer for later transmission. + /// Adds a log to the buffer. void addLog(SentryLog log); - /// Flushes all buffers, sending any pending telemetry data. - FutureOr flush(); + /// Clears all buffers which sends any pending telemetry data. + FutureOr clear(); } /// Manages buffering and sending of telemetry data to Sentry. @@ -46,8 +46,8 @@ class DefaultTelemetryProcessor implements TelemetryProcessor { void _add(dynamic item) { final buffer = switch (item) { - Span() => spanBuffer, - SentryLog() => logBuffer, + Span _ => spanBuffer, + SentryLog _ => logBuffer, _ => null, }; @@ -63,12 +63,12 @@ class DefaultTelemetryProcessor implements TelemetryProcessor { } @override - FutureOr flush() { - _logger(SentryLevel.debug, 'TelemetryProcessor: Flushing buffers'); + FutureOr clear() { + _logger(SentryLevel.debug, 'TelemetryProcessor: Clearing buffers'); final results = >[ - spanBuffer?.flush(), - logBuffer?.flush(), + spanBuffer?.clear(), + logBuffer?.clear(), ]; final futures = results.whereType>().toList(); @@ -88,5 +88,5 @@ class NoOpTelemetryProcessor implements TelemetryProcessor { void addLog(SentryLog log) {} @override - FutureOr flush() {} + FutureOr clear() {} } From 28ff74cf1bfe0bdadef2fcc82ecceae9633142ba Mon Sep 17 00:00:00 2001 From: Giancarlo Buenaflor Date: Wed, 17 Dec 2025 16:41:50 +0100 Subject: [PATCH 28/30] refactor(telemetry): Rename flush method to clear in MockTelemetryBuffer - Updated MockTelemetryBuffer to rename the flush method to clear, aligning with its intended functionality of clearing buffered items. - Adjusted related test cases to reflect the method name change, ensuring consistency across the telemetry processing tests. --- .../dart/test/mocks/mock_telemetry_buffer.dart | 6 +++--- .../telemetry_processor_test.dart | 14 +++++++------- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/packages/dart/test/mocks/mock_telemetry_buffer.dart b/packages/dart/test/mocks/mock_telemetry_buffer.dart index 4f7a397e6b..2f56ea135d 100644 --- a/packages/dart/test/mocks/mock_telemetry_buffer.dart +++ b/packages/dart/test/mocks/mock_telemetry_buffer.dart @@ -4,7 +4,7 @@ import 'package:sentry/src/telemetry_processing/telemetry_buffer.dart'; class MockTelemetryBuffer extends TelemetryBuffer { final List addedItems = []; - int flushCallCount = 0; + int clearCallCount = 0; final bool asyncFlush; MockTelemetryBuffer({this.asyncFlush = false}); @@ -13,8 +13,8 @@ class MockTelemetryBuffer extends TelemetryBuffer { void add(T item) => addedItems.add(item); @override - FutureOr flush() { - flushCallCount++; + FutureOr clear() { + clearCallCount++; if (asyncFlush) { return Future.value(); } diff --git a/packages/dart/test/telemetry_processing/telemetry_processor_test.dart b/packages/dart/test/telemetry_processing/telemetry_processor_test.dart index 1a164d1cd0..55f5087d4c 100644 --- a/packages/dart/test/telemetry_processing/telemetry_processor_test.dart +++ b/packages/dart/test/telemetry_processing/telemetry_processor_test.dart @@ -96,10 +96,10 @@ void main() { logBuffer: mockLogBuffer, ); - await processor.flush(); + await processor.clear(); - expect(mockSpanBuffer.flushCallCount, 1); - expect(mockLogBuffer.flushCallCount, 1); + expect(mockSpanBuffer.clearCallCount, 1); + expect(mockLogBuffer.clearCallCount, 1); }); test('flushes only span buffer when log buffer is null', () async { @@ -107,9 +107,9 @@ void main() { final processor = fixture.getSut(spanBuffer: mockSpanBuffer); processor.logBuffer = null; - await processor.flush(); + await processor.clear(); - expect(mockSpanBuffer.flushCallCount, 1); + expect(mockSpanBuffer.clearCallCount, 1); }); test('returns sync (null) when all buffers flush synchronously', () { @@ -117,7 +117,7 @@ void main() { final processor = fixture.getSut(spanBuffer: mockSpanBuffer); processor.logBuffer = null; - final result = processor.flush(); + final result = processor.clear(); expect(result, isNull); }); @@ -128,7 +128,7 @@ void main() { final processor = fixture.getSut(spanBuffer: mockSpanBuffer); processor.logBuffer = null; - final result = processor.flush(); + final result = processor.clear(); expect(result, isA()); await result; From 3a1904d6dd62ef4c29f19b463de06942a949d01f Mon Sep 17 00:00:00 2001 From: Giancarlo Buenaflor Date: Wed, 17 Dec 2025 16:53:02 +0100 Subject: [PATCH 29/30] refactor(telemetry): Update futures type in telemetry processor - Changed the type of futures in DefaultTelemetryProcessor from Future to Future, allowing for more flexibility in handling future results. - This adjustment improves the clarity and usability of the telemetry processing logic. --- .../dart/lib/src/telemetry_processing/telemetry_processor.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/dart/lib/src/telemetry_processing/telemetry_processor.dart b/packages/dart/lib/src/telemetry_processing/telemetry_processor.dart index db3782ce84..378349bc33 100644 --- a/packages/dart/lib/src/telemetry_processing/telemetry_processor.dart +++ b/packages/dart/lib/src/telemetry_processing/telemetry_processor.dart @@ -71,7 +71,7 @@ class DefaultTelemetryProcessor implements TelemetryProcessor { logBuffer?.clear(), ]; - final futures = results.whereType>().toList(); + final futures = results.whereType().toList(); if (futures.isEmpty) { return null; } From ff13cc4f4221346cea5d6c37c0a944cacbdbc9e9 Mon Sep 17 00:00:00 2001 From: Giancarlo Buenaflor Date: Wed, 17 Dec 2025 18:08:14 +0100 Subject: [PATCH 30/30] refactor(telemetry): Rename asyncFlush to asyncClear in MockTelemetryBuffer - Updated the MockTelemetryBuffer class to rename the asyncFlush parameter to asyncClear, aligning with the method's functionality of clearing items. - Adjusted related test cases to reflect this change, ensuring consistency in the telemetry processing tests. --- packages/dart/test/mocks/mock_telemetry_buffer.dart | 6 +++--- .../test/telemetry_processing/telemetry_processor_test.dart | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/packages/dart/test/mocks/mock_telemetry_buffer.dart b/packages/dart/test/mocks/mock_telemetry_buffer.dart index 2f56ea135d..9ff63de2be 100644 --- a/packages/dart/test/mocks/mock_telemetry_buffer.dart +++ b/packages/dart/test/mocks/mock_telemetry_buffer.dart @@ -5,9 +5,9 @@ import 'package:sentry/src/telemetry_processing/telemetry_buffer.dart'; class MockTelemetryBuffer extends TelemetryBuffer { final List addedItems = []; int clearCallCount = 0; - final bool asyncFlush; + final bool asyncClear; - MockTelemetryBuffer({this.asyncFlush = false}); + MockTelemetryBuffer({this.asyncClear = false}); @override void add(T item) => addedItems.add(item); @@ -15,7 +15,7 @@ class MockTelemetryBuffer extends TelemetryBuffer { @override FutureOr clear() { clearCallCount++; - if (asyncFlush) { + if (asyncClear) { return Future.value(); } return null; diff --git a/packages/dart/test/telemetry_processing/telemetry_processor_test.dart b/packages/dart/test/telemetry_processing/telemetry_processor_test.dart index 55f5087d4c..5e62c14a82 100644 --- a/packages/dart/test/telemetry_processing/telemetry_processor_test.dart +++ b/packages/dart/test/telemetry_processing/telemetry_processor_test.dart @@ -113,7 +113,7 @@ void main() { }); test('returns sync (null) when all buffers flush synchronously', () { - final mockSpanBuffer = MockTelemetryBuffer(asyncFlush: false); + final mockSpanBuffer = MockTelemetryBuffer(asyncClear: false); final processor = fixture.getSut(spanBuffer: mockSpanBuffer); processor.logBuffer = null; @@ -124,7 +124,7 @@ void main() { test('returns Future when at least one buffer flushes asynchronously', () async { - final mockSpanBuffer = MockTelemetryBuffer(asyncFlush: true); + final mockSpanBuffer = MockTelemetryBuffer(asyncClear: true); final processor = fixture.getSut(spanBuffer: mockSpanBuffer); processor.logBuffer = null;