@@ -32,7 +32,7 @@ import 'package:meta/meta.dart';
32
32
// The maximum number of log events in a batch is 10,000.
33
33
34
34
const int _maxNumberOfLogEventsInBatch = 10000 ;
35
- const int _maxLogEventsTimeSpanInBatch = 24 * 3600 ;
35
+ const int _maxLogEventsTimeSpanInBatch = 24 * 3600 * 1000 ;
36
36
const int _maxLogEventsBatchSize = 1048576 ;
37
37
const int _baseBufferSize = 26 ;
38
38
const int _maxLogEventSize = 256000 ;
@@ -138,51 +138,26 @@ class CloudWatchLoggerPlugin extends AWSLoggerPlugin
138
138
139
139
Future <void > _startSyncingIfNotInProgress () async {
140
140
Future <void > startSyncing () async {
141
- String logStream;
142
- try {
143
- logStream = await _logStreamProvider.logStream;
144
- } on Exception catch (e) {
145
- if (await _logStore.isFull (_pluginConfig.localStoreMaxSizeInMB)) {
146
- await _logStore.clear ();
147
- logger.warn (
148
- 'Reached local store max size of: '
149
- '${_pluginConfig .localStoreMaxSizeInMB }.Hence logs are deleted from '
150
- 'local store.' ,
151
- );
152
- }
153
- logger.error ('Failed to create CloudWatch log stream' , e);
154
- return ;
155
- }
156
-
157
141
final batcheStream = _getLogBatchesToSync ();
158
142
await for (final (logs, events) in batcheStream) {
159
- try {
160
- final response = await _sendToCloudWatch (events, logStream);
161
- if (response.rejectedLogEventsInfo? .tooNewLogEventStartIndex !=
162
- null ) {
163
- break ;
164
- }
165
- await _logStore.deleteItems (logs);
166
- } on Exception catch (e) {
167
- if (await _logStore.isFull (_pluginConfig.localStoreMaxSizeInMB)) {
168
- await _logStore.deleteItems (logs);
169
- logger.warn (
170
- 'Reached local store max size of: '
171
- '${_pluginConfig .localStoreMaxSizeInMB }.Hence logs are deleted '
172
- 'from local store.' ,
173
- );
174
- }
175
- logger.error ('Failed to sync batched logs to CloudWatch' , e);
143
+ final response = await _sendToCloudWatch (events);
144
+ if (response.rejectedLogEventsInfo? .tooNewLogEventStartIndex != null ) {
145
+ throw _TooNewLogEventException (
146
+ 'logs can not be more than 2 hours in the future' ,
147
+ );
176
148
}
149
+ await _logStore.deleteItems (logs);
177
150
}
178
151
}
179
152
180
153
if (! _syncing) {
154
+ // TODO(nikahsn): disable log rotation.
181
155
_syncing = true ;
182
156
try {
183
157
await startSyncing ();
184
158
} on Exception catch (e) {
185
159
logger.error ('Failed to sync logs to CloudWatch.' , e);
160
+ // TODO(nikahsn): enable log rotation if the log store is full
186
161
} finally {
187
162
_syncing = false ;
188
163
}
@@ -200,43 +175,49 @@ class CloudWatchLoggerPlugin extends AWSLoggerPlugin
200
175
201
176
Future <PutLogEventsResponse > _sendToCloudWatch (
202
177
List <InputLogEvent > logEvents,
203
- String logStreamName,
204
178
) async {
179
+ final logStreamName = await _logStreamProvider.logStream;
205
180
final request = PutLogEventsRequest (
206
181
logGroupName: _pluginConfig.logGroupName,
207
182
logStreamName: logStreamName,
208
183
logEvents: logEvents,
209
184
);
210
- return _client.putLogEvents (request).result;
185
+ try {
186
+ return _client.putLogEvents (request).result;
187
+ } on ResourceNotFoundException {
188
+ await _logStreamProvider.createLogStream (logStreamName);
189
+ return _client.putLogEvents (request).result;
190
+ } on Exception {
191
+ rethrow ;
192
+ }
211
193
}
212
194
213
195
Stream <_LogBatch > _getLogBatchesToSync () async * {
214
196
final queuedLogs = (await _logStore.getAll ()).toList ();
215
- if (queuedLogs.isEmpty) {
216
- yield ([], []);
217
- }
218
- final logEvents = < InputLogEvent > [];
219
- final logQueues = < QueuedItem > [];
220
- var totalByteSize = 0 ;
221
-
222
- for (final currentLog in queuedLogs) {
223
- final currentLogEvent = currentLog.toInputLogEvent ();
224
- final size = currentLogEvent.message.length + _baseBufferSize;
225
- if (totalByteSize + size >= _maxLogEventsBatchSize ||
226
- logEvents.length >= _maxNumberOfLogEventsInBatch ||
227
- (logEvents.length > 1 &&
228
- currentLogEvent.timestamp - logEvents.first.timestamp >=
229
- _maxLogEventsTimeSpanInBatch)) {
230
- yield (logQueues, logEvents);
231
- totalByteSize = 0 ;
232
- logEvents.clear ();
233
- logQueues.clear ();
197
+ if (queuedLogs.isNotEmpty) {
198
+ final logEvents = < InputLogEvent > [];
199
+ final logQueues = < QueuedItem > [];
200
+ var totalByteSize = 0 ;
201
+
202
+ for (final currentLog in queuedLogs) {
203
+ final currentLogEvent = currentLog.toInputLogEvent ();
204
+ final size = currentLogEvent.message.length + _baseBufferSize;
205
+ if (totalByteSize + size >= _maxLogEventsBatchSize ||
206
+ logEvents.length >= _maxNumberOfLogEventsInBatch ||
207
+ (logEvents.length > 1 &&
208
+ currentLogEvent.timestamp - logEvents.first.timestamp >=
209
+ _maxLogEventsTimeSpanInBatch)) {
210
+ yield (logQueues, logEvents);
211
+ totalByteSize = 0 ;
212
+ logEvents.clear ();
213
+ logQueues.clear ();
214
+ }
215
+ totalByteSize += size;
216
+ logEvents.add (currentLogEvent);
217
+ logQueues.add (currentLog);
234
218
}
235
- totalByteSize += size;
236
- logEvents.add (currentLogEvent);
237
- logQueues.add (currentLog);
219
+ yield (logQueues, logEvents);
238
220
}
239
- yield (logQueues, logEvents);
240
221
}
241
222
242
223
/// Whether a [logEntry] should be logged by this plugin.
@@ -314,3 +295,8 @@ extension on LogEntry {
314
295
);
315
296
}
316
297
}
298
+
299
+ class _TooNewLogEventException implements Exception {
300
+ _TooNewLogEventException (this .message);
301
+ final String message;
302
+ }
0 commit comments