Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
79 commits
Select commit Hold shift + click to select a range
481ddd5
Add melos setup and check only set up Dart for now
buenaflor Jul 29, 2025
82fa1bc
Update
buenaflor Jul 30, 2025
af3e3ee
Update]
buenaflor Jul 30, 2025
7734657
Update]
buenaflor Jul 30, 2025
b5e5b42
Update
buenaflor Jul 30, 2025
75e40d4
Update
buenaflor Jul 30, 2025
086519b
Update
buenaflor Jul 30, 2025
f977b38
Fix CHANGELOG
buenaflor Aug 5, 2025
ecce8da
Update gitignore
buenaflor Aug 5, 2025
c692b29
Fix symlink in CHANGELOG
buenaflor Aug 5, 2025
9d5b607
melos setup #1: initial set up and start with dart package (#3117)
buenaflor Aug 5, 2025
0cae93e
Add logging to melos
buenaflor Aug 5, 2025
1d983dd
Update
buenaflor Aug 5, 2025
030fb25
Merge branch 'umbrella/melos' into chore/melos/logging
buenaflor Aug 5, 2025
831a6de
Update
buenaflor Aug 5, 2025
412240d
Update
buenaflor Aug 5, 2025
26ec9b8
Update
buenaflor Aug 5, 2025
33a6226
Add dio to packages
buenaflor Aug 5, 2025
f0b3ecf
Update workflow
buenaflor Aug 5, 2025
17289a5
Update
buenaflor Aug 5, 2025
feb0e3f
Update
buenaflor Aug 5, 2025
4bc5a30
Update
buenaflor Aug 5, 2025
dae9306
Update
buenaflor Aug 5, 2025
7cc04b4
Update
buenaflor Aug 5, 2025
0706b8a
Add hive to packages
buenaflor Aug 5, 2025
47ea449
Update
buenaflor Aug 5, 2025
0679ecf
Add file to packages
buenaflor Aug 5, 2025
784ef2d
Add link to packages
buenaflor Aug 5, 2025
f5a74a7
Update
buenaflor Aug 5, 2025
326b809
Update
buenaflor Aug 5, 2025
1364687
Update
buenaflor Aug 5, 2025
b7af752
Update
buenaflor Aug 5, 2025
e3e05e5
Fix test
buenaflor Aug 5, 2025
ea6336a
Fix test
buenaflor Aug 5, 2025
ccbc158
Fix test
buenaflor Aug 5, 2025
049e3dc
Fix test
buenaflor Aug 5, 2025
476b8ed
Fix test
buenaflor Aug 5, 2025
2f0529d
Add flutter to packages
buenaflor Aug 5, 2025
de2a130
Update
buenaflor Aug 5, 2025
9e8d113
Update
buenaflor Aug 5, 2025
00c8f61
Update
buenaflor Aug 5, 2025
ff47526
Update
buenaflor Aug 5, 2025
01e4133
Update
buenaflor Aug 5, 2025
387477d
Update
buenaflor Aug 5, 2025
0e5657b
Update
buenaflor Aug 5, 2025
433eb78
Update
buenaflor Aug 5, 2025
070f3ce
Update
buenaflor Aug 5, 2025
ef1c5fc
Update
buenaflor Aug 5, 2025
78247fc
Update
buenaflor Aug 5, 2025
020d1f9
Update
buenaflor Aug 5, 2025
238abad
Update
buenaflor Aug 5, 2025
4e1f46d
Update
buenaflor Aug 5, 2025
f5ecc24
Update
buenaflor Aug 5, 2025
a4f63fa
Update
buenaflor Aug 5, 2025
7d8578e
Clean up
buenaflor Aug 5, 2025
1c76782
melos #2: logging package (#3129)
buenaflor Aug 6, 2025
2a79d62
melos #3: dio (#3130)
buenaflor Aug 6, 2025
641a7b6
melos #4: hive (#3131)
buenaflor Aug 6, 2025
edc0ba4
melos #5: file (#3132)
buenaflor Aug 6, 2025
e2d836a
melos #6: link (#3133)
buenaflor Aug 6, 2025
775ac23
melos #7: drift (#3134)
buenaflor Aug 6, 2025
9b0fcee
melos #8: flutter (#3135)
buenaflor Aug 6, 2025
3c34547
melos #9: isar (#3136)
buenaflor Aug 6, 2025
c51192f
melos #10: sqflite (#3137)
buenaflor Aug 6, 2025
5f8892d
melos #11: firebase remote config (#3139)
buenaflor Aug 6, 2025
76b8309
Merge branch 'umbrella/melos' into chore/melos/general-cleanup
buenaflor Aug 6, 2025
057fade
Updaet
buenaflor Aug 6, 2025
cc55001
Updaet
buenaflor Aug 6, 2025
656cce4
Update
buenaflor Aug 6, 2025
9da64c1
Merge branch 'main' into umbrella/melos
buenaflor Aug 6, 2025
3706b67
Merge branch 'umbrella/melos' into chore/melos/general-cleanup
buenaflor Aug 6, 2025
44d2e92
melos #12: general cleanup (#3142)
buenaflor Aug 6, 2025
455f4f2
Update
buenaflor Aug 6, 2025
f4bcadf
Update
buenaflor Aug 6, 2025
a3da850
Merge branch 'umbrella/melos' into enh/new-envelope-builder
buenaflor Aug 6, 2025
92368ca
update
buenaflor Aug 6, 2025
6a048d4
update
buenaflor Aug 6, 2025
1d65777
Merge branch 'umbrella/melos' into enh/new-envelope-builder
buenaflor Aug 6, 2025
e66fb57
Merge branch 'main' into enh/new-envelope-builder
buenaflor Aug 6, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,10 @@

