|
1 | 1 | import 'dart:async'; |
2 | | -import 'sentry_envelope.dart'; |
3 | 2 | import 'sentry_options.dart'; |
4 | 3 | import 'protocol/sentry_log.dart'; |
| 4 | +import 'protocol/sentry_level.dart'; |
| 5 | +import 'sentry_envelope.dart'; |
| 6 | +import 'utils.dart'; |
5 | 7 | import 'package:meta/meta.dart'; |
6 | 8 |
|
7 | 9 | @internal |
8 | 10 | class SentryLogBatcher { |
9 | | - SentryLogBatcher(this._options, {Duration? flushTimeout, int? maxBufferSize}) |
10 | | - : _flushTimeout = flushTimeout ?? Duration(seconds: 5), |
11 | | - _maxBufferSize = maxBufferSize ?? 100; |
| 11 | + SentryLogBatcher( |
| 12 | + this._options, { |
| 13 | + Duration? flushTimeout, |
| 14 | + int? maxBufferSizeBytes, |
| 15 | + }) : _flushTimeout = flushTimeout ?? Duration(seconds: 5), |
| 16 | + _maxBufferSizeBytes = maxBufferSizeBytes ?? |
| 17 | + 1024 * 1024; // 1MB default per BatchProcessor spec |
12 | 18 |
|
13 | 19 | final SentryOptions _options; |
14 | 20 | final Duration _flushTimeout; |
15 | | - final int _maxBufferSize; |
| 21 | + final int _maxBufferSizeBytes; |
16 | 22 |
|
17 | | - final _logBuffer = <SentryLog>[]; |
| 23 | + // Store encoded log data instead of raw logs to avoid re-serialization |
| 24 | + final List<List<int>> _encodedLogs = []; |
| 25 | + int _encodedLogsSize = 0; |
18 | 26 |
|
19 | 27 | Timer? _flushTimer; |
20 | 28 |
|
| 29 | + /// Adds a log to the buffer. |
21 | 30 | void addLog(SentryLog log) { |
22 | | - _logBuffer.add(log); |
| 31 | + try { |
| 32 | + final encodedLog = utf8JsonEncoder.convert(log.toJson()); |
23 | 33 |
|
24 | | - _flushTimer?.cancel(); |
| 34 | + _encodedLogs.add(encodedLog); |
| 35 | + _encodedLogsSize += encodedLog.length; |
25 | 36 |
|
26 | | - if (_logBuffer.length >= _maxBufferSize) { |
27 | | - return flush(); |
28 | | - } else { |
29 | | - _flushTimer = Timer(_flushTimeout, flush); |
| 37 | + // Flush if size threshold is reached |
| 38 | + if (_encodedLogsSize >= _maxBufferSizeBytes) { |
| 39 | + // Buffer size exceeded, flush immediately |
| 40 | + _performFlushLogs(); |
| 41 | + } else if (_flushTimer == null) { |
| 42 | + // Start timeout only when first item is added |
| 43 | + _startTimer(); |
| 44 | + } |
| 45 | + // Note: We don't restart the timer on subsequent additions per spec |
| 46 | + } catch (error) { |
| 47 | + _options.log( |
| 48 | + SentryLevel.error, |
| 49 | + 'Failed to encode log: $error', |
| 50 | + ); |
30 | 51 | } |
31 | 52 | } |
32 | 53 |
|
| 54 | + /// Flushes the buffer immediately, sending all buffered logs. |
33 | 55 | void flush() { |
| 56 | + _performFlushLogs(); |
| 57 | + } |
| 58 | + |
| 59 | + void _startTimer() { |
| 60 | + _flushTimer = Timer(_flushTimeout, () { |
| 61 | + _options.log( |
| 62 | + SentryLevel.debug, |
| 63 | + 'SentryLogBatcher: Timer fired, calling performCaptureLogs().', |
| 64 | + ); |
| 65 | + _performFlushLogs(); |
| 66 | + }); |
| 67 | + } |
| 68 | + |
| 69 | + void _performFlushLogs() { |
| 70 | + // Reset timer state first |
34 | 71 | _flushTimer?.cancel(); |
35 | 72 | _flushTimer = null; |
36 | 73 |
|
37 | | - final logs = List<SentryLog>.from(_logBuffer); |
38 | | - _logBuffer.clear(); |
| 74 | + // Reset buffer on function exit |
| 75 | + final logsToSend = List<List<int>>.from(_encodedLogs); |
| 76 | + _encodedLogs.clear(); |
| 77 | + _encodedLogsSize = 0; |
39 | 78 |
|
40 | | - if (logs.isEmpty) { |
| 79 | + if (logsToSend.isEmpty) { |
| 80 | + _options.log( |
| 81 | + SentryLevel.debug, |
| 82 | + 'SentryLogBatcher: No logs to flush.', |
| 83 | + ); |
41 | 84 | return; |
42 | 85 | } |
43 | 86 |
|
44 | | - final envelope = SentryEnvelope.fromLogs( |
45 | | - logs, |
46 | | - _options.sdk, |
47 | | - ); |
48 | | - |
49 | | - // TODO: Make sure the Android SDK understands the log envelope type. |
50 | | - _options.transport.send(envelope); |
| 87 | + try { |
| 88 | + final envelope = SentryEnvelope.fromLogsData(logsToSend, _options.sdk); |
| 89 | + _options.transport.send(envelope); |
| 90 | + } catch (error) { |
| 91 | + _options.log( |
| 92 | + SentryLevel.error, |
| 93 | + 'Failed to send batched logs: $error', |
| 94 | + ); |
| 95 | + } |
51 | 96 | } |
52 | 97 | } |
0 commit comments