- Tag all spans with thread info ([#3101](https://github.com/getsentry/sentry-dart/pull/3101))

### Enhancements

- Improve envelope conversion to `Uint8List` in `FileSystemTransport` ([#3147](https://github.com/getsentry/sentry-dart/pull/3147))

## 9.6.0

Note: this release might require updating your Android Gradle Plugin version to at least `8.1.4`.
Expand Down
15 changes: 6 additions & 9 deletions packages/flutter/lib/src/file_system_transport.dart
Original file line number Diff line number Diff line change
@@ -1,9 +1,5 @@
// backcompatibility for Flutter < 3.3
// ignore: unnecessary_import
import 'dart:typed_data';

import 'package:flutter/services.dart';

import '../sentry_flutter.dart';
import 'native/sentry_native_binding.dart';

Expand All @@ -15,12 +11,13 @@ class FileSystemTransport implements Transport {

@override
Future<SentryId?> send(SentryEnvelope envelope) async {
final envelopeData = <int>[];
await envelope.envelopeStream(_options).forEach(envelopeData.addAll);
final bytesBuilder = BytesBuilder(copy: false);
await envelope.envelopeStream(_options).forEach(bytesBuilder.add);
final envelopeData = bytesBuilder.takeBytes();

try {
// TODO avoid copy
await _native.captureEnvelope(Uint8List.fromList(envelopeData),
envelope.containsUnhandledException);
await _native.captureEnvelope(
envelopeData, envelope.containsUnhandledException);
} catch (exception, stackTrace) {
_options.log(
SentryLevel.error,
Expand Down
2 changes: 2 additions & 0 deletions packages/flutter/microbenchmarks/lib/main.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import 'dart:io';
import 'src/image_bench.dart' as image_bench;
import 'src/memory_bench.dart' as memory_bench;
import 'src/jni_bench.dart' as jni_bench;
import 'src/envelope_builder_bench.dart' as envelope_builder_bench;

typedef BenchmarkSet = (String name, Future<void> Function() callback);

Expand All @@ -12,6 +13,7 @@ Future<void> main() async {
('Image', image_bench.execute),
('Memory', memory_bench.execute),
if (Platform.isAndroid) ('JNI', jni_bench.execute),
('Envelope builder', envelope_builder_bench.execute)
];

RegExp? filterRegexp;
Expand Down
174 changes: 174 additions & 0 deletions packages/flutter/microbenchmarks/lib/src/envelope_builder_bench.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,174 @@
import 'dart:typed_data';
import 'dart:math';

const _minIterations = 50;
const _maxIterations = 1000;

Future<void> execute() async {
print('Envelope Builder Benchmark');
print('==========================');
print('Comparing legacy List<int> vs BytesBuilder approaches\n');

// Test with different envelope sizes
final sizes = [
(1024, '1 KB'),
(10 * 1024, '10 KB'),
(100 * 1024, '100 KB'),
(1024 * 1024, '1 MB'),
(5 * 1024 * 1024, '5 MB'),
];

for (final (size, label) in sizes) {
print('Envelope size: $label');
print('-' * 40);

// Use adaptive iteration count based on data size
final iterations = _getIterationCount(size);
print('Running $iterations iterations...');

// Create mock envelope data
final mockData = _generateMockEnvelopeData(size);

// Benchmark legacy approach
final legacyResults = await _benchmarkLegacyApproach(mockData, iterations);
final legacyAvg =
legacyResults.reduce((a, b) => a + b) / legacyResults.length;
final legacyMin = legacyResults.reduce(min);
final legacyMax = legacyResults.reduce(max);

// Benchmark new approach
final newResults = await _benchmarkNewApproach(mockData, iterations);
final newAvg = newResults.reduce((a, b) => a + b) / newResults.length;
final newMin = newResults.reduce(min);
final newMax = newResults.reduce(max);

// Calculate improvement
final improvement =
((legacyAvg - newAvg) / legacyAvg * 100).toStringAsFixed(1);
final speedup = (legacyAvg / newAvg).toStringAsFixed(2);

print('Legacy approach (List<int> + addAll):');
print(' Average: ${_formatMicroseconds(legacyAvg)}');
print(' Min: ${_formatMicroseconds(legacyMin)}');
print(' Max: ${_formatMicroseconds(legacyMax)}');

print('New approach (BytesBuilder):');
print(' Average: ${_formatMicroseconds(newAvg)}');
print(' Min: ${_formatMicroseconds(newMin)}');
print(' Max: ${_formatMicroseconds(newMax)}');

print('Performance improvement: $improvement% (${speedup}x faster)');
print('');
}
}

// Adaptive iteration count to avoid memory pressure and hanging
int _getIterationCount(int dataSize) {
if (dataSize <= 10 * 1024) {
return _maxIterations; // 1K iterations for <= 10KB
} else if (dataSize <= 100 * 1024) {
return _maxIterations ~/ 2; // 500 iterations for <= 100KB
} else if (dataSize <= 1024 * 1024) {
return _maxIterations ~/ 5; // 200 iterations for <= 1MB
} else {
return _minIterations; // 50 iterations for > 1MB
}
}

// Generate mock envelope data chunks to simulate streaming
List<List<int>> _generateMockEnvelopeData(int totalSize) {
final chunks = <List<int>>[];
final random = Random(42); // Fixed seed for reproducibility

// Simulate realistic chunk sizes (similar to how envelope streams work)
final chunkSizes = [64, 128, 256, 512, 1024];
var remaining = totalSize;

while (remaining > 0) {
final chunkSize = chunkSizes[random.nextInt(chunkSizes.length)];
final actualSize = remaining < chunkSize ? remaining : chunkSize;

// Create chunk with random data
final chunk = List<int>.generate(actualSize, (_) => random.nextInt(256));
chunks.add(chunk);
remaining -= actualSize;
}

return chunks;
}

Future<List<double>> _benchmarkLegacyApproach(
List<List<int>> chunks, int iterations) async {
final results = <double>[];

// Reduced warmup for large data
final warmupIterations = min(20, iterations ~/ 5);

// Warmup
for (var i = 0; i < warmupIterations; i++) {
_runLegacyApproach(chunks);
}

// Actual benchmark
for (var i = 0; i < iterations; i++) {
final stopwatch = Stopwatch()..start();
_runLegacyApproach(chunks);
stopwatch.stop();
results.add(stopwatch.elapsedMicroseconds.toDouble());
}

return results;
}

Future<List<double>> _benchmarkNewApproach(
List<List<int>> chunks, int iterations) async {
final results = <double>[];

// Reduced warmup for large data
final warmupIterations = min(20, iterations ~/ 5);

// Warmup
for (var i = 0; i < warmupIterations; i++) {
_runNewApproach(chunks);
}

// Actual benchmark
for (var i = 0; i < iterations; i++) {
final stopwatch = Stopwatch()..start();
_runNewApproach(chunks);
stopwatch.stop();
results.add(stopwatch.elapsedMicroseconds.toDouble());
}

return results;
}

Uint8List _runLegacyApproach(List<List<int>> chunks) {
final envelopeData = <int>[];
for (final chunk in chunks) {
envelopeData.addAll(chunk);
}
return Uint8List.fromList(envelopeData);
}

Uint8List _runNewApproach(List<List<int>> chunks) {
final builder = BytesBuilder(copy: false);
for (final chunk in chunks) {
builder.add(chunk);
}
return builder.takeBytes();
}

String _formatMicroseconds(double microseconds) {
if (microseconds < 1000) {
return '${microseconds.toStringAsFixed(1)} μs';
} else if (microseconds < 1000000) {
return '${(microseconds / 1000).toStringAsFixed(2)} ms';
} else {
return '${(microseconds / 1000000).toStringAsFixed(2)} s';
}
}

void main() async {
await execute();
}
Loading