From eda0a6ab926e6aa82fda18f9e51327984b396efc Mon Sep 17 00:00:00 2001 From: NikaHsn Date: Tue, 12 Sep 2023 16:28:07 -0700 Subject: [PATCH 01/49] feat(logging): enable log rotation and set retry on full log store sync (#3699) * feat(logging): enable log rotation and set retry --- .../dart_queued_item_store.stub.dart | 2 +- .../dart_queued_item_store.vm.dart | 2 +- .../dart_queued_item_store.web.dart | 24 +- .../drift/drift_queued_item_store.dart | 2 +- .../index_db/indexed_db_adapter.dart | 7 +- .../test/queued_item_store_test.dart | 4 +- .../lib/src/cloudwatch_logger_plugin.dart | 126 ++++- .../queued_item_store/queued_item_store.dart | 2 +- .../test/cloudwatch_logger_plugin_test.dart | 451 +++++++++++++++++- .../queued_item_store_test.dart | 4 +- 10 files changed, 574 insertions(+), 50 deletions(-) diff --git a/packages/logging_cloudwatch/amplify_logging_cloudwatch/lib/src/queued_item_store/dart_queued_item_store.stub.dart b/packages/logging_cloudwatch/amplify_logging_cloudwatch/lib/src/queued_item_store/dart_queued_item_store.stub.dart index 74f5ac28b97..9e9fd28c3f1 100644 --- a/packages/logging_cloudwatch/amplify_logging_cloudwatch/lib/src/queued_item_store/dart_queued_item_store.stub.dart +++ b/packages/logging_cloudwatch/amplify_logging_cloudwatch/lib/src/queued_item_store/dart_queued_item_store.stub.dart @@ -42,7 +42,7 @@ class DartQueuedItemStore implements QueuedItemStore, Closeable { } @override - FutureOr isFull(int maxSizeInMB) { + bool isFull(int maxSizeInMB) { throw UnimplementedError('isFull() has not been implemented.'); } diff --git a/packages/logging_cloudwatch/amplify_logging_cloudwatch/lib/src/queued_item_store/dart_queued_item_store.vm.dart b/packages/logging_cloudwatch/amplify_logging_cloudwatch/lib/src/queued_item_store/dart_queued_item_store.vm.dart index 627213d0e22..7acc8ee13c7 100644 --- a/packages/logging_cloudwatch/amplify_logging_cloudwatch/lib/src/queued_item_store/dart_queued_item_store.vm.dart +++ b/packages/logging_cloudwatch/amplify_logging_cloudwatch/lib/src/queued_item_store/dart_queued_item_store.vm.dart @@ -56,7 +56,7 @@ class DartQueuedItemStore implements QueuedItemStore, Closeable { } @override - Future isFull(int maxSizeInMB) { + bool isFull(int maxSizeInMB) { return _database.isFull(maxSizeInMB); } diff --git a/packages/logging_cloudwatch/amplify_logging_cloudwatch/lib/src/queued_item_store/dart_queued_item_store.web.dart b/packages/logging_cloudwatch/amplify_logging_cloudwatch/lib/src/queued_item_store/dart_queued_item_store.web.dart index 0dc36a615cf..c20db8c60be 100644 --- a/packages/logging_cloudwatch/amplify_logging_cloudwatch/lib/src/queued_item_store/dart_queued_item_store.web.dart +++ b/packages/logging_cloudwatch/amplify_logging_cloudwatch/lib/src/queued_item_store/dart_queued_item_store.web.dart @@ -14,8 +14,8 @@ class DartQueuedItemStore // ignore: avoid_unused_constructor_parameters DartQueuedItemStore(String? storagePath); - late final Future _database = () async { - if (await IndexedDbAdapter.checkIsIndexedDBSupported()) { + late final QueuedItemStore _database = () { + if (IndexedDbAdapter.checkIsIndexedDBSupported()) { return IndexedDbAdapter(); } logger.warn( @@ -34,8 +34,7 @@ class DartQueuedItemStore String timestamp, { bool enableQueueRotation = false, }) async { - final db = await _database; - await db.addItem( + await _database.addItem( string, timestamp, enableQueueRotation: enableQueueRotation, @@ -44,34 +43,29 @@ class DartQueuedItemStore @override Future deleteItems(Iterable items) async { - final db = await _database; - await db.deleteItems(items); + await _database.deleteItems(items); } @override Future> getCount(int count) async { - final db = await _database; - return db.getCount(count); + return _database.getCount(count); } @override Future> getAll() async { - final db = await _database; - return db.getAll(); + return _database.getAll(); } @override - Future isFull(int maxSizeInMB) async { - final db = await _database; - return db.isFull(maxSizeInMB); + bool isFull(int maxSizeInMB) { + return _database.isFull(maxSizeInMB); } /// Clear IndexedDB data. @override @visibleForTesting Future clear() async { - final db = await _database; - return db.clear(); + return _database.clear(); } @override diff --git a/packages/logging_cloudwatch/amplify_logging_cloudwatch/lib/src/queued_item_store/drift/drift_queued_item_store.dart b/packages/logging_cloudwatch/amplify_logging_cloudwatch/lib/src/queued_item_store/drift/drift_queued_item_store.dart index a7d6026ccea..d29f32777c1 100644 --- a/packages/logging_cloudwatch/amplify_logging_cloudwatch/lib/src/queued_item_store/drift/drift_queued_item_store.dart +++ b/packages/logging_cloudwatch/amplify_logging_cloudwatch/lib/src/queued_item_store/drift/drift_queued_item_store.dart @@ -104,7 +104,7 @@ class DriftQueuedItemStore extends _$DriftQueuedItemStore } @override - Future isFull(int maxSizeInMB) async { + bool isFull(int maxSizeInMB) { final maxBytes = maxSizeInMB * 1024 * 1024; return _currentTotalByteSize >= maxBytes; } diff --git a/packages/logging_cloudwatch/amplify_logging_cloudwatch/lib/src/queued_item_store/index_db/indexed_db_adapter.dart b/packages/logging_cloudwatch/amplify_logging_cloudwatch/lib/src/queued_item_store/index_db/indexed_db_adapter.dart index 37c1812e789..c4e4c13763a 100644 --- a/packages/logging_cloudwatch/amplify_logging_cloudwatch/lib/src/queued_item_store/index_db/indexed_db_adapter.dart +++ b/packages/logging_cloudwatch/amplify_logging_cloudwatch/lib/src/queued_item_store/index_db/indexed_db_adapter.dart @@ -150,7 +150,7 @@ class IndexedDbAdapter implements QueuedItemStore { } @override - Future isFull(int maxSizeInMB) async { + bool isFull(int maxSizeInMB) { final maxBytes = maxSizeInMB * 1024 * 1024; return _currentTotalByteSize >= maxBytes; } @@ -167,15 +167,14 @@ class IndexedDbAdapter implements QueuedItemStore { void close() {} /// Check that IndexDB will work on this device. - static Future checkIsIndexedDBSupported() async { + static bool checkIsIndexedDBSupported() { if (indexedDB == null) { return false; } // indexedDB will be non-null in Firefox private browsing, // but will fail to open. try { - final openRequest = indexedDB!.open('test', 1); - await openRequest.future; + indexedDB!.open('test', 1).result; return true; } on Object { return false; diff --git a/packages/logging_cloudwatch/amplify_logging_cloudwatch/test/queued_item_store_test.dart b/packages/logging_cloudwatch/amplify_logging_cloudwatch/test/queued_item_store_test.dart index 4c18fc12d88..c49b1057808 100644 --- a/packages/logging_cloudwatch/amplify_logging_cloudwatch/test/queued_item_store_test.dart +++ b/packages/logging_cloudwatch/amplify_logging_cloudwatch/test/queued_item_store_test.dart @@ -233,14 +233,14 @@ void main() { await db.addItem(largeItem, DateTime.now().toIso8601String()); } - var result = await db.isFull(capacityLimit); + var result = db.isFull(capacityLimit); expect(result, isFalse); for (var i = 0; i < 100; i++) { await db.addItem(largeItem, DateTime.now().toIso8601String()); } - result = await db.isFull(capacityLimit); + result = db.isFull(capacityLimit); expect(result, isTrue); }, ); diff --git a/packages/logging_cloudwatch/aws_logging_cloudwatch/lib/src/cloudwatch_logger_plugin.dart b/packages/logging_cloudwatch/aws_logging_cloudwatch/lib/src/cloudwatch_logger_plugin.dart index 93da31d0407..5e302b497e1 100644 --- a/packages/logging_cloudwatch/aws_logging_cloudwatch/lib/src/cloudwatch_logger_plugin.dart +++ b/packages/logging_cloudwatch/aws_logging_cloudwatch/lib/src/cloudwatch_logger_plugin.dart @@ -32,9 +32,10 @@ import 'package:meta/meta.dart'; const int _maxNumberOfLogEventsInBatch = 10000; const int _maxLogEventsBatchSize = 1048576; const int _baseBufferSize = 26; +const int _maxLogEventsTimeSpanInBatch = Duration.millisecondsPerDay; const int _maxLogEventSize = 256000; -final int _maxLogEventsTimeSpanInBatch = - const Duration(hours: 24).inMilliseconds; +const Duration _minusMaxLogEventTimeInFuture = Duration(hours: -2); +const Duration _baseRetryInterval = Duration(seconds: 10); typedef _LogBatch = (List logQueues, List logEvents); @@ -113,7 +114,8 @@ class CloudWatchLoggerPlugin extends AWSLoggerPlugin bool _enabled; StoppableTimer? _timer; RemoteLoggingConstraintProvider? _remoteLoggingConstraintProvider; - + int _retryCount = 0; + DateTime? _retryTime; set remoteLoggingConstraintProvider( RemoteLoggingConstraintProvider remoteProvider, ) { @@ -129,32 +131,89 @@ class CloudWatchLoggerPlugin extends AWSLoggerPlugin Future startSyncing() async { final batchStream = _getLogBatchesToSync(); await for (final (logs, events) in batchStream) { - final response = await _sendToCloudWatch(events); - // TODO(nikahsn): handle tooOldLogEventEndIndex - // and expiredLogEventEndIndex. - if (response.rejectedLogEventsInfo?.tooNewLogEventStartIndex != null) { - // TODO(nikahsn): throw and exception to enable log rotation if the - // log store is full. - break; + _TooNewLogEventException? tooNewException; + while (logs.isNotEmpty && events.isNotEmpty) { + final rejectedLogEventsInfo = + (await _sendToCloudWatch(events)).rejectedLogEventsInfo; + if (rejectedLogEventsInfo == null) { + await _logStore.deleteItems(logs); + break; + } + + final (tooOldEndIndex, tooNewStartIndex) = + rejectedLogEventsInfo.parse(events.length); + + if (_isValidIndex(tooNewStartIndex, events.length)) { + tooNewException = _TooNewLogEventException( + events[tooNewStartIndex!].timestamp.toInt(), + ); + // set logs to end before the index. + logs.removeRange(tooNewStartIndex, events.length); + // set events to end before the index. + events.removeRange(tooNewStartIndex, events.length); + } + if (_isValidIndex(tooOldEndIndex, events.length)) { + // remove old logs from log store. + await _logStore.deleteItems(logs.sublist(0, tooOldEndIndex! + 1)); + // set logs to start after the index. + logs.removeRange(0, tooOldEndIndex + 1); + // set events to start after the index. + events.removeRange(0, tooOldEndIndex + 1); + } + } + // after sending each batch to CloudWatch check if the batch has + // `tooNewException` and throw to stop syncing next batches. + if (tooNewException != null) { + throw tooNewException; } - await _logStore.deleteItems(logs); } } if (!_syncing) { - // TODO(nikahsn): disable log rotation. _syncing = true; + DateTime? nextRetry; try { await startSyncing(); + } on _TooNewLogEventException catch (e) { + nextRetry = + DateTime.fromMillisecondsSinceEpoch(e.timeInMillisecondsSinceEpoch) + .add(_minusMaxLogEventTimeInFuture); } on Exception catch (e) { logger.error('Failed to sync logs to CloudWatch.', e); - // TODO(nikahsn): enable log rotation if the log store is full } finally { + _handleFullLogStoreAfterSync( + retryTime: nextRetry, + ); _syncing = false; } } } + void _handleFullLogStoreAfterSync({ + DateTime? retryTime, + }) { + final isLogStoreFull = + _logStore.isFull(_pluginConfig.localStoreMaxSizeInMB); + if (!isLogStoreFull) { + _retryCount = 0; + _retryTime = null; + return; + } + if (retryTime != null && retryTime.isAfter(DateTime.timestamp())) { + _retryTime = retryTime; + return; + } + _retryCount += 1; + _retryTime = DateTime.timestamp().add((_baseRetryInterval * _retryCount)); + } + + bool _shouldSyncOnFullLogStore() { + if (_retryTime == null) { + return true; + } + return !(_retryTime!.isAfter(DateTime.timestamp())); + } + void _onTimerError(Object e) { logger.error('Failed to sync logs to CloudWatch.', e); } @@ -225,11 +284,17 @@ class CloudWatchLoggerPlugin extends AWSLoggerPlugin return; } final item = logEntry.toQueuedItem(); + final isLogStoreFull = + _logStore.isFull(_pluginConfig.localStoreMaxSizeInMB); + final shouldEnableQueueRotation = isLogStoreFull && _retryTime != null; + await _logStore.addItem( item.value, item.timestamp, + enableQueueRotation: shouldEnableQueueRotation, ); - if (await _logStore.isFull(_pluginConfig.localStoreMaxSizeInMB)) { + + if (isLogStoreFull && _shouldSyncOnFullLogStore()) { await _startSyncingIfNotInProgress(); } } @@ -253,6 +318,8 @@ class CloudWatchLoggerPlugin extends AWSLoggerPlugin _enabled = false; _timer?.stop(); await _logStore.clear(); + _retryCount = 0; + _retryTime = null; } /// Sends logs on-demand to CloudWatch. @@ -285,3 +352,34 @@ extension on LogEntry { ); } } + +extension on RejectedLogEventsInfo { + (int? pastEndIndex, int? futureStartIndex) parse(int length) { + int? pastEndIndex; + int? futureStartIndex; + + if (_isValidIndex(tooOldLogEventEndIndex, length)) { + pastEndIndex = tooOldLogEventEndIndex; + } + if (_isValidIndex(expiredLogEventEndIndex, length)) { + pastEndIndex = pastEndIndex == null + ? expiredLogEventEndIndex + : max(pastEndIndex, expiredLogEventEndIndex!); + } + if (_isValidIndex(tooNewLogEventStartIndex, length)) { + futureStartIndex = tooNewLogEventStartIndex; + } + return (pastEndIndex, futureStartIndex); + } +} + +class _TooNewLogEventException implements Exception { + const _TooNewLogEventException( + this.timeInMillisecondsSinceEpoch, + ); + final int timeInMillisecondsSinceEpoch; +} + +bool _isValidIndex(int? index, int length) { + return index != null && index >= 0 && index <= length - 1; +} diff --git a/packages/logging_cloudwatch/aws_logging_cloudwatch/lib/src/queued_item_store/queued_item_store.dart b/packages/logging_cloudwatch/aws_logging_cloudwatch/lib/src/queued_item_store/queued_item_store.dart index 24e197d449c..9317aa48789 100644 --- a/packages/logging_cloudwatch/aws_logging_cloudwatch/lib/src/queued_item_store/queued_item_store.dart +++ b/packages/logging_cloudwatch/aws_logging_cloudwatch/lib/src/queued_item_store/queued_item_store.dart @@ -24,7 +24,7 @@ abstract interface class QueuedItemStore { FutureOr> getAll(); /// Whether the queue size is reached [maxSizeInMB]. - FutureOr isFull(int maxSizeInMB); + bool isFull(int maxSizeInMB); /// Clear the queue of items. FutureOr clear(); diff --git a/packages/logging_cloudwatch/aws_logging_cloudwatch/test/cloudwatch_logger_plugin_test.dart b/packages/logging_cloudwatch/aws_logging_cloudwatch/test/cloudwatch_logger_plugin_test.dart index fe699366825..4e4f57f39e2 100644 --- a/packages/logging_cloudwatch/aws_logging_cloudwatch/test/cloudwatch_logger_plugin_test.dart +++ b/packages/logging_cloudwatch/aws_logging_cloudwatch/test/cloudwatch_logger_plugin_test.dart @@ -45,7 +45,17 @@ void main() { ), QueuedItem( id: 2, - value: 'second og message', + value: 'second log message', + timestamp: DateTime.timestamp().toIso8601String(), + ), + QueuedItem( + id: 3, + value: 'third log message', + timestamp: DateTime.timestamp().toIso8601String(), + ), + QueuedItem( + id: 4, + value: 'forth log message', timestamp: DateTime.timestamp().toIso8601String(), ), ]; @@ -62,17 +72,34 @@ void main() { logStreamProvider: mockCloudWatchLogStreamProvider, ); }); + test('when enabled, logs are added to the item store', () async { - when(() => mockQueuedItemStore.addItem(any(), any())) - .thenAnswer((_) async => {}); + when( + () => mockQueuedItemStore.addItem( + any(), + any(), + enableQueueRotation: false, + ), + ).thenAnswer((_) async => {}); + when(() => mockQueuedItemStore.isFull(pluginConfig.localStoreMaxSizeInMB)) - .thenAnswer((_) async => Future.value(false)); + .thenReturn(false); + plugin.enable(); + await expectLater( plugin.handleLogEntry(errorLog), completes, ); - verify(() => mockQueuedItemStore.addItem(any(), any())).called(1); + + verify( + () => mockQueuedItemStore.addItem( + any(), + any(), + enableQueueRotation: false, + ), + ).called(1); + verify( () => mockQueuedItemStore.isFull(pluginConfig.localStoreMaxSizeInMB), ).called(1); @@ -138,8 +165,8 @@ void main() { when(() => mockCloudWatchLogStreamProvider.defaultLogStream) .thenAnswer((_) async => Future.value('log stream name')); - when(() => mockQueuedItemStore.addItem(any(), any())) - .thenAnswer((_) async => {}); + when(() => mockQueuedItemStore.isFull(pluginConfig.localStoreMaxSizeInMB)) + .thenReturn(false); when(() => mockQueuedItemStore.deleteItems(any())) .thenAnswer((_) async => {}); @@ -184,8 +211,8 @@ void main() { when(() => mockCloudWatchLogStreamProvider.defaultLogStream) .thenAnswer((_) async => Future.value('log stream name')); - when(() => mockQueuedItemStore.addItem(any(), any())) - .thenAnswer((_) async => {}); + when(() => mockQueuedItemStore.isFull(pluginConfig.localStoreMaxSizeInMB)) + .thenReturn(false); when(() => mockQueuedItemStore.getAll()).thenAnswer( (_) async => Future>.value(queuedItems), @@ -239,6 +266,9 @@ void main() { (_) async => Future>.value(queuedItems), ); + when(() => mockQueuedItemStore.isFull(pluginConfig.localStoreMaxSizeInMB)) + .thenReturn(false); + await expectLater( plugin.flushLogs(), completes, @@ -276,6 +306,9 @@ void main() { (_) async => Future>.value(queuedItems), ); + when(() => mockQueuedItemStore.isFull(pluginConfig.localStoreMaxSizeInMB)) + .thenReturn(false); + await expectLater( plugin.flushLogs(), completes, @@ -289,5 +322,405 @@ void main() { () => mockCloudWatchLogStreamProvider.createLogStream(any()), ).called(1); }); + + test('it enables log rotation when log store is full and retry is set', + () async { + when( + () => mockPutLogEventsOperation.result, + ).thenAnswer( + (_) async => Future.value(PutLogEventsResponse()), + ); + + when(() => mockCloudWatchLogsClient.putLogEvents(any())).thenAnswer( + (_) => mockPutLogEventsOperation, + ); + + when(() => mockCloudWatchLogStreamProvider.defaultLogStream) + .thenAnswer((_) async => Future.value('log stream name')); + + when(() => mockQueuedItemStore.isFull(pluginConfig.localStoreMaxSizeInMB)) + .thenReturn(true); + + when(() => mockQueuedItemStore.deleteItems(any())) + .thenAnswer((_) async => {}); + + when(() => mockQueuedItemStore.getAll()).thenAnswer( + (_) async => Future>.value(queuedItems), + ); + plugin.enable(); + + await expectLater( + plugin.flushLogs(), + completes, + ); + + await expectLater( + plugin.handleLogEntry(errorLog), + completes, + ); + + verify( + () => mockQueuedItemStore.addItem( + any(), + any(), + enableQueueRotation: true, + ), + ).called(1); + }); + + test( + 'it does not enable log rotation when log store is full if retry is not ' + 'set. it start sync on full log store.', + () async { + final isFullResponse = [false, true, false]; + when( + () => mockQueuedItemStore.isFull(pluginConfig.localStoreMaxSizeInMB), + ).thenAnswer((_) => isFullResponse.removeAt(0)); + + when( + () => mockPutLogEventsOperation.result, + ).thenAnswer( + (_) async => + Future.value(PutLogEventsResponse()), + ); + + when(() => mockCloudWatchLogsClient.putLogEvents(any())).thenAnswer( + (_) => mockPutLogEventsOperation, + ); + + when(() => mockCloudWatchLogStreamProvider.defaultLogStream) + .thenAnswer((_) async => Future.value('log stream name')); + + when(() => mockQueuedItemStore.deleteItems(any())) + .thenAnswer((_) async => {}); + + when(() => mockQueuedItemStore.getAll()).thenAnswer( + (_) async => Future>.value(queuedItems), + ); + + plugin.enable(); + + await expectLater( + plugin.flushLogs(), + completes, + ); + + await expectLater( + plugin.handleLogEntry(errorLog), + completes, + ); + + verify( + () => mockCloudWatchLogsClient.putLogEvents(any()), + ).called(2); + + verify(() => mockQueuedItemStore.deleteItems(queuedItems)).called(2); + + verify( + () => mockQueuedItemStore.addItem( + any(), + any(), + enableQueueRotation: false, + ), + ).called(1); + }, + ); + + test('it does not sync on full log store if retry time not reached', + () async { + when( + () => mockPutLogEventsOperation.result, + ).thenAnswer( + (_) async => Future.value(PutLogEventsResponse()), + ); + + when(() => mockCloudWatchLogsClient.putLogEvents(any())).thenAnswer( + (_) => mockPutLogEventsOperation, + ); + + when(() => mockCloudWatchLogStreamProvider.defaultLogStream) + .thenAnswer((_) async => Future.value('log stream name')); + + when(() => mockQueuedItemStore.isFull(pluginConfig.localStoreMaxSizeInMB)) + .thenReturn(true); + + when(() => mockQueuedItemStore.deleteItems(any())) + .thenAnswer((_) async => {}); + + when(() => mockQueuedItemStore.getAll()).thenAnswer( + (_) async => Future>.value(queuedItems), + ); + plugin.enable(); + + await expectLater( + plugin.flushLogs(), + completes, + ); + + await expectLater( + plugin.handleLogEntry(errorLog), + completes, + ); + + verify( + () => mockCloudWatchLogsClient.putLogEvents(any()), + ).called(1); + + verify(() => mockQueuedItemStore.deleteItems(queuedItems)).called(1); + }); + + test( + 'it deletes too old logs in the batch and sync the rest', + () async { + final responses = [ + PutLogEventsResponse( + rejectedLogEventsInfo: + RejectedLogEventsInfo(tooOldLogEventEndIndex: 0), + ), + PutLogEventsResponse(), + ]; + + when( + () => mockPutLogEventsOperation.result, + ).thenAnswer( + (_) async { + final response = responses.removeAt(0); + return Future.value(response); + }, + ); + + when(() => mockCloudWatchLogsClient.putLogEvents(any())).thenAnswer( + (_) => mockPutLogEventsOperation, + ); + + when(() => mockCloudWatchLogStreamProvider.defaultLogStream) + .thenAnswer((_) async => Future.value('log stream name')); + + when( + () => mockQueuedItemStore.isFull(pluginConfig.localStoreMaxSizeInMB), + ).thenReturn(false); + + when(() => mockQueuedItemStore.deleteItems(any())) + .thenAnswer((_) async => {}); + + when(() => mockQueuedItemStore.getAll()).thenAnswer( + (_) async => Future>.value(queuedItems), + ); + plugin.enable(); + + await expectLater( + plugin.flushLogs(), + completes, + ); + + verify( + () => mockCloudWatchLogsClient.putLogEvents(any()), + ).called(2); + + final captures = verify( + () => mockQueuedItemStore + .deleteItems(captureAny>()), + ); + + expect(captures.callCount, 2); + expect( + (captures.captured.first as Iterable).first, + queuedItems.first, + ); + expect( + (captures.captured.last as Iterable), + queuedItems.sublist(1), + ); + }, + ); + + test('it deletes expired logs in the batch and sync the rest', () async { + final responses = [ + PutLogEventsResponse( + rejectedLogEventsInfo: + RejectedLogEventsInfo(expiredLogEventEndIndex: 0), + ), + PutLogEventsResponse(), + ]; + + when( + () => mockPutLogEventsOperation.result, + ).thenAnswer( + (_) async { + final response = responses.removeAt(0); + return Future.value(response); + }, + ); + + when(() => mockCloudWatchLogsClient.putLogEvents(any())).thenAnswer( + (_) => mockPutLogEventsOperation, + ); + + when(() => mockCloudWatchLogStreamProvider.defaultLogStream) + .thenAnswer((_) async => Future.value('log stream name')); + + when( + () => mockQueuedItemStore.isFull(pluginConfig.localStoreMaxSizeInMB), + ).thenReturn(false); + + when(() => mockQueuedItemStore.deleteItems(any())) + .thenAnswer((_) async => {}); + + when(() => mockQueuedItemStore.getAll()).thenAnswer( + (_) async => Future>.value(queuedItems), + ); + plugin.enable(); + + await expectLater( + plugin.flushLogs(), + completes, + ); + + verify( + () => mockCloudWatchLogsClient.putLogEvents(any()), + ).called(2); + + final captures = verify( + () => + mockQueuedItemStore.deleteItems(captureAny>()), + ); + + expect(captures.callCount, 2); + expect( + (captures.captured.first as Iterable).first, + queuedItems.first, + ); + expect( + (captures.captured.last as Iterable), + queuedItems.sublist(1), + ); + }); + + test('it leaves too new logs in the batch and sync the rest', () async { + final responses = [ + PutLogEventsResponse( + rejectedLogEventsInfo: + RejectedLogEventsInfo(tooNewLogEventStartIndex: 1), + ), + PutLogEventsResponse(), + ]; + + when( + () => mockPutLogEventsOperation.result, + ).thenAnswer( + (_) async { + final response = responses.removeAt(0); + return Future.value(response); + }, + ); + + when(() => mockCloudWatchLogsClient.putLogEvents(any())).thenAnswer( + (_) => mockPutLogEventsOperation, + ); + + when(() => mockCloudWatchLogStreamProvider.defaultLogStream) + .thenAnswer((_) async => Future.value('log stream name')); + + when( + () => mockQueuedItemStore.isFull(pluginConfig.localStoreMaxSizeInMB), + ).thenReturn(false); + + when(() => mockQueuedItemStore.deleteItems(any())) + .thenAnswer((_) async => {}); + + when(() => mockQueuedItemStore.getAll()).thenAnswer( + (_) async => Future>.value(queuedItems), + ); + plugin.enable(); + + await expectLater( + plugin.flushLogs(), + completes, + ); + + verify( + () => mockCloudWatchLogsClient.putLogEvents(any()), + ).called(2); + + final captures = verify( + () => + mockQueuedItemStore.deleteItems(captureAny>()), + ); + + expect(captures.callCount, 1); + expect(captures.captured.length, 1); + expect( + (captures.captured.last as Iterable).first, + queuedItems.first, + ); + }); + + test( + 'it deltes old logs and leaves too new logs in the batch' + ' and sync the rest', () async { + final responses = [ + PutLogEventsResponse( + rejectedLogEventsInfo: RejectedLogEventsInfo( + expiredLogEventEndIndex: 0, + tooOldLogEventEndIndex: 1, + tooNewLogEventStartIndex: 3, + ), + ), + PutLogEventsResponse(), + ]; + + when( + () => mockPutLogEventsOperation.result, + ).thenAnswer( + (_) async { + final response = responses.removeAt(0); + return Future.value(response); + }, + ); + + when(() => mockCloudWatchLogsClient.putLogEvents(any())).thenAnswer( + (_) => mockPutLogEventsOperation, + ); + + when(() => mockCloudWatchLogStreamProvider.defaultLogStream) + .thenAnswer((_) async => Future.value('log stream name')); + + when( + () => mockQueuedItemStore.isFull(pluginConfig.localStoreMaxSizeInMB), + ).thenReturn(false); + + when(() => mockQueuedItemStore.deleteItems(any())) + .thenAnswer((_) async => {}); + + when(() => mockQueuedItemStore.getAll()).thenAnswer( + (_) async => Future>.value(queuedItems), + ); + plugin.enable(); + + await expectLater( + plugin.flushLogs(), + completes, + ); + + verify( + () => mockCloudWatchLogsClient.putLogEvents(any()), + ).called(2); + + final captures = verify( + () => + mockQueuedItemStore.deleteItems(captureAny>()), + ); + + expect(captures.callCount, 2); + expect( + (captures.captured.first as Iterable), + queuedItems.sublist(0, 2), + ); + + expect( + (captures.captured.last as Iterable), + queuedItems.sublist(2, 3), + ); + }); }); } diff --git a/packages/logging_cloudwatch/aws_logging_cloudwatch/test/queued_item_store/queued_item_store_test.dart b/packages/logging_cloudwatch/aws_logging_cloudwatch/test/queued_item_store/queued_item_store_test.dart index ec2bca88743..ab035a6ca2e 100644 --- a/packages/logging_cloudwatch/aws_logging_cloudwatch/test/queued_item_store/queued_item_store_test.dart +++ b/packages/logging_cloudwatch/aws_logging_cloudwatch/test/queued_item_store/queued_item_store_test.dart @@ -231,7 +231,7 @@ void main() { await db.addItem('0', DateTime.now().toIso8601String()); } - var result = await db.isFull(capacityLimit); + var result = db.isFull(capacityLimit); expect(result, isFalse); // add enough items to exceed capacity limit of 1mb @@ -239,7 +239,7 @@ void main() { await db.addItem('0', DateTime.now().toIso8601String()); } - result = await db.isFull(capacityLimit); + result = db.isFull(capacityLimit); expect(result, isTrue); }, ); From ee143fea9c12ac7200616ef30ccc3415c33708f4 Mon Sep 17 00:00:00 2001 From: NikaHsn Date: Tue, 12 Sep 2023 16:30:02 -0700 Subject: [PATCH 02/49] feat(logging): add amplify cloudwatch logger plugin base implementation (#3736) --- .../src/amplify_cloudwatch_logger_plugin.dart | 19 +++++++++ .../src/amplify_log_stream_name_provider.dart | 39 +++++++++++++++++++ .../lib/src/device_info/device_info.dart | 3 ++ .../lib/src/device_info/device_info.stub.dart | 7 ++++ .../lib/src/device_info/device_info.vm.dart | 30 ++++++++++++++ .../lib/src/device_info/device_info.web.dart | 16 ++++++++ .../amplify_logging_cloudwatch/pubspec.yaml | 4 ++ .../amplify_log_stream_provider_test.dart | 21 ++++++++++ .../lib/src/cloudwatch_logger_plugin.dart | 6 +-- .../lib/src/log_stream_provider.dart | 31 ++++++++++----- 10 files changed, 162 insertions(+), 14 deletions(-) create mode 100644 packages/logging_cloudwatch/amplify_logging_cloudwatch/lib/src/amplify_cloudwatch_logger_plugin.dart create mode 100644 packages/logging_cloudwatch/amplify_logging_cloudwatch/lib/src/amplify_log_stream_name_provider.dart create mode 100644 packages/logging_cloudwatch/amplify_logging_cloudwatch/lib/src/device_info/device_info.dart create mode 100644 packages/logging_cloudwatch/amplify_logging_cloudwatch/lib/src/device_info/device_info.stub.dart create mode 100644 packages/logging_cloudwatch/amplify_logging_cloudwatch/lib/src/device_info/device_info.vm.dart create mode 100644 packages/logging_cloudwatch/amplify_logging_cloudwatch/lib/src/device_info/device_info.web.dart create mode 100644 packages/logging_cloudwatch/amplify_logging_cloudwatch/test/amplify_log_stream_provider_test.dart diff --git a/packages/logging_cloudwatch/amplify_logging_cloudwatch/lib/src/amplify_cloudwatch_logger_plugin.dart b/packages/logging_cloudwatch/amplify_logging_cloudwatch/lib/src/amplify_cloudwatch_logger_plugin.dart new file mode 100644 index 00000000000..929557d7788 --- /dev/null +++ b/packages/logging_cloudwatch/amplify_logging_cloudwatch/lib/src/amplify_cloudwatch_logger_plugin.dart @@ -0,0 +1,19 @@ +import 'package:amplify_logging_cloudwatch/src/amplify_log_stream_name_provider.dart'; +import 'package:aws_logging_cloudwatch/aws_logging_cloudwatch.dart'; + +/// {@macro aws_logging_cloudwatch.cloudwatch_logger_plugin} +class AmplifyCloudWatchLoggerPlugin extends CloudWatchLoggerPlugin { + /// {@macro aws_logging_cloudwatch.cloudwatch_logger_plugin} + AmplifyCloudWatchLoggerPlugin({ + required super.credentialsProvider, + required super.pluginConfig, + }) : super( + logStreamProvider: DefaultCloudWatchLogStreamProvider( + credentialsProvider: credentialsProvider, + region: pluginConfig.region, + logGroupName: pluginConfig.logGroupName, + defaultLogStreamNameProvider: + AmplifyLogStreamNameProvider().defaultLogStreamName, + ), + ); +} diff --git a/packages/logging_cloudwatch/amplify_logging_cloudwatch/lib/src/amplify_log_stream_name_provider.dart b/packages/logging_cloudwatch/amplify_logging_cloudwatch/lib/src/amplify_log_stream_name_provider.dart new file mode 100644 index 00000000000..28fc1b66d7e --- /dev/null +++ b/packages/logging_cloudwatch/amplify_logging_cloudwatch/lib/src/amplify_log_stream_name_provider.dart @@ -0,0 +1,39 @@ +import 'package:amplify_core/amplify_core.dart'; +import 'package:amplify_logging_cloudwatch/src/device_info/device_info.dart'; +import 'package:intl/intl.dart'; + +const _guestUserId = 'guest'; + +/// {@template amplify_logging_cloudwatch.amplify_log_stream_name_provider} +/// It uses {mm-dd-yyyy}.{deviceId}.{userId|guest} format for log stream name. +/// +/// It gets deviceId from platform inforamtion or uuid if it is `null`. +/// It gets userId from `Amplify.Auth.getCurrentUser()).userId` or uses `guest` +/// if userId is not available. +/// {@endtemplate} +class AmplifyLogStreamNameProvider { + /// {@macro amplify_logging_cloudwatch.amplify_log_stream_name_provider} + AmplifyLogStreamNameProvider(); + static final DateFormat _dateFormat = DateFormat('yyyy-MM-dd'); + String? _deviceID; + + /// Returns log stream name in `{mm-dd-yyyy}.{deviceId}.{userId|guest}` format + Future defaultLogStreamName() async { + _deviceID ??= await getDeviceId() ?? UUID.getUUID(); + String userId; + userId = await _getUserId(); + return '${_dateFormat.format(DateTime.timestamp())}.$_deviceID.$userId'; + } + + Future _getUserId() async { + String userId; + try { + userId = (await Amplify.Auth.getCurrentUser()).userId; + } on Error { + userId = _guestUserId; + } on Exception { + userId = _guestUserId; + } + return userId; + } +} diff --git a/packages/logging_cloudwatch/amplify_logging_cloudwatch/lib/src/device_info/device_info.dart b/packages/logging_cloudwatch/amplify_logging_cloudwatch/lib/src/device_info/device_info.dart new file mode 100644 index 00000000000..b5c3a0672cf --- /dev/null +++ b/packages/logging_cloudwatch/amplify_logging_cloudwatch/lib/src/device_info/device_info.dart @@ -0,0 +1,3 @@ +export 'device_info.stub.dart' + if (dart.library.io) 'device_info.vm.dart' + if (dart.library.html) 'device_info.web.dart'; diff --git a/packages/logging_cloudwatch/amplify_logging_cloudwatch/lib/src/device_info/device_info.stub.dart b/packages/logging_cloudwatch/amplify_logging_cloudwatch/lib/src/device_info/device_info.stub.dart new file mode 100644 index 00000000000..5929bec1e24 --- /dev/null +++ b/packages/logging_cloudwatch/amplify_logging_cloudwatch/lib/src/device_info/device_info.stub.dart @@ -0,0 +1,7 @@ +/// {@template amplify_logging_cloudwatch.device_info} +/// Returns device Id from platform information on `vm`. +/// Returns a UUID across browser sessions for web. +/// {@endtemplate} +Future getDeviceId() { + throw UnimplementedError('getDeviceId() has not been implemented.'); +} diff --git a/packages/logging_cloudwatch/amplify_logging_cloudwatch/lib/src/device_info/device_info.vm.dart b/packages/logging_cloudwatch/amplify_logging_cloudwatch/lib/src/device_info/device_info.vm.dart new file mode 100644 index 00000000000..246e600f035 --- /dev/null +++ b/packages/logging_cloudwatch/amplify_logging_cloudwatch/lib/src/device_info/device_info.vm.dart @@ -0,0 +1,30 @@ +import 'dart:io'; + +import 'package:device_info_plus/device_info_plus.dart'; + +/// {@macro amplify_logging_cloudwatch.device_info} +Future getDeviceId() async { + final deviceInfo = DeviceInfoPlugin(); + String? deviceID; + try { + if (Platform.isAndroid) { + final androidInfo = await deviceInfo.androidInfo; + deviceID = androidInfo.id; + } else if (Platform.isIOS) { + final iosInfo = await deviceInfo.iosInfo; + deviceID = iosInfo.identifierForVendor ?? ''; + } else if (Platform.isLinux) { + final linuxInfo = await deviceInfo.linuxInfo; + deviceID = linuxInfo.machineId ?? ''; + } else if (Platform.isMacOS) { + final macInfo = await deviceInfo.macOsInfo; + deviceID = macInfo.systemGUID ?? ''; + } else if (Platform.isWindows) { + final windowsInfo = await deviceInfo.windowsInfo; + deviceID = windowsInfo.deviceId; + } + } on Exception { + return null; + } + return deviceID; +} diff --git a/packages/logging_cloudwatch/amplify_logging_cloudwatch/lib/src/device_info/device_info.web.dart b/packages/logging_cloudwatch/amplify_logging_cloudwatch/lib/src/device_info/device_info.web.dart new file mode 100644 index 00000000000..a6ee9e49722 --- /dev/null +++ b/packages/logging_cloudwatch/amplify_logging_cloudwatch/lib/src/device_info/device_info.web.dart @@ -0,0 +1,16 @@ +import 'dart:html'; + +import 'package:amplify_core/amplify_core.dart'; + +const _localStorageKey = 'amplify-cloudwatch-logger-device-id'; + +/// {@macro amplify_logging_cloudwatch.device_info} +Future getDeviceId() async { + var deviceID = window.localStorage[_localStorageKey]; + if (deviceID != null) { + return deviceID; + } + deviceID = UUID.getUUID(); + window.localStorage.putIfAbsent(_localStorageKey, () => deviceID!); + return deviceID; +} diff --git a/packages/logging_cloudwatch/amplify_logging_cloudwatch/pubspec.yaml b/packages/logging_cloudwatch/amplify_logging_cloudwatch/pubspec.yaml index 2c5bf793db5..d378666f82f 100644 --- a/packages/logging_cloudwatch/amplify_logging_cloudwatch/pubspec.yaml +++ b/packages/logging_cloudwatch/amplify_logging_cloudwatch/pubspec.yaml @@ -15,9 +15,11 @@ dependencies: aws_common: ">=0.6.0 <0.7.0" aws_logging_cloudwatch: ^0.1.0 collection: ^1.15.0 + device_info_plus: ^9.0.0 drift: ">=2.11.0 <2.12.0" flutter: sdk: flutter + intl: ">=0.18.0 <1.0.0" meta: ^1.7.0 path_provider: ^2.0.0 @@ -27,4 +29,6 @@ dev_dependencies: build_test: ^2.0.0 build_web_compilers: ^4.0.0 drift_dev: ^2.2.0+1 + flutter_test: + sdk: flutter test: ^1.22.1 diff --git a/packages/logging_cloudwatch/amplify_logging_cloudwatch/test/amplify_log_stream_provider_test.dart b/packages/logging_cloudwatch/amplify_logging_cloudwatch/test/amplify_log_stream_provider_test.dart new file mode 100644 index 00000000000..b9e04b2b56c --- /dev/null +++ b/packages/logging_cloudwatch/amplify_logging_cloudwatch/test/amplify_log_stream_provider_test.dart @@ -0,0 +1,21 @@ +@TestOn('vm') + +import 'package:amplify_logging_cloudwatch/src/amplify_log_stream_name_provider.dart'; +import 'package:flutter_test/flutter_test.dart' as flutter; +import 'package:test/test.dart'; + +void main() { + flutter.TestWidgetsFlutterBinding.ensureInitialized(); + test('it uses uuid and guest when their values are not provided', () async { + final logStreamNameProvider = AmplifyLogStreamNameProvider(); + await expectLater(logStreamNameProvider.defaultLogStreamName(), completes); + }); + + test('it caches the device Id', () async { + final logStreamNameProvider = AmplifyLogStreamNameProvider(); + final logStreamName1 = await logStreamNameProvider.defaultLogStreamName(); + final logStreamName2 = await logStreamNameProvider.defaultLogStreamName(); + + expect(logStreamName1, logStreamName2); + }); +} diff --git a/packages/logging_cloudwatch/aws_logging_cloudwatch/lib/src/cloudwatch_logger_plugin.dart b/packages/logging_cloudwatch/aws_logging_cloudwatch/lib/src/cloudwatch_logger_plugin.dart index 5e302b497e1..22fe2c1cbed 100644 --- a/packages/logging_cloudwatch/aws_logging_cloudwatch/lib/src/cloudwatch_logger_plugin.dart +++ b/packages/logging_cloudwatch/aws_logging_cloudwatch/lib/src/cloudwatch_logger_plugin.dart @@ -73,10 +73,8 @@ class CloudWatchLoggerPlugin extends AWSLoggerPlugin _logStreamProvider = logStreamProvider ?? DefaultCloudWatchLogStreamProvider( logGroupName: pluginConfig.logGroupName, - client: CloudWatchLogsClient( - region: pluginConfig.region, - credentialsProvider: credentialsProvider, - ), + region: pluginConfig.region, + credentialsProvider: credentialsProvider, ) { _timer = pluginConfig.flushIntervalInSeconds > Duration.zero ? StoppableTimer( diff --git a/packages/logging_cloudwatch/aws_logging_cloudwatch/lib/src/log_stream_provider.dart b/packages/logging_cloudwatch/aws_logging_cloudwatch/lib/src/log_stream_provider.dart index 963c47e5e13..8828b2609e3 100644 --- a/packages/logging_cloudwatch/aws_logging_cloudwatch/lib/src/log_stream_provider.dart +++ b/packages/logging_cloudwatch/aws_logging_cloudwatch/lib/src/log_stream_provider.dart @@ -3,6 +3,7 @@ import 'dart:async'; +import 'package:aws_common/aws_common.dart'; import 'package:aws_logging_cloudwatch/src/sdk/cloud_watch_logs.dart'; import 'package:intl/intl.dart'; @@ -22,30 +23,36 @@ abstract class CloudWatchLogStreamProvider { /// {@template aws_logging_cloudwatch.default_cloudwatch_logstream_provider} /// The default implementaion of [CloudWatchLogStreamProvider]. /// -/// It uses `defaultLogStreamName` if provided otherwise uses `yyyy-MM-dd` -/// date format of UTC time now for the `defaultLogStreamName`. +/// It uses `defaultLogStreamNameProvider` if provided otherwise uses +/// `yyyy-MM-dd` date format of UTC time now for the `defaultLogStreamName`. /// {@endtemplate} class DefaultCloudWatchLogStreamProvider implements CloudWatchLogStreamProvider { /// {@macro aws_logging_cloudwatch.default_cloudwatch_logstream_provider} DefaultCloudWatchLogStreamProvider({ - required CloudWatchLogsClient client, + required AWSCredentialsProvider credentialsProvider, + required String region, required String logGroupName, - String? defaultLogStreamName, - }) : _defaultLogStreamName = defaultLogStreamName, - _logGroupName = logGroupName, - _client = client; + FutureOr Function()? defaultLogStreamNameProvider, + }) : _logGroupName = logGroupName, + _client = CloudWatchLogsClient( + region: region, + credentialsProvider: credentialsProvider, + ), + _defaultLogStreamNameProvider = defaultLogStreamNameProvider; - final String? _defaultLogStreamName; + final FutureOr Function()? _defaultLogStreamNameProvider; final String _logGroupName; final CloudWatchLogsClient _client; + static final DateFormat _dateFormat = DateFormat('yyyy-MM-dd'); final _createdLogStreams = {}; @override Future get defaultLogStream async { - final logStreamName = - _defaultLogStreamName ?? _dateFormat.format(DateTime.timestamp()); + final logStreamNameProvider = + _defaultLogStreamNameProvider ?? _timeBasedLogStreamNameProvider; + final logStreamName = await logStreamNameProvider(); if (_createdLogStreams.contains(logStreamName)) { return logStreamName; } @@ -54,6 +61,10 @@ class DefaultCloudWatchLogStreamProvider return logStreamName; } + String _timeBasedLogStreamNameProvider() { + return _dateFormat.format(DateTime.timestamp()); + } + @override Future createLogStream(String logStreamName) async { try { From 66552675f7a9826f8fce71314046645b6b0ac655 Mon Sep 17 00:00:00 2001 From: Nika Hassani Date: Wed, 16 Aug 2023 16:27:39 -0700 Subject: [PATCH 03/49] feat(logging): add cloudwatch logger plugin --- .../test/cloudwatch_logger_plugin_test.dart | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/logging_cloudwatch/aws_logging_cloudwatch/test/cloudwatch_logger_plugin_test.dart b/packages/logging_cloudwatch/aws_logging_cloudwatch/test/cloudwatch_logger_plugin_test.dart index 4e4f57f39e2..3fe37d8d5be 100644 --- a/packages/logging_cloudwatch/aws_logging_cloudwatch/test/cloudwatch_logger_plugin_test.dart +++ b/packages/logging_cloudwatch/aws_logging_cloudwatch/test/cloudwatch_logger_plugin_test.dart @@ -25,6 +25,7 @@ void main() { localLoggingConstraint: loggingConstraint, enable: false, ); + final errorLog = LogEntry( level: LogLevel.error, message: 'error message', @@ -57,7 +58,7 @@ void main() { id: 4, value: 'forth log message', timestamp: DateTime.timestamp().toIso8601String(), - ), + ) ]; group('enable/disable: ', () { From 20ae7cd84f16ccfb2484d3cdf658c029722dde79 Mon Sep 17 00:00:00 2001 From: Kha Truong <64438356+khatruong2009@users.noreply.github.com> Date: Mon, 28 Aug 2023 15:51:36 -0700 Subject: [PATCH 04/49] feat(logging): default remote config --- .../lib/src/plugin_config.dart | 9 ++ .../lib/src/remote_constraint_provider.dart | 82 ++++++++++++++++++- .../aws_logging_cloudwatch/pubspec.yaml | 1 + 3 files changed, 90 insertions(+), 2 deletions(-) diff --git a/packages/logging_cloudwatch/aws_logging_cloudwatch/lib/src/plugin_config.dart b/packages/logging_cloudwatch/aws_logging_cloudwatch/lib/src/plugin_config.dart index 9fd10d18d06..6a1e9e58382 100644 --- a/packages/logging_cloudwatch/aws_logging_cloudwatch/lib/src/plugin_config.dart +++ b/packages/logging_cloudwatch/aws_logging_cloudwatch/lib/src/plugin_config.dart @@ -48,6 +48,15 @@ class CloudWatchLoggerPluginConfiguration with AWSDebuggable { /// The logging constraint for sending logs to CloudWatch. /// {@endtemplate} class LoggingConstraint with AWSDebuggable { + factory LoggingConstraint.fromJson(Map json) { + return LoggingConstraint( + defaultLogLevel: LogLevel.values.firstWhere( + (e) => e.toString() == 'LogLevel.${json['defaultLogLevel']}', + orElse: () => LogLevel.error, // Default value if not found + ), + ); + } + /// {@macro aws_logging_cloudwatch.logging_constraint} const LoggingConstraint({this.defaultLogLevel = LogLevel.error}); diff --git a/packages/logging_cloudwatch/aws_logging_cloudwatch/lib/src/remote_constraint_provider.dart b/packages/logging_cloudwatch/aws_logging_cloudwatch/lib/src/remote_constraint_provider.dart index 7a8a36332f0..076efaba25b 100644 --- a/packages/logging_cloudwatch/aws_logging_cloudwatch/lib/src/remote_constraint_provider.dart +++ b/packages/logging_cloudwatch/aws_logging_cloudwatch/lib/src/remote_constraint_provider.dart @@ -1,11 +1,15 @@ // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. // SPDX-License-Identifier: Apache-2.0 +import 'dart:convert'; +import 'dart:io'; + // TODO(nikahsn): remove after implementing the get loggingConstraint. // ignore_for_file: unused_field import 'package:aws_common/aws_common.dart'; import 'package:aws_logging_cloudwatch/aws_logging_cloudwatch.dart'; +import 'package:http/http.dart' as http; /// {@template aws_logging_cloudwatch.remote_logging_constraint_provider} /// An Interface to provide custom implementation for @@ -33,9 +37,83 @@ class DefaultRemoteLoggingConstraintProvider final DefaultRemoteConfiguration _config; final AWSCredentialsProvider _credentialsProvider; + LoggingConstraint? _loggingConstraint; + DateTime? _lastUpdated; + + Future _saveConstraintLocally(LoggingConstraint constraint) async { + final file = File('logging_constraint.json'); + await file.writeAsString(jsonEncode(constraint)); + } + + Future _getConstraintFromLocalStorage() async { + final file = File('logging_constraint.json'); + if (await file.exists()) { + final content = await file.readAsString(); + return LoggingConstraint.fromJson( + jsonDecode(content) as Map, + ); + } + return null; + } + + Future _fetchAndCacheConstraintFromEndpoint() async { + try { + final constraint = await _fetchConstraintFromEndpoint(); + if (constraint != null) { + _loggingConstraint = constraint; + _lastUpdated = DateTime.now(); + } + } catch (error) { + print('Error fetching constraints: $error'); + } + } + + Future _fetchConstraintFromEndpoint() async { + final response = await http.get(Uri.parse(_config.endpoint)); + if (response.statusCode == 200) { + final fetchedConstraint = LoggingConstraint.fromJson( + jsonDecode(response.body) as Map, + ); + await _saveConstraintLocally(fetchedConstraint); + return fetchedConstraint; + } + throw Exception( + 'Failed to fetch logging constraint from ${_config.endpoint}', + ); + } + @override - // TODO(nikahsn): add implementation. - LoggingConstraint get loggingConstraint => throw UnimplementedError(); + LoggingConstraint? get loggingConstraint { + if (_loggingConstraint != null && + _lastUpdated != null && + DateTime.now().difference(_lastUpdated!).inSeconds <= + _config.refreshIntervalInSeconds.inSeconds) { + return _loggingConstraint; + } + // Load from local storage synchronously + final file = File('logging_constraint.json'); + if (file.existsSync()) { + final content = file.readAsStringSync(); + return LoggingConstraint.fromJson( + jsonDecode(content) as Map, + ); + } + return null; + } + + /// Initializes and starts the periodic fetch. + void initialize() { + _fetchAndCacheConstraintFromEndpoint(); // Fetch once immediately on initialize + _refreshConstraintPeriodically(); + } + + /// Refreshes the constraint from the endpoint periodically. + Future _refreshConstraintPeriodically() async { + while (true) { + await Future.delayed(_config.refreshIntervalInSeconds); + await _fetchAndCacheConstraintFromEndpoint(); + } + } } /// {@template aws_logging_cloudwatch.default_remote_configuration} diff --git a/packages/logging_cloudwatch/aws_logging_cloudwatch/pubspec.yaml b/packages/logging_cloudwatch/aws_logging_cloudwatch/pubspec.yaml index 9d2e09f7d32..c5943984a0d 100644 --- a/packages/logging_cloudwatch/aws_logging_cloudwatch/pubspec.yaml +++ b/packages/logging_cloudwatch/aws_logging_cloudwatch/pubspec.yaml @@ -15,6 +15,7 @@ dependencies: built_collection: ^5.1.1 built_value: ">=8.6.0 <8.7.0" fixnum: ^1.1.0 + http: ^1.0.0 intl: ">=0.18.0 <1.0.0" meta: ^1.9.1 smithy: ^0.5.0+3 From a7d180edc9c7ab86a1491087f343ad7c8253f340 Mon Sep 17 00:00:00 2001 From: Kha Truong <64438356+khatruong2009@users.noreply.github.com> Date: Wed, 30 Aug 2023 10:45:12 -0700 Subject: [PATCH 05/49] chore: moved declarations to improve dart syntax --- .../aws_logging_cloudwatch/lib/src/plugin_config.dart | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/packages/logging_cloudwatch/aws_logging_cloudwatch/lib/src/plugin_config.dart b/packages/logging_cloudwatch/aws_logging_cloudwatch/lib/src/plugin_config.dart index 6a1e9e58382..79dffd0fddc 100644 --- a/packages/logging_cloudwatch/aws_logging_cloudwatch/lib/src/plugin_config.dart +++ b/packages/logging_cloudwatch/aws_logging_cloudwatch/lib/src/plugin_config.dart @@ -48,6 +48,10 @@ class CloudWatchLoggerPluginConfiguration with AWSDebuggable { /// The logging constraint for sending logs to CloudWatch. /// {@endtemplate} class LoggingConstraint with AWSDebuggable { + /// {@macro aws_logging_cloudwatch.logging_constraint} + const LoggingConstraint({this.defaultLogLevel = LogLevel.error}); + + /// Converts a [Map] to an [LoggingConstraint] instance. factory LoggingConstraint.fromJson(Map json) { return LoggingConstraint( defaultLogLevel: LogLevel.values.firstWhere( @@ -57,9 +61,6 @@ class LoggingConstraint with AWSDebuggable { ); } - /// {@macro aws_logging_cloudwatch.logging_constraint} - const LoggingConstraint({this.defaultLogLevel = LogLevel.error}); - /// The default [LogLevel] for sending logs to CloudWatch. final LogLevel defaultLogLevel; From 97eb764f0f7392b45fdfac72eb2c6ec504621948 Mon Sep 17 00:00:00 2001 From: Kha Truong <64438356+khatruong2009@users.noreply.github.com> Date: Wed, 30 Aug 2023 12:13:16 -0700 Subject: [PATCH 06/49] chore: use logger instead of print statement --- .../lib/src/remote_constraint_provider.dart | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/packages/logging_cloudwatch/aws_logging_cloudwatch/lib/src/remote_constraint_provider.dart b/packages/logging_cloudwatch/aws_logging_cloudwatch/lib/src/remote_constraint_provider.dart index 076efaba25b..93cba543dd3 100644 --- a/packages/logging_cloudwatch/aws_logging_cloudwatch/lib/src/remote_constraint_provider.dart +++ b/packages/logging_cloudwatch/aws_logging_cloudwatch/lib/src/remote_constraint_provider.dart @@ -7,7 +7,7 @@ import 'dart:io'; // TODO(nikahsn): remove after implementing the get loggingConstraint. // ignore_for_file: unused_field -import 'package:aws_common/aws_common.dart'; +import 'package:amplify_core/amplify_core.dart'; import 'package:aws_logging_cloudwatch/aws_logging_cloudwatch.dart'; import 'package:http/http.dart' as http; @@ -40,6 +40,8 @@ class DefaultRemoteLoggingConstraintProvider LoggingConstraint? _loggingConstraint; DateTime? _lastUpdated; + static final _logger = AmplifyLogger('default-remote-config'); + Future _saveConstraintLocally(LoggingConstraint constraint) async { final file = File('logging_constraint.json'); await file.writeAsString(jsonEncode(constraint)); @@ -64,7 +66,7 @@ class DefaultRemoteLoggingConstraintProvider _lastUpdated = DateTime.now(); } } catch (error) { - print('Error fetching constraints: $error'); + _logger.debug('Error fetching constraints: $error'); } } From f3751abea821a4308e85d1163f904c1b08d63e08 Mon Sep 17 00:00:00 2001 From: Kha Truong <64438356+khatruong2009@users.noreply.github.com> Date: Wed, 30 Aug 2023 14:13:25 -0700 Subject: [PATCH 07/49] chore: added sigv4signer to sign the http request --- .../lib/src/remote_constraint_provider.dart | 24 ++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/packages/logging_cloudwatch/aws_logging_cloudwatch/lib/src/remote_constraint_provider.dart b/packages/logging_cloudwatch/aws_logging_cloudwatch/lib/src/remote_constraint_provider.dart index 93cba543dd3..782ad818ab7 100644 --- a/packages/logging_cloudwatch/aws_logging_cloudwatch/lib/src/remote_constraint_provider.dart +++ b/packages/logging_cloudwatch/aws_logging_cloudwatch/lib/src/remote_constraint_provider.dart @@ -9,6 +9,7 @@ import 'dart:io'; import 'package:amplify_core/amplify_core.dart'; import 'package:aws_logging_cloudwatch/aws_logging_cloudwatch.dart'; +import 'package:aws_signature_v4/aws_signature_v4.dart'; import 'package:http/http.dart' as http; /// {@template aws_logging_cloudwatch.remote_logging_constraint_provider} @@ -40,6 +41,12 @@ class DefaultRemoteLoggingConstraintProvider LoggingConstraint? _loggingConstraint; DateTime? _lastUpdated; + /// The signer to sign the request. + static const signer = AWSSigV4Signer(); + + /// The scope to sign the request. + final scope = AWSCredentialScope(region: 'us-west-2', service: AWSService.s3); + static final _logger = AmplifyLogger('default-remote-config'); Future _saveConstraintLocally(LoggingConstraint constraint) async { @@ -71,7 +78,22 @@ class DefaultRemoteLoggingConstraintProvider } Future _fetchConstraintFromEndpoint() async { - final response = await http.get(Uri.parse(_config.endpoint)); + final uri = Uri.parse(_config.endpoint); + + final request = AWSHttpRequest(method: AWSHttpMethod.get, uri: uri); + + final signedRequest = await signer.sign( + request, + credentialScope: scope, + ); + + final headers = signedRequest.headers.map( + MapEntry.new, + ); + + final response = await http.get(uri, headers: headers); + + // final response = await http.get(Uri.parse(_config.endpoint)); if (response.statusCode == 200) { final fetchedConstraint = LoggingConstraint.fromJson( jsonDecode(response.body) as Map, From 8ec7dc4c564b258e1c7986af1f1d79dc11909f98 Mon Sep 17 00:00:00 2001 From: Kha Truong <64438356+khatruong2009@users.noreply.github.com> Date: Wed, 30 Aug 2023 15:36:55 -0700 Subject: [PATCH 08/49] chore: switched Future.delayed to Timer and implemented jsonserializable --- .../lib/src/plugin_config.dart | 24 ++++++++++------ .../lib/src/plugin_config.g.dart | 28 +++++++++++++++++++ .../lib/src/remote_constraint_provider.dart | 8 +++++- .../aws_logging_cloudwatch/pubspec.yaml | 1 + 4 files changed, 52 insertions(+), 9 deletions(-) create mode 100644 packages/logging_cloudwatch/aws_logging_cloudwatch/lib/src/plugin_config.g.dart diff --git a/packages/logging_cloudwatch/aws_logging_cloudwatch/lib/src/plugin_config.dart b/packages/logging_cloudwatch/aws_logging_cloudwatch/lib/src/plugin_config.dart index 79dffd0fddc..5c8ad68af99 100644 --- a/packages/logging_cloudwatch/aws_logging_cloudwatch/lib/src/plugin_config.dart +++ b/packages/logging_cloudwatch/aws_logging_cloudwatch/lib/src/plugin_config.dart @@ -3,6 +3,9 @@ import 'package:aws_common/aws_common.dart'; import 'package:aws_logging_cloudwatch/aws_logging_cloudwatch.dart'; +import 'package:json_annotation/json_annotation.dart'; + +part 'plugin_config.g.dart'; /// {@template aws_logging_cloudwatch.cloudwatch_logger_plugin_configuration} /// The configuration for `CloudWatchLoggerPlugin`. @@ -47,19 +50,24 @@ class CloudWatchLoggerPluginConfiguration with AWSDebuggable { /// {@template aws_logging_cloudwatch.logging_constraint} /// The logging constraint for sending logs to CloudWatch. /// {@endtemplate} + +@JsonSerializable() class LoggingConstraint with AWSDebuggable { /// {@macro aws_logging_cloudwatch.logging_constraint} const LoggingConstraint({this.defaultLogLevel = LogLevel.error}); /// Converts a [Map] to an [LoggingConstraint] instance. - factory LoggingConstraint.fromJson(Map json) { - return LoggingConstraint( - defaultLogLevel: LogLevel.values.firstWhere( - (e) => e.toString() == 'LogLevel.${json['defaultLogLevel']}', - orElse: () => LogLevel.error, // Default value if not found - ), - ); - } + // factory LoggingConstraint.fromJson(Map json) { + // return LoggingConstraint( + // defaultLogLevel: LogLevel.values.firstWhere( + // (e) => e.toString() == 'LogLevel.${json['defaultLogLevel']}', + // orElse: () => LogLevel.error, // Default value if not found + // ), + // ); + // } + + factory LoggingConstraint.fromJson(Map json) => + _$LoggingConstraintFromJson(json); /// The default [LogLevel] for sending logs to CloudWatch. final LogLevel defaultLogLevel; diff --git a/packages/logging_cloudwatch/aws_logging_cloudwatch/lib/src/plugin_config.g.dart b/packages/logging_cloudwatch/aws_logging_cloudwatch/lib/src/plugin_config.g.dart new file mode 100644 index 00000000000..f3ed0674a61 --- /dev/null +++ b/packages/logging_cloudwatch/aws_logging_cloudwatch/lib/src/plugin_config.g.dart @@ -0,0 +1,28 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'plugin_config.dart'; + +// ************************************************************************** +// JsonSerializableGenerator +// ************************************************************************** + +LoggingConstraint _$LoggingConstraintFromJson(Map json) => + LoggingConstraint( + defaultLogLevel: + $enumDecodeNullable(_$LogLevelEnumMap, json['defaultLogLevel']) ?? + LogLevel.error, + ); + +Map _$LoggingConstraintToJson(LoggingConstraint instance) => + { + 'defaultLogLevel': _$LogLevelEnumMap[instance.defaultLogLevel]!, + }; + +const _$LogLevelEnumMap = { + LogLevel.verbose: 'verbose', + LogLevel.debug: 'debug', + LogLevel.info: 'info', + LogLevel.warn: 'warn', + LogLevel.error: 'error', + LogLevel.none: 'none', +}; diff --git a/packages/logging_cloudwatch/aws_logging_cloudwatch/lib/src/remote_constraint_provider.dart b/packages/logging_cloudwatch/aws_logging_cloudwatch/lib/src/remote_constraint_provider.dart index 782ad818ab7..18223b22f2c 100644 --- a/packages/logging_cloudwatch/aws_logging_cloudwatch/lib/src/remote_constraint_provider.dart +++ b/packages/logging_cloudwatch/aws_logging_cloudwatch/lib/src/remote_constraint_provider.dart @@ -1,6 +1,7 @@ // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. // SPDX-License-Identifier: Apache-2.0 +import 'dart:async'; import 'dart:convert'; import 'dart:io'; @@ -49,6 +50,8 @@ class DefaultRemoteLoggingConstraintProvider static final _logger = AmplifyLogger('default-remote-config'); + Timer? _timer; + Future _saveConstraintLocally(LoggingConstraint constraint) async { final file = File('logging_constraint.json'); await file.writeAsString(jsonEncode(constraint)); @@ -134,7 +137,10 @@ class DefaultRemoteLoggingConstraintProvider /// Refreshes the constraint from the endpoint periodically. Future _refreshConstraintPeriodically() async { while (true) { - await Future.delayed(_config.refreshIntervalInSeconds); + _timer?.cancel(); + _timer = Timer.periodic(_config.refreshIntervalInSeconds, (timer) async { + await _fetchAndCacheConstraintFromEndpoint(); + }); await _fetchAndCacheConstraintFromEndpoint(); } } diff --git a/packages/logging_cloudwatch/aws_logging_cloudwatch/pubspec.yaml b/packages/logging_cloudwatch/aws_logging_cloudwatch/pubspec.yaml index c5943984a0d..0d823134c5c 100644 --- a/packages/logging_cloudwatch/aws_logging_cloudwatch/pubspec.yaml +++ b/packages/logging_cloudwatch/aws_logging_cloudwatch/pubspec.yaml @@ -17,6 +17,7 @@ dependencies: fixnum: ^1.1.0 http: ^1.0.0 intl: ">=0.18.0 <1.0.0" + json_annotation: ^4.8.1 meta: ^1.9.1 smithy: ^0.5.0+3 smithy_aws: ^0.5.0+3 From 7ca5581c33f0547266c0981dad815ff841f94a37 Mon Sep 17 00:00:00 2001 From: Kha Truong <64438356+khatruong2009@users.noreply.github.com> Date: Wed, 30 Aug 2023 15:38:45 -0700 Subject: [PATCH 09/49] chore: roll back unnecessary changes from cloudwatch_logger_plugin --- .../test/cloudwatch_logger_plugin_test.dart | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/packages/logging_cloudwatch/aws_logging_cloudwatch/test/cloudwatch_logger_plugin_test.dart b/packages/logging_cloudwatch/aws_logging_cloudwatch/test/cloudwatch_logger_plugin_test.dart index 3fe37d8d5be..4e4f57f39e2 100644 --- a/packages/logging_cloudwatch/aws_logging_cloudwatch/test/cloudwatch_logger_plugin_test.dart +++ b/packages/logging_cloudwatch/aws_logging_cloudwatch/test/cloudwatch_logger_plugin_test.dart @@ -25,7 +25,6 @@ void main() { localLoggingConstraint: loggingConstraint, enable: false, ); - final errorLog = LogEntry( level: LogLevel.error, message: 'error message', @@ -58,7 +57,7 @@ void main() { id: 4, value: 'forth log message', timestamp: DateTime.timestamp().toIso8601String(), - ) + ), ]; group('enable/disable: ', () { From f3aadccd4e108fa53a60055cc2ce7b10a7e715c4 Mon Sep 17 00:00:00 2001 From: Kha Truong <64438356+khatruong2009@users.noreply.github.com> Date: Wed, 30 Aug 2023 15:55:21 -0700 Subject: [PATCH 10/49] chore: removed an extra line of fetchAndCacheConstraintFromEndpoint --- .../lib/src/remote_constraint_provider.dart | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/logging_cloudwatch/aws_logging_cloudwatch/lib/src/remote_constraint_provider.dart b/packages/logging_cloudwatch/aws_logging_cloudwatch/lib/src/remote_constraint_provider.dart index 18223b22f2c..4f9e67b99dc 100644 --- a/packages/logging_cloudwatch/aws_logging_cloudwatch/lib/src/remote_constraint_provider.dart +++ b/packages/logging_cloudwatch/aws_logging_cloudwatch/lib/src/remote_constraint_provider.dart @@ -141,7 +141,6 @@ class DefaultRemoteLoggingConstraintProvider _timer = Timer.periodic(_config.refreshIntervalInSeconds, (timer) async { await _fetchAndCacheConstraintFromEndpoint(); }); - await _fetchAndCacheConstraintFromEndpoint(); } } } From 71874354397d2972d9233849db1d4ce28278e0b5 Mon Sep 17 00:00:00 2001 From: Kha Truong <64438356+khatruong2009@users.noreply.github.com> Date: Thu, 31 Aug 2023 11:27:04 -0700 Subject: [PATCH 11/49] chore: moved saveConstraintLocally out of fetchConstraintFromEndpoint and moved into fetchAndCacheFromEndpoint --- .../lib/src/remote_constraint_provider.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/logging_cloudwatch/aws_logging_cloudwatch/lib/src/remote_constraint_provider.dart b/packages/logging_cloudwatch/aws_logging_cloudwatch/lib/src/remote_constraint_provider.dart index 4f9e67b99dc..f2aba52b9ce 100644 --- a/packages/logging_cloudwatch/aws_logging_cloudwatch/lib/src/remote_constraint_provider.dart +++ b/packages/logging_cloudwatch/aws_logging_cloudwatch/lib/src/remote_constraint_provider.dart @@ -74,6 +74,7 @@ class DefaultRemoteLoggingConstraintProvider if (constraint != null) { _loggingConstraint = constraint; _lastUpdated = DateTime.now(); + await _saveConstraintLocally(constraint); } } catch (error) { _logger.debug('Error fetching constraints: $error'); @@ -101,7 +102,6 @@ class DefaultRemoteLoggingConstraintProvider final fetchedConstraint = LoggingConstraint.fromJson( jsonDecode(response.body) as Map, ); - await _saveConstraintLocally(fetchedConstraint); return fetchedConstraint; } throw Exception( From ef754637c1540dd6e9b61e70b224ed1a7f2d6d74 Mon Sep 17 00:00:00 2001 From: Kha Truong <64438356+khatruong2009@users.noreply.github.com> Date: Thu, 31 Aug 2023 14:15:26 -0700 Subject: [PATCH 12/49] fix: seeing if moving the queued_item_store_test.dart file into main test directory will fix testing issue --- .../test/queued_item_store_test.dart | 232 ++++++++++++++++++ 1 file changed, 232 insertions(+) create mode 100644 packages/logging_cloudwatch/aws_logging_cloudwatch/test/queued_item_store_test.dart diff --git a/packages/logging_cloudwatch/aws_logging_cloudwatch/test/queued_item_store_test.dart b/packages/logging_cloudwatch/aws_logging_cloudwatch/test/queued_item_store_test.dart new file mode 100644 index 00000000000..48e73ca64e4 --- /dev/null +++ b/packages/logging_cloudwatch/aws_logging_cloudwatch/test/queued_item_store_test.dart @@ -0,0 +1,232 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +import 'package:aws_logging_cloudwatch/src/queued_item_store/in_memory_queued_item_store.dart'; +import 'package:aws_logging_cloudwatch/src/queued_item_store/queued_item_store.dart'; +import 'package:test/test.dart'; + +void main() { + late QueuedItemStore db; + + group('InMemoryQueuedItemStore ', () { + setUpAll(() { + db = InMemoryQueuedItemStore(); + }); + + tearDownAll(() async { + await db.clear(); + }); + + setUp(() async { + await db.clear(); + }); + + Future> getAll() async { + return db.getCount(100); + } + + test('writes values to storage', () async { + const values = ['0', '1', '2', '3', '4', '5']; + for (final value in values) { + await db.addItem(value, DateTime.now().toIso8601String()); + } + + final readItems = await db.getCount(values.length); + final readValues = readItems.map((e) => e.value); + expect(readValues, equals(values)); + }); + + test('returns first n items in storage', () async { + const values = ['0', '1', '2', '3', '4', '5']; + for (final value in values) { + await db.addItem(value, DateTime.now().toIso8601String()); + } + + final readItems = await db.getCount(3); + final readValues = readItems.map((e) => e.value); + expect(readValues, equals(values.sublist(0, 3))); + }); + + test( + 'returns all stored items when get request size exceeds stored item count', + () async { + const values = ['0', '1', '2', '3', '4', '5']; + for (final value in values) { + await db.addItem(value, DateTime.now().toIso8601String()); + } + + final readItems = await db.getCount(100); + final readValues = readItems.map((e) => e.value); + expect(readValues, values); + }); + + test('deletes all items in storage', () async { + const values = ['0', '1', '2', '3', '4', '5']; + for (final value in values) { + await db.addItem(value, DateTime.now().toIso8601String()); + } + + await db.deleteItems(await getAll()); + + final readItems = await getAll(); + expect(readItems, isEmpty); + }); + + test('deletes first subset of stored items', () async { + const values = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9']; + for (final value in values) { + await db.addItem(value, DateTime.now().toIso8601String()); + } + + await db.deleteItems(await db.getCount(3)); + + final readItems = await getAll(); + final readValues = readItems.map((e) => e.value); + expect(readValues, values.sublist(3)); + }); + + test('deletes middle subset of stored items', () async { + const values = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9']; + for (final value in values) { + await db.addItem(value, DateTime.now().toIso8601String()); + } + + final itemsToDelete = (await getAll()).toList().sublist(3, 7); + await db.deleteItems(itemsToDelete); + + final readItems = await getAll(); + final readValues = readItems.map((e) => e.value); + expect(readValues, const ['0', '1', '2', '7', '8', '9']); + }); + + test('deletes last subset of stored items', () async { + const values = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9']; + for (final value in values) { + await db.addItem(value, DateTime.now().toIso8601String()); + } + + final itemsToDelete = (await getAll()).toList().sublist(7); + await db.deleteItems(itemsToDelete); + + final readItems = await getAll(); + final readValues = readItems.map((e) => e.value); + expect(readValues, values.sublist(0, 7)); + }); + + test('deletes first, middle, and last subsets of stored items', () async { + const values = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9']; + for (final value in values) { + await db.addItem(value, DateTime.now().toIso8601String()); + } + + const valuesToDelete = ['0', '1', '4', '5', '8', '9']; + final itemsToDelete = (await getAll()).where((item) { + return valuesToDelete.contains(item.value); + }); + await db.deleteItems(itemsToDelete); + + final readItems = await getAll(); + final readValues = readItems.map((e) => e.value); + expect(readValues, const ['2', '3', '6', '7']); + }); + + test('deletes inner left and right subsets of stored items', () async { + const values = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9']; + for (final value in values) { + await db.addItem(value, DateTime.now().toIso8601String()); + } + + const valuesToDelete = ['1', '2', '4', '5', '7', '8']; + final itemsToDelete = (await getAll()).where((item) { + return valuesToDelete.contains(item.value); + }); + await db.deleteItems(itemsToDelete); + + final readItems = await getAll(); + final readValues = readItems.map((e) => e.value); + expect(readValues, const ['0', '3', '6', '9']); + }); + + test('deletes the first stored item', () async { + const values = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9']; + for (final value in values) { + await db.addItem(value, DateTime.now().toIso8601String()); + } + + final itemsToDelete = (await getAll()).toList().sublist(0, 1); + await db.deleteItems(itemsToDelete); + + final readItems = await getAll(); + final readValues = readItems.map((e) => e.value); + expect(readValues, values.sublist(1)); + }); + + test('deletes the last stored item', () async { + const values = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9']; + for (final value in values) { + await db.addItem(value, DateTime.now().toIso8601String()); + } + + final itemsToDelete = (await getAll()).toList().sublist(9); + await db.deleteItems(itemsToDelete); + + final readItems = await getAll(); + final readValues = readItems.map((e) => e.value); + expect(readValues, values.sublist(0, 9)); + }); + + test('throws no error when deleting all items twice', () async { + const values = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9']; + for (final value in values) { + await db.addItem(value, DateTime.now().toIso8601String()); + } + + var readValues = await getAll(); + + await db.deleteItems(readValues); + await db.deleteItems(readValues); + + readValues = await getAll(); + + expect(readValues, isEmpty); + }); + + test('returns all stored items', () async { + const values = ['0', '1', '2', '3', '4', '5']; + for (final value in values) { + await db.addItem(value, DateTime.now().toIso8601String()); + } + + final readItems = await getAll(); + final readValues = readItems.map((e) => e.value); + expect(readValues, values); + }); + + test('returns empty list when no items are stored', () async { + final readItems = await getAll(); + expect(readItems, isEmpty); + }); + + test( + 'checks if storage is full', + () async { + const capacityLimit = 1; + + for (var i = 0; i < 100; i++) { + await db.addItem('0', DateTime.now().toIso8601String()); + } + + var result = await db.isFull(capacityLimit); + expect(result, isFalse); + + // add enough items to exceed capacity limit of 1mb + for (var i = 0; i < 50000; i++) { + await db.addItem('0', DateTime.now().toIso8601String()); + } + + result = await db.isFull(capacityLimit); + expect(result, isTrue); + }, + ); + }); +} From c445577770ceb09dbb606e4c63fe7a2ba9d65489 Mon Sep 17 00:00:00 2001 From: Kha Truong <64438356+khatruong2009@users.noreply.github.com> Date: Thu, 31 Aug 2023 14:23:26 -0700 Subject: [PATCH 13/49] Revert "fix: seeing if moving the queued_item_store_test.dart file into main test directory will fix testing issue" This reverts commit f0337131e988eb8e970335dd6a178d5584c9b5d6. --- .../test/queued_item_store_test.dart | 232 ------------------ 1 file changed, 232 deletions(-) delete mode 100644 packages/logging_cloudwatch/aws_logging_cloudwatch/test/queued_item_store_test.dart diff --git a/packages/logging_cloudwatch/aws_logging_cloudwatch/test/queued_item_store_test.dart b/packages/logging_cloudwatch/aws_logging_cloudwatch/test/queued_item_store_test.dart deleted file mode 100644 index 48e73ca64e4..00000000000 --- a/packages/logging_cloudwatch/aws_logging_cloudwatch/test/queued_item_store_test.dart +++ /dev/null @@ -1,232 +0,0 @@ -// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. -// SPDX-License-Identifier: Apache-2.0 - -import 'package:aws_logging_cloudwatch/src/queued_item_store/in_memory_queued_item_store.dart'; -import 'package:aws_logging_cloudwatch/src/queued_item_store/queued_item_store.dart'; -import 'package:test/test.dart'; - -void main() { - late QueuedItemStore db; - - group('InMemoryQueuedItemStore ', () { - setUpAll(() { - db = InMemoryQueuedItemStore(); - }); - - tearDownAll(() async { - await db.clear(); - }); - - setUp(() async { - await db.clear(); - }); - - Future> getAll() async { - return db.getCount(100); - } - - test('writes values to storage', () async { - const values = ['0', '1', '2', '3', '4', '5']; - for (final value in values) { - await db.addItem(value, DateTime.now().toIso8601String()); - } - - final readItems = await db.getCount(values.length); - final readValues = readItems.map((e) => e.value); - expect(readValues, equals(values)); - }); - - test('returns first n items in storage', () async { - const values = ['0', '1', '2', '3', '4', '5']; - for (final value in values) { - await db.addItem(value, DateTime.now().toIso8601String()); - } - - final readItems = await db.getCount(3); - final readValues = readItems.map((e) => e.value); - expect(readValues, equals(values.sublist(0, 3))); - }); - - test( - 'returns all stored items when get request size exceeds stored item count', - () async { - const values = ['0', '1', '2', '3', '4', '5']; - for (final value in values) { - await db.addItem(value, DateTime.now().toIso8601String()); - } - - final readItems = await db.getCount(100); - final readValues = readItems.map((e) => e.value); - expect(readValues, values); - }); - - test('deletes all items in storage', () async { - const values = ['0', '1', '2', '3', '4', '5']; - for (final value in values) { - await db.addItem(value, DateTime.now().toIso8601String()); - } - - await db.deleteItems(await getAll()); - - final readItems = await getAll(); - expect(readItems, isEmpty); - }); - - test('deletes first subset of stored items', () async { - const values = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9']; - for (final value in values) { - await db.addItem(value, DateTime.now().toIso8601String()); - } - - await db.deleteItems(await db.getCount(3)); - - final readItems = await getAll(); - final readValues = readItems.map((e) => e.value); - expect(readValues, values.sublist(3)); - }); - - test('deletes middle subset of stored items', () async { - const values = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9']; - for (final value in values) { - await db.addItem(value, DateTime.now().toIso8601String()); - } - - final itemsToDelete = (await getAll()).toList().sublist(3, 7); - await db.deleteItems(itemsToDelete); - - final readItems = await getAll(); - final readValues = readItems.map((e) => e.value); - expect(readValues, const ['0', '1', '2', '7', '8', '9']); - }); - - test('deletes last subset of stored items', () async { - const values = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9']; - for (final value in values) { - await db.addItem(value, DateTime.now().toIso8601String()); - } - - final itemsToDelete = (await getAll()).toList().sublist(7); - await db.deleteItems(itemsToDelete); - - final readItems = await getAll(); - final readValues = readItems.map((e) => e.value); - expect(readValues, values.sublist(0, 7)); - }); - - test('deletes first, middle, and last subsets of stored items', () async { - const values = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9']; - for (final value in values) { - await db.addItem(value, DateTime.now().toIso8601String()); - } - - const valuesToDelete = ['0', '1', '4', '5', '8', '9']; - final itemsToDelete = (await getAll()).where((item) { - return valuesToDelete.contains(item.value); - }); - await db.deleteItems(itemsToDelete); - - final readItems = await getAll(); - final readValues = readItems.map((e) => e.value); - expect(readValues, const ['2', '3', '6', '7']); - }); - - test('deletes inner left and right subsets of stored items', () async { - const values = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9']; - for (final value in values) { - await db.addItem(value, DateTime.now().toIso8601String()); - } - - const valuesToDelete = ['1', '2', '4', '5', '7', '8']; - final itemsToDelete = (await getAll()).where((item) { - return valuesToDelete.contains(item.value); - }); - await db.deleteItems(itemsToDelete); - - final readItems = await getAll(); - final readValues = readItems.map((e) => e.value); - expect(readValues, const ['0', '3', '6', '9']); - }); - - test('deletes the first stored item', () async { - const values = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9']; - for (final value in values) { - await db.addItem(value, DateTime.now().toIso8601String()); - } - - final itemsToDelete = (await getAll()).toList().sublist(0, 1); - await db.deleteItems(itemsToDelete); - - final readItems = await getAll(); - final readValues = readItems.map((e) => e.value); - expect(readValues, values.sublist(1)); - }); - - test('deletes the last stored item', () async { - const values = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9']; - for (final value in values) { - await db.addItem(value, DateTime.now().toIso8601String()); - } - - final itemsToDelete = (await getAll()).toList().sublist(9); - await db.deleteItems(itemsToDelete); - - final readItems = await getAll(); - final readValues = readItems.map((e) => e.value); - expect(readValues, values.sublist(0, 9)); - }); - - test('throws no error when deleting all items twice', () async { - const values = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9']; - for (final value in values) { - await db.addItem(value, DateTime.now().toIso8601String()); - } - - var readValues = await getAll(); - - await db.deleteItems(readValues); - await db.deleteItems(readValues); - - readValues = await getAll(); - - expect(readValues, isEmpty); - }); - - test('returns all stored items', () async { - const values = ['0', '1', '2', '3', '4', '5']; - for (final value in values) { - await db.addItem(value, DateTime.now().toIso8601String()); - } - - final readItems = await getAll(); - final readValues = readItems.map((e) => e.value); - expect(readValues, values); - }); - - test('returns empty list when no items are stored', () async { - final readItems = await getAll(); - expect(readItems, isEmpty); - }); - - test( - 'checks if storage is full', - () async { - const capacityLimit = 1; - - for (var i = 0; i < 100; i++) { - await db.addItem('0', DateTime.now().toIso8601String()); - } - - var result = await db.isFull(capacityLimit); - expect(result, isFalse); - - // add enough items to exceed capacity limit of 1mb - for (var i = 0; i < 50000; i++) { - await db.addItem('0', DateTime.now().toIso8601String()); - } - - result = await db.isFull(capacityLimit); - expect(result, isTrue); - }, - ); - }); -} From 5d80a8b1df3f9cf7eafaa29221de4652c9f7af94 Mon Sep 17 00:00:00 2001 From: Kha Truong <64438356+khatruong2009@users.noreply.github.com> Date: Thu, 31 Aug 2023 15:20:41 -0700 Subject: [PATCH 14/49] chore: added ignore line for try catch block and removed unnecessary method --- .../lib/src/remote_constraint_provider.dart | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/packages/logging_cloudwatch/aws_logging_cloudwatch/lib/src/remote_constraint_provider.dart b/packages/logging_cloudwatch/aws_logging_cloudwatch/lib/src/remote_constraint_provider.dart index f2aba52b9ce..a4569acb9b8 100644 --- a/packages/logging_cloudwatch/aws_logging_cloudwatch/lib/src/remote_constraint_provider.dart +++ b/packages/logging_cloudwatch/aws_logging_cloudwatch/lib/src/remote_constraint_provider.dart @@ -57,17 +57,6 @@ class DefaultRemoteLoggingConstraintProvider await file.writeAsString(jsonEncode(constraint)); } - Future _getConstraintFromLocalStorage() async { - final file = File('logging_constraint.json'); - if (await file.exists()) { - final content = await file.readAsString(); - return LoggingConstraint.fromJson( - jsonDecode(content) as Map, - ); - } - return null; - } - Future _fetchAndCacheConstraintFromEndpoint() async { try { final constraint = await _fetchConstraintFromEndpoint(); @@ -76,6 +65,7 @@ class DefaultRemoteLoggingConstraintProvider _lastUpdated = DateTime.now(); await _saveConstraintLocally(constraint); } + // ignore: avoid_catches_without_on_clauses } catch (error) { _logger.debug('Error fetching constraints: $error'); } From f7a1c8edfc3da91a38649d48726f4b593f25b177 Mon Sep 17 00:00:00 2001 From: Kha Truong <64438356+khatruong2009@users.noreply.github.com> Date: Fri, 1 Sep 2023 14:02:33 -0700 Subject: [PATCH 15/49] chore: added web implementation of remote_constraint_provider --- .../lib/src/local_storage/io_storage.dart | 25 +++++++++++++++++++ .../lib/src/local_storage/web_storage.dart | 16 ++++++++++++ .../lib/src/plugin_config.dart | 12 +++------ .../lib/src/remote_constraint_provider.dart | 6 +++-- .../aws_logging_cloudwatch/pubspec.yaml | 1 + 5 files changed, 49 insertions(+), 11 deletions(-) create mode 100644 packages/logging_cloudwatch/aws_logging_cloudwatch/lib/src/local_storage/io_storage.dart create mode 100644 packages/logging_cloudwatch/aws_logging_cloudwatch/lib/src/local_storage/web_storage.dart diff --git a/packages/logging_cloudwatch/aws_logging_cloudwatch/lib/src/local_storage/io_storage.dart b/packages/logging_cloudwatch/aws_logging_cloudwatch/lib/src/local_storage/io_storage.dart new file mode 100644 index 00000000000..5008115867a --- /dev/null +++ b/packages/logging_cloudwatch/aws_logging_cloudwatch/lib/src/local_storage/io_storage.dart @@ -0,0 +1,25 @@ +import 'dart:convert'; +import 'dart:io'; + +import 'package:path_provider/path_provider.dart'; + +/// Save constraint locally to file +Future saveConstraintLocally(Map constraint) async { + final directory = await getApplicationSupportDirectory(); + final path = directory.path; + final file = File('$path/logging_constraint.json'); + await file.writeAsString(jsonEncode(constraint)); +} + +/// Load constraint from file +Future?> loadConstraint() async { + final directory = await getApplicationSupportDirectory(); + final path = directory.path; + final file = File('$path/logging_constraint.json'); + + if (file.existsSync()) { + final content = await file.readAsString(); + return jsonDecode(content) as Map; + } + return null; +} diff --git a/packages/logging_cloudwatch/aws_logging_cloudwatch/lib/src/local_storage/web_storage.dart b/packages/logging_cloudwatch/aws_logging_cloudwatch/lib/src/local_storage/web_storage.dart new file mode 100644 index 00000000000..95c3531958b --- /dev/null +++ b/packages/logging_cloudwatch/aws_logging_cloudwatch/lib/src/local_storage/web_storage.dart @@ -0,0 +1,16 @@ +import 'dart:convert'; +import 'dart:html'; + +/// Save constraint locally to web storage +Future saveConstraintLocally(Map constraint) async { + window.localStorage['logging_constraint'] = jsonEncode(constraint); +} + +/// Load constraint from web storage +Map? loadConstraint() { + final content = window.localStorage['logging_constraint']; + if (content != null) { + return jsonDecode(content) as Map; + } + return null; +} diff --git a/packages/logging_cloudwatch/aws_logging_cloudwatch/lib/src/plugin_config.dart b/packages/logging_cloudwatch/aws_logging_cloudwatch/lib/src/plugin_config.dart index 5c8ad68af99..8a31e2c0da6 100644 --- a/packages/logging_cloudwatch/aws_logging_cloudwatch/lib/src/plugin_config.dart +++ b/packages/logging_cloudwatch/aws_logging_cloudwatch/lib/src/plugin_config.dart @@ -57,18 +57,12 @@ class LoggingConstraint with AWSDebuggable { const LoggingConstraint({this.defaultLogLevel = LogLevel.error}); /// Converts a [Map] to an [LoggingConstraint] instance. - // factory LoggingConstraint.fromJson(Map json) { - // return LoggingConstraint( - // defaultLogLevel: LogLevel.values.firstWhere( - // (e) => e.toString() == 'LogLevel.${json['defaultLogLevel']}', - // orElse: () => LogLevel.error, // Default value if not found - // ), - // ); - // } - factory LoggingConstraint.fromJson(Map json) => _$LoggingConstraintFromJson(json); + /// Converts an [LoggingConstraint] instance to a [Map]. + Map toJson() => _$LoggingConstraintToJson(this); + /// The default [LogLevel] for sending logs to CloudWatch. final LogLevel defaultLogLevel; diff --git a/packages/logging_cloudwatch/aws_logging_cloudwatch/lib/src/remote_constraint_provider.dart b/packages/logging_cloudwatch/aws_logging_cloudwatch/lib/src/remote_constraint_provider.dart index a4569acb9b8..063e5cbbf14 100644 --- a/packages/logging_cloudwatch/aws_logging_cloudwatch/lib/src/remote_constraint_provider.dart +++ b/packages/logging_cloudwatch/aws_logging_cloudwatch/lib/src/remote_constraint_provider.dart @@ -10,6 +10,9 @@ import 'dart:io'; import 'package:amplify_core/amplify_core.dart'; import 'package:aws_logging_cloudwatch/aws_logging_cloudwatch.dart'; +import 'package:aws_logging_cloudwatch/src/local_storage/io_storage.dart' + if (dart.library.html) 'package:aws_logging_cloudwatch/src/local_storage/web_storage.dart' + as storage; import 'package:aws_signature_v4/aws_signature_v4.dart'; import 'package:http/http.dart' as http; @@ -53,8 +56,7 @@ class DefaultRemoteLoggingConstraintProvider Timer? _timer; Future _saveConstraintLocally(LoggingConstraint constraint) async { - final file = File('logging_constraint.json'); - await file.writeAsString(jsonEncode(constraint)); + await storage.saveConstraintLocally(constraint.toJson()); } Future _fetchAndCacheConstraintFromEndpoint() async { diff --git a/packages/logging_cloudwatch/aws_logging_cloudwatch/pubspec.yaml b/packages/logging_cloudwatch/aws_logging_cloudwatch/pubspec.yaml index 0d823134c5c..c3febc1440a 100644 --- a/packages/logging_cloudwatch/aws_logging_cloudwatch/pubspec.yaml +++ b/packages/logging_cloudwatch/aws_logging_cloudwatch/pubspec.yaml @@ -19,6 +19,7 @@ dependencies: intl: ">=0.18.0 <1.0.0" json_annotation: ^4.8.1 meta: ^1.9.1 + path_provider: ^2.1.1 smithy: ^0.5.0+3 smithy_aws: ^0.5.0+3 From 8910a19b650538340e636ff08b02c0cec4c2002a Mon Sep 17 00:00:00 2001 From: Kha Truong <64438356+khatruong2009@users.noreply.github.com> Date: Fri, 1 Sep 2023 14:36:18 -0700 Subject: [PATCH 16/49] fix: try changing path provider dependency to fix test --- packages/logging_cloudwatch/aws_logging_cloudwatch/pubspec.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/logging_cloudwatch/aws_logging_cloudwatch/pubspec.yaml b/packages/logging_cloudwatch/aws_logging_cloudwatch/pubspec.yaml index c3febc1440a..d8257783b50 100644 --- a/packages/logging_cloudwatch/aws_logging_cloudwatch/pubspec.yaml +++ b/packages/logging_cloudwatch/aws_logging_cloudwatch/pubspec.yaml @@ -19,7 +19,7 @@ dependencies: intl: ">=0.18.0 <1.0.0" json_annotation: ^4.8.1 meta: ^1.9.1 - path_provider: ^2.1.1 + path_provider: ^2.0.1 smithy: ^0.5.0+3 smithy_aws: ^0.5.0+3 From 146fd034b6111918d2a495c96004aa79b113a0aa Mon Sep 17 00:00:00 2001 From: Kha Truong <64438356+khatruong2009@users.noreply.github.com> Date: Fri, 1 Sep 2023 15:18:44 -0700 Subject: [PATCH 17/49] fix: added flutter sdk to dependencies --- .../logging_cloudwatch/aws_logging_cloudwatch/pubspec.yaml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/packages/logging_cloudwatch/aws_logging_cloudwatch/pubspec.yaml b/packages/logging_cloudwatch/aws_logging_cloudwatch/pubspec.yaml index d8257783b50..ee57936307f 100644 --- a/packages/logging_cloudwatch/aws_logging_cloudwatch/pubspec.yaml +++ b/packages/logging_cloudwatch/aws_logging_cloudwatch/pubspec.yaml @@ -6,6 +6,7 @@ repository: https://github.com/aws-amplify/amplify-flutter/tree/main/packages/aw issue_tracker: https://github.com/aws-amplify/amplify-flutter/issues environment: +flutter: ">=3.10.0" sdk: "^3.0.0" dependencies: @@ -15,6 +16,8 @@ dependencies: built_collection: ^5.1.1 built_value: ">=8.6.0 <8.7.0" fixnum: ^1.1.0 + flutter: + sdk: flutter http: ^1.0.0 intl: ">=0.18.0 <1.0.0" json_annotation: ^4.8.1 From 2e7fa8a9d11b0dfd9b958b5a6e41182ce07ccdaf Mon Sep 17 00:00:00 2001 From: Kha Truong <64438356+khatruong2009@users.noreply.github.com> Date: Fri, 1 Sep 2023 15:21:43 -0700 Subject: [PATCH 18/49] chore: generated workflows after adding dependencies --- .github/dependabot.yaml | 24 ------------------- .../workflows/amplify_logging_cloudwatch.yaml | 6 ----- 2 files changed, 30 deletions(-) diff --git a/.github/dependabot.yaml b/.github/dependabot.yaml index 02f212d71d2..9f0591219fd 100644 --- a/.github/dependabot.yaml +++ b/.github/dependabot.yaml @@ -814,9 +814,6 @@ updates: - dependency-name: "amplify_lints" - dependency-name: "aws_signature_v4" - dependency-name: "amplify_db_common_dart" - - dependency-name: "aws_logging_cloudwatch" - - dependency-name: "smithy" - - dependency-name: "smithy_aws" - package-ecosystem: "pub" directory: "packages/logging_cloudwatch/amplify_logging_cloudwatch/example" schedule: @@ -827,21 +824,6 @@ updates: update-types: - "version-update:semver-patch" - dependency-name: "amplify_lints" - - package-ecosystem: "pub" - directory: "packages/logging_cloudwatch/aws_logging_cloudwatch" - schedule: - interval: "daily" - ignore: - # Ignore patch version bumps - - dependency-name: "*" - update-types: - - "version-update:semver-patch" - - dependency-name: "amplify_core" - - dependency-name: "aws_common" - - dependency-name: "amplify_lints" - - dependency-name: "aws_signature_v4" - - dependency-name: "smithy" - - dependency-name: "smithy_aws" - package-ecosystem: "pub" directory: "packages/logging_cloudwatch/aws_logging_cloudwatch/example" schedule: @@ -851,13 +833,7 @@ updates: - dependency-name: "*" update-types: - "version-update:semver-patch" - - dependency-name: "aws_logging_cloudwatch" - - dependency-name: "amplify_core" - - dependency-name: "aws_common" - dependency-name: "amplify_lints" - - dependency-name: "aws_signature_v4" - - dependency-name: "smithy" - - dependency-name: "smithy_aws" - package-ecosystem: "pub" directory: "packages/notifications/push/amplify_push_notifications" schedule: diff --git a/.github/workflows/amplify_logging_cloudwatch.yaml b/.github/workflows/amplify_logging_cloudwatch.yaml index 10e6f6751de..d3c9083bb01 100644 --- a/.github/workflows/amplify_logging_cloudwatch.yaml +++ b/.github/workflows/amplify_logging_cloudwatch.yaml @@ -26,12 +26,6 @@ on: - 'packages/logging_cloudwatch/amplify_logging_cloudwatch/**/*.yaml' - 'packages/logging_cloudwatch/amplify_logging_cloudwatch/lib/**/*' - 'packages/logging_cloudwatch/amplify_logging_cloudwatch/test/**/*' - - 'packages/logging_cloudwatch/aws_logging_cloudwatch/lib/**/*.dart' - - 'packages/logging_cloudwatch/aws_logging_cloudwatch/pubspec.yaml' - - 'packages/smithy/smithy/lib/**/*.dart' - - 'packages/smithy/smithy/pubspec.yaml' - - 'packages/smithy/smithy_aws/lib/**/*.dart' - - 'packages/smithy/smithy_aws/pubspec.yaml' schedule: - cron: "0 0 * * 0" # Every Sunday at 00:00 defaults: From 846a7cea21793465c4d4292513c670f7c5d7f449 Mon Sep 17 00:00:00 2001 From: Kha Truong <64438356+khatruong2009@users.noreply.github.com> Date: Fri, 1 Sep 2023 15:36:54 -0700 Subject: [PATCH 19/49] fix: fixed indentation issue in pubspec --- packages/logging_cloudwatch/aws_logging_cloudwatch/pubspec.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/logging_cloudwatch/aws_logging_cloudwatch/pubspec.yaml b/packages/logging_cloudwatch/aws_logging_cloudwatch/pubspec.yaml index ee57936307f..173e1560798 100644 --- a/packages/logging_cloudwatch/aws_logging_cloudwatch/pubspec.yaml +++ b/packages/logging_cloudwatch/aws_logging_cloudwatch/pubspec.yaml @@ -6,7 +6,7 @@ repository: https://github.com/aws-amplify/amplify-flutter/tree/main/packages/aw issue_tracker: https://github.com/aws-amplify/amplify-flutter/issues environment: -flutter: ">=3.10.0" + flutter: ">=3.10.0" sdk: "^3.0.0" dependencies: From 1d8b832b22a25146a9cab58031e37ec33ff25dbb Mon Sep 17 00:00:00 2001 From: Kha Truong <64438356+khatruong2009@users.noreply.github.com> Date: Fri, 1 Sep 2023 15:40:25 -0700 Subject: [PATCH 20/49] chore: generate new workflows --- .github/dependabot.yaml | 24 +++++++++++++++++++ .../workflows/amplify_logging_cloudwatch.yaml | 6 +++++ .github/workflows/aws_logging_cloudwatch.yaml | 23 ++---------------- 3 files changed, 32 insertions(+), 21 deletions(-) diff --git a/.github/dependabot.yaml b/.github/dependabot.yaml index 9f0591219fd..02f212d71d2 100644 --- a/.github/dependabot.yaml +++ b/.github/dependabot.yaml @@ -814,6 +814,9 @@ updates: - dependency-name: "amplify_lints" - dependency-name: "aws_signature_v4" - dependency-name: "amplify_db_common_dart" + - dependency-name: "aws_logging_cloudwatch" + - dependency-name: "smithy" + - dependency-name: "smithy_aws" - package-ecosystem: "pub" directory: "packages/logging_cloudwatch/amplify_logging_cloudwatch/example" schedule: @@ -824,6 +827,21 @@ updates: update-types: - "version-update:semver-patch" - dependency-name: "amplify_lints" + - package-ecosystem: "pub" + directory: "packages/logging_cloudwatch/aws_logging_cloudwatch" + schedule: + interval: "daily" + ignore: + # Ignore patch version bumps + - dependency-name: "*" + update-types: + - "version-update:semver-patch" + - dependency-name: "amplify_core" + - dependency-name: "aws_common" + - dependency-name: "amplify_lints" + - dependency-name: "aws_signature_v4" + - dependency-name: "smithy" + - dependency-name: "smithy_aws" - package-ecosystem: "pub" directory: "packages/logging_cloudwatch/aws_logging_cloudwatch/example" schedule: @@ -833,7 +851,13 @@ updates: - dependency-name: "*" update-types: - "version-update:semver-patch" + - dependency-name: "aws_logging_cloudwatch" + - dependency-name: "amplify_core" + - dependency-name: "aws_common" - dependency-name: "amplify_lints" + - dependency-name: "aws_signature_v4" + - dependency-name: "smithy" + - dependency-name: "smithy_aws" - package-ecosystem: "pub" directory: "packages/notifications/push/amplify_push_notifications" schedule: diff --git a/.github/workflows/amplify_logging_cloudwatch.yaml b/.github/workflows/amplify_logging_cloudwatch.yaml index d3c9083bb01..10e6f6751de 100644 --- a/.github/workflows/amplify_logging_cloudwatch.yaml +++ b/.github/workflows/amplify_logging_cloudwatch.yaml @@ -26,6 +26,12 @@ on: - 'packages/logging_cloudwatch/amplify_logging_cloudwatch/**/*.yaml' - 'packages/logging_cloudwatch/amplify_logging_cloudwatch/lib/**/*' - 'packages/logging_cloudwatch/amplify_logging_cloudwatch/test/**/*' + - 'packages/logging_cloudwatch/aws_logging_cloudwatch/lib/**/*.dart' + - 'packages/logging_cloudwatch/aws_logging_cloudwatch/pubspec.yaml' + - 'packages/smithy/smithy/lib/**/*.dart' + - 'packages/smithy/smithy/pubspec.yaml' + - 'packages/smithy/smithy_aws/lib/**/*.dart' + - 'packages/smithy/smithy_aws/pubspec.yaml' schedule: - cron: "0 0 * * 0" # Every Sunday at 00:00 defaults: diff --git a/.github/workflows/aws_logging_cloudwatch.yaml b/.github/workflows/aws_logging_cloudwatch.yaml index 901c6c12fd4..4ae5a356064 100644 --- a/.github/workflows/aws_logging_cloudwatch.yaml +++ b/.github/workflows/aws_logging_cloudwatch.yaml @@ -11,8 +11,7 @@ on: - '.github/workflows/aws_logging_cloudwatch.yaml' - '.github/workflows/dart_dart2js.yaml' - '.github/workflows/dart_ddc.yaml' - - '.github/workflows/dart_native.yaml' - - '.github/workflows/dart_vm.yaml' + - '.github/workflows/flutter_vm.yaml' - 'packages/amplify_core/lib/**/*.dart' - 'packages/amplify_core/pubspec.yaml' - 'packages/amplify_lints/lib/**/*.yaml' @@ -38,25 +37,7 @@ permissions: read-all jobs: test: - uses: ./.github/workflows/dart_vm.yaml - with: - package-name: aws_logging_cloudwatch - working-directory: packages/logging_cloudwatch/aws_logging_cloudwatch - native_test: - needs: test - uses: ./.github/workflows/dart_native.yaml - with: - package-name: aws_logging_cloudwatch - working-directory: packages/logging_cloudwatch/aws_logging_cloudwatch - ddc_test: - needs: test - uses: ./.github/workflows/dart_ddc.yaml - with: - package-name: aws_logging_cloudwatch - working-directory: packages/logging_cloudwatch/aws_logging_cloudwatch - dart2js_test: - needs: test - uses: ./.github/workflows/dart_dart2js.yaml + uses: ./.github/workflows/flutter_vm.yaml with: package-name: aws_logging_cloudwatch working-directory: packages/logging_cloudwatch/aws_logging_cloudwatch From 32840579c38c97d3cf91c929733e79fa56ae0fbd Mon Sep 17 00:00:00 2001 From: Kha Truong <64438356+khatruong2009@users.noreply.github.com> Date: Tue, 5 Sep 2023 13:19:07 -0700 Subject: [PATCH 21/49] chore: changed file and folder names for file_storage --- .../io_storage.dart => file_storage/file_storage.vm.dart} | 0 .../web_storage.dart => file_storage/file_storage.web.dart} | 0 2 files changed, 0 insertions(+), 0 deletions(-) rename packages/logging_cloudwatch/aws_logging_cloudwatch/lib/src/{local_storage/io_storage.dart => file_storage/file_storage.vm.dart} (100%) rename packages/logging_cloudwatch/aws_logging_cloudwatch/lib/src/{local_storage/web_storage.dart => file_storage/file_storage.web.dart} (100%) diff --git a/packages/logging_cloudwatch/aws_logging_cloudwatch/lib/src/local_storage/io_storage.dart b/packages/logging_cloudwatch/aws_logging_cloudwatch/lib/src/file_storage/file_storage.vm.dart similarity index 100% rename from packages/logging_cloudwatch/aws_logging_cloudwatch/lib/src/local_storage/io_storage.dart rename to packages/logging_cloudwatch/aws_logging_cloudwatch/lib/src/file_storage/file_storage.vm.dart diff --git a/packages/logging_cloudwatch/aws_logging_cloudwatch/lib/src/local_storage/web_storage.dart b/packages/logging_cloudwatch/aws_logging_cloudwatch/lib/src/file_storage/file_storage.web.dart similarity index 100% rename from packages/logging_cloudwatch/aws_logging_cloudwatch/lib/src/local_storage/web_storage.dart rename to packages/logging_cloudwatch/aws_logging_cloudwatch/lib/src/file_storage/file_storage.web.dart From c16fddce8120f09c58876ad72ad56c96a8a3d787 Mon Sep 17 00:00:00 2001 From: Kha Truong <64438356+khatruong2009@users.noreply.github.com> Date: Tue, 5 Sep 2023 13:41:25 -0700 Subject: [PATCH 22/49] chore: fix import for renamed files, added region as a required field to DefaultRemoteConfiguration and fixed scope variable to adjust for that. Also moved scope variable to inside fetchConstraintFromEndpoint method --- .../lib/src/remote_constraint_provider.dart | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/packages/logging_cloudwatch/aws_logging_cloudwatch/lib/src/remote_constraint_provider.dart b/packages/logging_cloudwatch/aws_logging_cloudwatch/lib/src/remote_constraint_provider.dart index 063e5cbbf14..dbc4f76e8df 100644 --- a/packages/logging_cloudwatch/aws_logging_cloudwatch/lib/src/remote_constraint_provider.dart +++ b/packages/logging_cloudwatch/aws_logging_cloudwatch/lib/src/remote_constraint_provider.dart @@ -10,8 +10,8 @@ import 'dart:io'; import 'package:amplify_core/amplify_core.dart'; import 'package:aws_logging_cloudwatch/aws_logging_cloudwatch.dart'; -import 'package:aws_logging_cloudwatch/src/local_storage/io_storage.dart' - if (dart.library.html) 'package:aws_logging_cloudwatch/src/local_storage/web_storage.dart' +import 'package:aws_logging_cloudwatch/src/file_storage/file_storage.vm.dart' + if (dart.library.html) 'package:aws_logging_cloudwatch/src/file_storage/file_storage.web.dart' as storage; import 'package:aws_signature_v4/aws_signature_v4.dart'; import 'package:http/http.dart' as http; @@ -48,9 +48,6 @@ class DefaultRemoteLoggingConstraintProvider /// The signer to sign the request. static const signer = AWSSigV4Signer(); - /// The scope to sign the request. - final scope = AWSCredentialScope(region: 'us-west-2', service: AWSService.s3); - static final _logger = AmplifyLogger('default-remote-config'); Timer? _timer; @@ -69,7 +66,7 @@ class DefaultRemoteLoggingConstraintProvider } // ignore: avoid_catches_without_on_clauses } catch (error) { - _logger.debug('Error fetching constraints: $error'); + _logger.error('Error fetching constraints: $error'); } } @@ -78,6 +75,11 @@ class DefaultRemoteLoggingConstraintProvider final request = AWSHttpRequest(method: AWSHttpMethod.get, uri: uri); + final scope = AWSCredentialScope( + region: _config.region, + service: AWSService.apiGatewayManagementApi, + ); + final signedRequest = await signer.sign( request, credentialScope: scope, @@ -145,6 +147,7 @@ class DefaultRemoteConfiguration { const DefaultRemoteConfiguration({ required this.endpoint, this.refreshIntervalInSeconds = const Duration(seconds: 1200), + required this.region, }); /// The endpoint to fetch the `loggingConstraint`. @@ -152,4 +155,7 @@ class DefaultRemoteConfiguration { /// The referesh interval in seconds to fetch the `loggingConstraint`. final Duration refreshIntervalInSeconds; + + /// The region of the endpoint. + final String region; } From e23c57e4edc8beef7eceb906756ee8bdd74fce14 Mon Sep 17 00:00:00 2001 From: Kha Truong <64438356+khatruong2009@users.noreply.github.com> Date: Tue, 5 Sep 2023 13:55:49 -0700 Subject: [PATCH 23/49] replaced AmplifyLogger with AWSLoggerMixin instead. --- .../lib/src/remote_constraint_provider.dart | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/packages/logging_cloudwatch/aws_logging_cloudwatch/lib/src/remote_constraint_provider.dart b/packages/logging_cloudwatch/aws_logging_cloudwatch/lib/src/remote_constraint_provider.dart index dbc4f76e8df..b2c13bbbd14 100644 --- a/packages/logging_cloudwatch/aws_logging_cloudwatch/lib/src/remote_constraint_provider.dart +++ b/packages/logging_cloudwatch/aws_logging_cloudwatch/lib/src/remote_constraint_provider.dart @@ -31,6 +31,7 @@ abstract class RemoteLoggingConstraintProvider { /// [LoggingConstraint] from an http endpoint periodically. /// {@endtemplate} class DefaultRemoteLoggingConstraintProvider + with AWSDebuggable, AWSLoggerMixin implements RemoteLoggingConstraintProvider { /// {@macro aws_logging_cloudwatch.default_remote_logging_constraint_provider} DefaultRemoteLoggingConstraintProvider({ @@ -48,10 +49,11 @@ class DefaultRemoteLoggingConstraintProvider /// The signer to sign the request. static const signer = AWSSigV4Signer(); - static final _logger = AmplifyLogger('default-remote-config'); - Timer? _timer; + @override + String get runtimeTypeName => 'DefaultRemoteLoggingConstraintProvider'; + Future _saveConstraintLocally(LoggingConstraint constraint) async { await storage.saveConstraintLocally(constraint.toJson()); } @@ -66,7 +68,7 @@ class DefaultRemoteLoggingConstraintProvider } // ignore: avoid_catches_without_on_clauses } catch (error) { - _logger.error('Error fetching constraints: $error'); + logger.error('Error fetching constraints: $error'); } } From 5af00ef7e60f58b144adb53919fbe0d23dc943e8 Mon Sep 17 00:00:00 2001 From: Kha Truong <64438356+khatruong2009@users.noreply.github.com> Date: Tue, 5 Sep 2023 14:34:24 -0700 Subject: [PATCH 24/49] chore: made signer private and used AWSHttpRequest.get method directly rather than calling it through AWSHttpRequest --- .../lib/src/remote_constraint_provider.dart | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/logging_cloudwatch/aws_logging_cloudwatch/lib/src/remote_constraint_provider.dart b/packages/logging_cloudwatch/aws_logging_cloudwatch/lib/src/remote_constraint_provider.dart index b2c13bbbd14..40c7f743fda 100644 --- a/packages/logging_cloudwatch/aws_logging_cloudwatch/lib/src/remote_constraint_provider.dart +++ b/packages/logging_cloudwatch/aws_logging_cloudwatch/lib/src/remote_constraint_provider.dart @@ -47,7 +47,7 @@ class DefaultRemoteLoggingConstraintProvider DateTime? _lastUpdated; /// The signer to sign the request. - static const signer = AWSSigV4Signer(); + static const _signer = AWSSigV4Signer(); Timer? _timer; @@ -75,14 +75,14 @@ class DefaultRemoteLoggingConstraintProvider Future _fetchConstraintFromEndpoint() async { final uri = Uri.parse(_config.endpoint); - final request = AWSHttpRequest(method: AWSHttpMethod.get, uri: uri); + final request = AWSHttpRequest.get(uri); final scope = AWSCredentialScope( region: _config.region, service: AWSService.apiGatewayManagementApi, ); - final signedRequest = await signer.sign( + final signedRequest = await _signer.sign( request, credentialScope: scope, ); From c54361b0db9fb90f0612d58fc4eba0eceeecb6e0 Mon Sep 17 00:00:00 2001 From: Kha Truong <64438356+khatruong2009@users.noreply.github.com> Date: Tue, 5 Sep 2023 14:49:18 -0700 Subject: [PATCH 25/49] use stoppable timer instead of while loop --- .../lib/src/remote_constraint_provider.dart | 24 +++++++++++++++---- 1 file changed, 19 insertions(+), 5 deletions(-) diff --git a/packages/logging_cloudwatch/aws_logging_cloudwatch/lib/src/remote_constraint_provider.dart b/packages/logging_cloudwatch/aws_logging_cloudwatch/lib/src/remote_constraint_provider.dart index 40c7f743fda..a625005d387 100644 --- a/packages/logging_cloudwatch/aws_logging_cloudwatch/lib/src/remote_constraint_provider.dart +++ b/packages/logging_cloudwatch/aws_logging_cloudwatch/lib/src/remote_constraint_provider.dart @@ -51,6 +51,13 @@ class DefaultRemoteLoggingConstraintProvider Timer? _timer; + bool isRunning = false; + + void stop() { + _timer?.cancel(); + isRunning = false; + } + @override String get runtimeTypeName => 'DefaultRemoteLoggingConstraintProvider'; @@ -132,12 +139,19 @@ class DefaultRemoteLoggingConstraintProvider /// Refreshes the constraint from the endpoint periodically. Future _refreshConstraintPeriodically() async { - while (true) { - _timer?.cancel(); - _timer = Timer.periodic(_config.refreshIntervalInSeconds, (timer) async { - await _fetchAndCacheConstraintFromEndpoint(); - }); + if (isRunning) { + return; } + + isRunning = true; + _timer?.cancel(); + + _timer = Timer.periodic( + _config.refreshIntervalInSeconds, + (Timer timer) async { + await _fetchAndCacheConstraintFromEndpoint(); + }, + ); } } From 079ae34e045eb8888aacd3c491a86da883a3ceff Mon Sep 17 00:00:00 2001 From: Kha Truong <64438356+khatruong2009@users.noreply.github.com> Date: Tue, 5 Sep 2023 15:54:02 -0700 Subject: [PATCH 26/49] chore: updated LoggingConstraint class to match the remote config file --- .../aws_logging_cloudwatch/.flutter-plugins | 6 ++++ .../.flutter-plugins-dependencies | 1 + .../example/.flutter-plugins | 6 ++++ .../example/.flutter-plugins-dependencies | 1 + .../lib/src/plugin_config.dart | 36 ++++++++++++++++++- .../lib/src/plugin_config.g.dart | 22 ++++++++++++ 6 files changed, 71 insertions(+), 1 deletion(-) create mode 100644 packages/logging_cloudwatch/aws_logging_cloudwatch/.flutter-plugins create mode 100644 packages/logging_cloudwatch/aws_logging_cloudwatch/.flutter-plugins-dependencies create mode 100644 packages/logging_cloudwatch/aws_logging_cloudwatch/example/.flutter-plugins create mode 100644 packages/logging_cloudwatch/aws_logging_cloudwatch/example/.flutter-plugins-dependencies diff --git a/packages/logging_cloudwatch/aws_logging_cloudwatch/.flutter-plugins b/packages/logging_cloudwatch/aws_logging_cloudwatch/.flutter-plugins new file mode 100644 index 00000000000..45b348ac281 --- /dev/null +++ b/packages/logging_cloudwatch/aws_logging_cloudwatch/.flutter-plugins @@ -0,0 +1,6 @@ +# This is a generated file; do not edit or check into version control. +path_provider=/Users/ktruon/.pub-cache/hosted/pub.dev/path_provider-2.1.1/ +path_provider_android=/Users/ktruon/.pub-cache/hosted/pub.dev/path_provider_android-2.2.0/ +path_provider_foundation=/Users/ktruon/.pub-cache/hosted/pub.dev/path_provider_foundation-2.3.1/ +path_provider_linux=/Users/ktruon/.pub-cache/hosted/pub.dev/path_provider_linux-2.2.1/ +path_provider_windows=/Users/ktruon/.pub-cache/hosted/pub.dev/path_provider_windows-2.2.1/ diff --git a/packages/logging_cloudwatch/aws_logging_cloudwatch/.flutter-plugins-dependencies b/packages/logging_cloudwatch/aws_logging_cloudwatch/.flutter-plugins-dependencies new file mode 100644 index 00000000000..3276c30eff1 --- /dev/null +++ b/packages/logging_cloudwatch/aws_logging_cloudwatch/.flutter-plugins-dependencies @@ -0,0 +1 @@ +{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"path_provider_foundation","path":"/Users/ktruon/.pub-cache/hosted/pub.dev/path_provider_foundation-2.3.1/","shared_darwin_source":true,"native_build":true,"dependencies":[]}],"android":[{"name":"path_provider_android","path":"/Users/ktruon/.pub-cache/hosted/pub.dev/path_provider_android-2.2.0/","native_build":true,"dependencies":[]}],"macos":[{"name":"path_provider_foundation","path":"/Users/ktruon/.pub-cache/hosted/pub.dev/path_provider_foundation-2.3.1/","shared_darwin_source":true,"native_build":true,"dependencies":[]}],"linux":[{"name":"path_provider_linux","path":"/Users/ktruon/.pub-cache/hosted/pub.dev/path_provider_linux-2.2.1/","native_build":false,"dependencies":[]}],"windows":[{"name":"path_provider_windows","path":"/Users/ktruon/.pub-cache/hosted/pub.dev/path_provider_windows-2.2.1/","native_build":false,"dependencies":[]}],"web":[]},"dependencyGraph":[{"name":"path_provider","dependencies":["path_provider_android","path_provider_foundation","path_provider_linux","path_provider_windows"]},{"name":"path_provider_android","dependencies":[]},{"name":"path_provider_foundation","dependencies":[]},{"name":"path_provider_linux","dependencies":[]},{"name":"path_provider_windows","dependencies":[]}],"date_created":"2023-09-05 15:49:54.060950","version":"3.10.6"} \ No newline at end of file diff --git a/packages/logging_cloudwatch/aws_logging_cloudwatch/example/.flutter-plugins b/packages/logging_cloudwatch/aws_logging_cloudwatch/example/.flutter-plugins new file mode 100644 index 00000000000..45b348ac281 --- /dev/null +++ b/packages/logging_cloudwatch/aws_logging_cloudwatch/example/.flutter-plugins @@ -0,0 +1,6 @@ +# This is a generated file; do not edit or check into version control. +path_provider=/Users/ktruon/.pub-cache/hosted/pub.dev/path_provider-2.1.1/ +path_provider_android=/Users/ktruon/.pub-cache/hosted/pub.dev/path_provider_android-2.2.0/ +path_provider_foundation=/Users/ktruon/.pub-cache/hosted/pub.dev/path_provider_foundation-2.3.1/ +path_provider_linux=/Users/ktruon/.pub-cache/hosted/pub.dev/path_provider_linux-2.2.1/ +path_provider_windows=/Users/ktruon/.pub-cache/hosted/pub.dev/path_provider_windows-2.2.1/ diff --git a/packages/logging_cloudwatch/aws_logging_cloudwatch/example/.flutter-plugins-dependencies b/packages/logging_cloudwatch/aws_logging_cloudwatch/example/.flutter-plugins-dependencies new file mode 100644 index 00000000000..33828a49db4 --- /dev/null +++ b/packages/logging_cloudwatch/aws_logging_cloudwatch/example/.flutter-plugins-dependencies @@ -0,0 +1 @@ +{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"path_provider_foundation","path":"/Users/ktruon/.pub-cache/hosted/pub.dev/path_provider_foundation-2.3.1/","shared_darwin_source":true,"native_build":true,"dependencies":[]}],"android":[{"name":"path_provider_android","path":"/Users/ktruon/.pub-cache/hosted/pub.dev/path_provider_android-2.2.0/","native_build":true,"dependencies":[]}],"macos":[{"name":"path_provider_foundation","path":"/Users/ktruon/.pub-cache/hosted/pub.dev/path_provider_foundation-2.3.1/","shared_darwin_source":true,"native_build":true,"dependencies":[]}],"linux":[{"name":"path_provider_linux","path":"/Users/ktruon/.pub-cache/hosted/pub.dev/path_provider_linux-2.2.1/","native_build":false,"dependencies":[]}],"windows":[{"name":"path_provider_windows","path":"/Users/ktruon/.pub-cache/hosted/pub.dev/path_provider_windows-2.2.1/","native_build":false,"dependencies":[]}],"web":[]},"dependencyGraph":[{"name":"path_provider","dependencies":["path_provider_android","path_provider_foundation","path_provider_linux","path_provider_windows"]},{"name":"path_provider_android","dependencies":[]},{"name":"path_provider_foundation","dependencies":[]},{"name":"path_provider_linux","dependencies":[]},{"name":"path_provider_windows","dependencies":[]}],"date_created":"2023-09-05 15:49:54.108026","version":"3.10.6"} \ No newline at end of file diff --git a/packages/logging_cloudwatch/aws_logging_cloudwatch/lib/src/plugin_config.dart b/packages/logging_cloudwatch/aws_logging_cloudwatch/lib/src/plugin_config.dart index 8a31e2c0da6..83e5c7fda50 100644 --- a/packages/logging_cloudwatch/aws_logging_cloudwatch/lib/src/plugin_config.dart +++ b/packages/logging_cloudwatch/aws_logging_cloudwatch/lib/src/plugin_config.dart @@ -54,7 +54,11 @@ class CloudWatchLoggerPluginConfiguration with AWSDebuggable { @JsonSerializable() class LoggingConstraint with AWSDebuggable { /// {@macro aws_logging_cloudwatch.logging_constraint} - const LoggingConstraint({this.defaultLogLevel = LogLevel.error}); + const LoggingConstraint({ + this.defaultLogLevel = LogLevel.error, + this.categoryLogLevel, + this.userLogLevel, + }); /// Converts a [Map] to an [LoggingConstraint] instance. factory LoggingConstraint.fromJson(Map json) => @@ -66,6 +70,36 @@ class LoggingConstraint with AWSDebuggable { /// The default [LogLevel] for sending logs to CloudWatch. final LogLevel defaultLogLevel; + /// The [LogLevel] for different categories. + final Map? categoryLogLevel; + + /// The [LogLevel] for different users. + final Map? userLogLevel; + @override String get runtimeTypeName => 'LoggingConstraint'; } + +@JsonSerializable() + +/// The logging constraint for user specific log level. +class UserLogLevel { + /// The logging constraint for user specific log level. + const UserLogLevel({ + this.defaultLogLevel, + this.categoryLogLevel, + }); + + ///Converts a [Map] to a [UserLogLevel] instance. + factory UserLogLevel.fromJson(Map json) => + _$UserLogLevelFromJson(json); + + /// Converts a [UserLogLevel] instance to a [Map]. + Map toJson() => _$UserLogLevelToJson(this); + + /// The default [LogLevel] for sending logs to CloudWatch. + final LogLevel? defaultLogLevel; + + /// The [LogLevel] for different categories. + final Map? categoryLogLevel; +} diff --git a/packages/logging_cloudwatch/aws_logging_cloudwatch/lib/src/plugin_config.g.dart b/packages/logging_cloudwatch/aws_logging_cloudwatch/lib/src/plugin_config.g.dart index f3ed0674a61..6fd6cd2a90f 100644 --- a/packages/logging_cloudwatch/aws_logging_cloudwatch/lib/src/plugin_config.g.dart +++ b/packages/logging_cloudwatch/aws_logging_cloudwatch/lib/src/plugin_config.g.dart @@ -11,11 +11,17 @@ LoggingConstraint _$LoggingConstraintFromJson(Map json) => defaultLogLevel: $enumDecodeNullable(_$LogLevelEnumMap, json['defaultLogLevel']) ?? LogLevel.error, + categoryLogLevel: + (json['categoryLogLevel'] as Map?)?.map( + (k, e) => MapEntry(k, $enumDecode(_$LogLevelEnumMap, e)), + ), ); Map _$LoggingConstraintToJson(LoggingConstraint instance) => { 'defaultLogLevel': _$LogLevelEnumMap[instance.defaultLogLevel]!, + 'categoryLogLevel': instance.categoryLogLevel + ?.map((k, e) => MapEntry(k, _$LogLevelEnumMap[e]!)), }; const _$LogLevelEnumMap = { @@ -26,3 +32,19 @@ const _$LogLevelEnumMap = { LogLevel.error: 'error', LogLevel.none: 'none', }; + +UserLogLevel _$UserLogLevelFromJson(Map json) => UserLogLevel( + defaultLogLevel: + $enumDecodeNullable(_$LogLevelEnumMap, json['defaultLogLevel']), + categoryLogLevel: + (json['categoryLogLevel'] as Map?)?.map( + (k, e) => MapEntry(k, $enumDecode(_$LogLevelEnumMap, e)), + ), + ); + +Map _$UserLogLevelToJson(UserLogLevel instance) => + { + 'defaultLogLevel': _$LogLevelEnumMap[instance.defaultLogLevel], + 'categoryLogLevel': instance.categoryLogLevel + ?.map((k, e) => MapEntry(k, _$LogLevelEnumMap[e]!)), + }; From a4ae5d484bf16c926f2c7604e18f4cccf1ccea35 Mon Sep 17 00:00:00 2001 From: Kha Truong <64438356+khatruong2009@users.noreply.github.com> Date: Tue, 5 Sep 2023 16:00:42 -0700 Subject: [PATCH 27/49] chore: added AWSHeaders.accept to the headers for the request --- .../lib/src/remote_constraint_provider.dart | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/packages/logging_cloudwatch/aws_logging_cloudwatch/lib/src/remote_constraint_provider.dart b/packages/logging_cloudwatch/aws_logging_cloudwatch/lib/src/remote_constraint_provider.dart index a625005d387..79acce7bdaf 100644 --- a/packages/logging_cloudwatch/aws_logging_cloudwatch/lib/src/remote_constraint_provider.dart +++ b/packages/logging_cloudwatch/aws_logging_cloudwatch/lib/src/remote_constraint_provider.dart @@ -98,7 +98,13 @@ class DefaultRemoteLoggingConstraintProvider MapEntry.new, ); - final response = await http.get(uri, headers: headers); + final response = await http.get( + uri, + headers: { + ...headers, + HttpHeaders.acceptHeader: 'application/json; charset=utf-8' + }, + ); // final response = await http.get(Uri.parse(_config.endpoint)); if (response.statusCode == 200) { From d798b405e9f27edfc6e60102cfcd138b35c8b030 Mon Sep 17 00:00:00 2001 From: Kha Truong <64438356+khatruong2009@users.noreply.github.com> Date: Wed, 6 Sep 2023 09:49:12 -0700 Subject: [PATCH 28/49] chore: added public documentation and trailing comma --- .../lib/src/remote_constraint_provider.dart | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/packages/logging_cloudwatch/aws_logging_cloudwatch/lib/src/remote_constraint_provider.dart b/packages/logging_cloudwatch/aws_logging_cloudwatch/lib/src/remote_constraint_provider.dart index 79acce7bdaf..331086bf8fb 100644 --- a/packages/logging_cloudwatch/aws_logging_cloudwatch/lib/src/remote_constraint_provider.dart +++ b/packages/logging_cloudwatch/aws_logging_cloudwatch/lib/src/remote_constraint_provider.dart @@ -51,8 +51,10 @@ class DefaultRemoteLoggingConstraintProvider Timer? _timer; + /// Whether the periodic fetch is running. bool isRunning = false; + /// Stops the periodic fetch. void stop() { _timer?.cancel(); isRunning = false; @@ -102,7 +104,7 @@ class DefaultRemoteLoggingConstraintProvider uri, headers: { ...headers, - HttpHeaders.acceptHeader: 'application/json; charset=utf-8' + HttpHeaders.acceptHeader: 'application/json; charset=utf-8', }, ); From 36e493c1fe312279be278d4316b834120b82fa0f Mon Sep 17 00:00:00 2001 From: Kha Truong <64438356+khatruong2009@users.noreply.github.com> Date: Wed, 6 Sep 2023 10:37:56 -0700 Subject: [PATCH 29/49] chore: removed unnecessary time checks in the getter if statement --- .../lib/src/remote_constraint_provider.dart | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/packages/logging_cloudwatch/aws_logging_cloudwatch/lib/src/remote_constraint_provider.dart b/packages/logging_cloudwatch/aws_logging_cloudwatch/lib/src/remote_constraint_provider.dart index 331086bf8fb..48531d6af71 100644 --- a/packages/logging_cloudwatch/aws_logging_cloudwatch/lib/src/remote_constraint_provider.dart +++ b/packages/logging_cloudwatch/aws_logging_cloudwatch/lib/src/remote_constraint_provider.dart @@ -108,7 +108,6 @@ class DefaultRemoteLoggingConstraintProvider }, ); - // final response = await http.get(Uri.parse(_config.endpoint)); if (response.statusCode == 200) { final fetchedConstraint = LoggingConstraint.fromJson( jsonDecode(response.body) as Map, @@ -122,10 +121,7 @@ class DefaultRemoteLoggingConstraintProvider @override LoggingConstraint? get loggingConstraint { - if (_loggingConstraint != null && - _lastUpdated != null && - DateTime.now().difference(_lastUpdated!).inSeconds <= - _config.refreshIntervalInSeconds.inSeconds) { + if (_loggingConstraint != null && _lastUpdated != null) { return _loggingConstraint; } // Load from local storage synchronously From 568da90714a0eb4faa2c62ebf1038d2ccd49f8d8 Mon Sep 17 00:00:00 2001 From: Kha Truong <64438356+khatruong2009@users.noreply.github.com> Date: Wed, 6 Sep 2023 12:39:55 -0700 Subject: [PATCH 30/49] chore: removed initialize() method and put it into the constructor --- .../aws_logging_cloudwatch/.flutter-plugins | 6 ------ .../.flutter-plugins-dependencies | 1 - .../lib/src/remote_constraint_provider.dart | 11 ++++------- 3 files changed, 4 insertions(+), 14 deletions(-) delete mode 100644 packages/logging_cloudwatch/aws_logging_cloudwatch/.flutter-plugins delete mode 100644 packages/logging_cloudwatch/aws_logging_cloudwatch/.flutter-plugins-dependencies diff --git a/packages/logging_cloudwatch/aws_logging_cloudwatch/.flutter-plugins b/packages/logging_cloudwatch/aws_logging_cloudwatch/.flutter-plugins deleted file mode 100644 index 45b348ac281..00000000000 --- a/packages/logging_cloudwatch/aws_logging_cloudwatch/.flutter-plugins +++ /dev/null @@ -1,6 +0,0 @@ -# This is a generated file; do not edit or check into version control. -path_provider=/Users/ktruon/.pub-cache/hosted/pub.dev/path_provider-2.1.1/ -path_provider_android=/Users/ktruon/.pub-cache/hosted/pub.dev/path_provider_android-2.2.0/ -path_provider_foundation=/Users/ktruon/.pub-cache/hosted/pub.dev/path_provider_foundation-2.3.1/ -path_provider_linux=/Users/ktruon/.pub-cache/hosted/pub.dev/path_provider_linux-2.2.1/ -path_provider_windows=/Users/ktruon/.pub-cache/hosted/pub.dev/path_provider_windows-2.2.1/ diff --git a/packages/logging_cloudwatch/aws_logging_cloudwatch/.flutter-plugins-dependencies b/packages/logging_cloudwatch/aws_logging_cloudwatch/.flutter-plugins-dependencies deleted file mode 100644 index 3276c30eff1..00000000000 --- a/packages/logging_cloudwatch/aws_logging_cloudwatch/.flutter-plugins-dependencies +++ /dev/null @@ -1 +0,0 @@ -{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"path_provider_foundation","path":"/Users/ktruon/.pub-cache/hosted/pub.dev/path_provider_foundation-2.3.1/","shared_darwin_source":true,"native_build":true,"dependencies":[]}],"android":[{"name":"path_provider_android","path":"/Users/ktruon/.pub-cache/hosted/pub.dev/path_provider_android-2.2.0/","native_build":true,"dependencies":[]}],"macos":[{"name":"path_provider_foundation","path":"/Users/ktruon/.pub-cache/hosted/pub.dev/path_provider_foundation-2.3.1/","shared_darwin_source":true,"native_build":true,"dependencies":[]}],"linux":[{"name":"path_provider_linux","path":"/Users/ktruon/.pub-cache/hosted/pub.dev/path_provider_linux-2.2.1/","native_build":false,"dependencies":[]}],"windows":[{"name":"path_provider_windows","path":"/Users/ktruon/.pub-cache/hosted/pub.dev/path_provider_windows-2.2.1/","native_build":false,"dependencies":[]}],"web":[]},"dependencyGraph":[{"name":"path_provider","dependencies":["path_provider_android","path_provider_foundation","path_provider_linux","path_provider_windows"]},{"name":"path_provider_android","dependencies":[]},{"name":"path_provider_foundation","dependencies":[]},{"name":"path_provider_linux","dependencies":[]},{"name":"path_provider_windows","dependencies":[]}],"date_created":"2023-09-05 15:49:54.060950","version":"3.10.6"} \ No newline at end of file diff --git a/packages/logging_cloudwatch/aws_logging_cloudwatch/lib/src/remote_constraint_provider.dart b/packages/logging_cloudwatch/aws_logging_cloudwatch/lib/src/remote_constraint_provider.dart index 48531d6af71..794fb195d46 100644 --- a/packages/logging_cloudwatch/aws_logging_cloudwatch/lib/src/remote_constraint_provider.dart +++ b/packages/logging_cloudwatch/aws_logging_cloudwatch/lib/src/remote_constraint_provider.dart @@ -38,7 +38,10 @@ class DefaultRemoteLoggingConstraintProvider required DefaultRemoteConfiguration config, required AWSCredentialsProvider credentialsProvider, }) : _config = config, - _credentialsProvider = credentialsProvider; + _credentialsProvider = credentialsProvider { + _fetchAndCacheConstraintFromEndpoint(); // Fetch once immediately on initialize + _refreshConstraintPeriodically(); + } final DefaultRemoteConfiguration _config; final AWSCredentialsProvider _credentialsProvider; @@ -135,12 +138,6 @@ class DefaultRemoteLoggingConstraintProvider return null; } - /// Initializes and starts the periodic fetch. - void initialize() { - _fetchAndCacheConstraintFromEndpoint(); // Fetch once immediately on initialize - _refreshConstraintPeriodically(); - } - /// Refreshes the constraint from the endpoint periodically. Future _refreshConstraintPeriodically() async { if (isRunning) { From 416e19b3bae31d20b606ceb536a556593b1ec70c Mon Sep 17 00:00:00 2001 From: Kha Truong <64438356+khatruong2009@users.noreply.github.com> Date: Wed, 6 Sep 2023 13:05:52 -0700 Subject: [PATCH 31/49] chore: removed unnecessary lastUpdate variable now that it is no longer checked in the getter --- .../lib/src/remote_constraint_provider.dart | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/packages/logging_cloudwatch/aws_logging_cloudwatch/lib/src/remote_constraint_provider.dart b/packages/logging_cloudwatch/aws_logging_cloudwatch/lib/src/remote_constraint_provider.dart index 794fb195d46..79453b2a48a 100644 --- a/packages/logging_cloudwatch/aws_logging_cloudwatch/lib/src/remote_constraint_provider.dart +++ b/packages/logging_cloudwatch/aws_logging_cloudwatch/lib/src/remote_constraint_provider.dart @@ -47,7 +47,6 @@ class DefaultRemoteLoggingConstraintProvider final AWSCredentialsProvider _credentialsProvider; LoggingConstraint? _loggingConstraint; - DateTime? _lastUpdated; /// The signer to sign the request. static const _signer = AWSSigV4Signer(); @@ -75,7 +74,6 @@ class DefaultRemoteLoggingConstraintProvider final constraint = await _fetchConstraintFromEndpoint(); if (constraint != null) { _loggingConstraint = constraint; - _lastUpdated = DateTime.now(); await _saveConstraintLocally(constraint); } // ignore: avoid_catches_without_on_clauses @@ -124,7 +122,7 @@ class DefaultRemoteLoggingConstraintProvider @override LoggingConstraint? get loggingConstraint { - if (_loggingConstraint != null && _lastUpdated != null) { + if (_loggingConstraint != null) { return _loggingConstraint; } // Load from local storage synchronously From 100338b0efd9086fe22590ced8952d76523697c1 Mon Sep 17 00:00:00 2001 From: Kha Truong <64438356+khatruong2009@users.noreply.github.com> Date: Wed, 6 Sep 2023 15:28:12 -0700 Subject: [PATCH 32/49] chore: added a comment and removed flutter plugin files --- .../aws_logging_cloudwatch/example/.flutter-plugins | 6 ------ .../example/.flutter-plugins-dependencies | 1 - .../lib/src/remote_constraint_provider.dart | 1 + 3 files changed, 1 insertion(+), 7 deletions(-) delete mode 100644 packages/logging_cloudwatch/aws_logging_cloudwatch/example/.flutter-plugins delete mode 100644 packages/logging_cloudwatch/aws_logging_cloudwatch/example/.flutter-plugins-dependencies diff --git a/packages/logging_cloudwatch/aws_logging_cloudwatch/example/.flutter-plugins b/packages/logging_cloudwatch/aws_logging_cloudwatch/example/.flutter-plugins deleted file mode 100644 index 45b348ac281..00000000000 --- a/packages/logging_cloudwatch/aws_logging_cloudwatch/example/.flutter-plugins +++ /dev/null @@ -1,6 +0,0 @@ -# This is a generated file; do not edit or check into version control. -path_provider=/Users/ktruon/.pub-cache/hosted/pub.dev/path_provider-2.1.1/ -path_provider_android=/Users/ktruon/.pub-cache/hosted/pub.dev/path_provider_android-2.2.0/ -path_provider_foundation=/Users/ktruon/.pub-cache/hosted/pub.dev/path_provider_foundation-2.3.1/ -path_provider_linux=/Users/ktruon/.pub-cache/hosted/pub.dev/path_provider_linux-2.2.1/ -path_provider_windows=/Users/ktruon/.pub-cache/hosted/pub.dev/path_provider_windows-2.2.1/ diff --git a/packages/logging_cloudwatch/aws_logging_cloudwatch/example/.flutter-plugins-dependencies b/packages/logging_cloudwatch/aws_logging_cloudwatch/example/.flutter-plugins-dependencies deleted file mode 100644 index 33828a49db4..00000000000 --- a/packages/logging_cloudwatch/aws_logging_cloudwatch/example/.flutter-plugins-dependencies +++ /dev/null @@ -1 +0,0 @@ -{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"path_provider_foundation","path":"/Users/ktruon/.pub-cache/hosted/pub.dev/path_provider_foundation-2.3.1/","shared_darwin_source":true,"native_build":true,"dependencies":[]}],"android":[{"name":"path_provider_android","path":"/Users/ktruon/.pub-cache/hosted/pub.dev/path_provider_android-2.2.0/","native_build":true,"dependencies":[]}],"macos":[{"name":"path_provider_foundation","path":"/Users/ktruon/.pub-cache/hosted/pub.dev/path_provider_foundation-2.3.1/","shared_darwin_source":true,"native_build":true,"dependencies":[]}],"linux":[{"name":"path_provider_linux","path":"/Users/ktruon/.pub-cache/hosted/pub.dev/path_provider_linux-2.2.1/","native_build":false,"dependencies":[]}],"windows":[{"name":"path_provider_windows","path":"/Users/ktruon/.pub-cache/hosted/pub.dev/path_provider_windows-2.2.1/","native_build":false,"dependencies":[]}],"web":[]},"dependencyGraph":[{"name":"path_provider","dependencies":["path_provider_android","path_provider_foundation","path_provider_linux","path_provider_windows"]},{"name":"path_provider_android","dependencies":[]},{"name":"path_provider_foundation","dependencies":[]},{"name":"path_provider_linux","dependencies":[]},{"name":"path_provider_windows","dependencies":[]}],"date_created":"2023-09-05 15:49:54.108026","version":"3.10.6"} \ No newline at end of file diff --git a/packages/logging_cloudwatch/aws_logging_cloudwatch/lib/src/remote_constraint_provider.dart b/packages/logging_cloudwatch/aws_logging_cloudwatch/lib/src/remote_constraint_provider.dart index 79453b2a48a..e22dce74850 100644 --- a/packages/logging_cloudwatch/aws_logging_cloudwatch/lib/src/remote_constraint_provider.dart +++ b/packages/logging_cloudwatch/aws_logging_cloudwatch/lib/src/remote_constraint_provider.dart @@ -51,6 +51,7 @@ class DefaultRemoteLoggingConstraintProvider /// The signer to sign the request. static const _signer = AWSSigV4Signer(); + // The timer to refresh the constraint periodically. Timer? _timer; /// Whether the periodic fetch is running. From 7d7dac35f1754f37444fa3bf4ef057e425e39358 Mon Sep 17 00:00:00 2001 From: Kha Truong <64438356+khatruong2009@users.noreply.github.com> Date: Thu, 7 Sep 2023 09:41:11 -0700 Subject: [PATCH 33/49] chore: fixed some formatting --- .../aws_logging_cloudwatch/lib/src/plugin_config.dart | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/packages/logging_cloudwatch/aws_logging_cloudwatch/lib/src/plugin_config.dart b/packages/logging_cloudwatch/aws_logging_cloudwatch/lib/src/plugin_config.dart index 83e5c7fda50..0b43428b50f 100644 --- a/packages/logging_cloudwatch/aws_logging_cloudwatch/lib/src/plugin_config.dart +++ b/packages/logging_cloudwatch/aws_logging_cloudwatch/lib/src/plugin_config.dart @@ -50,7 +50,6 @@ class CloudWatchLoggerPluginConfiguration with AWSDebuggable { /// {@template aws_logging_cloudwatch.logging_constraint} /// The logging constraint for sending logs to CloudWatch. /// {@endtemplate} - @JsonSerializable() class LoggingConstraint with AWSDebuggable { /// {@macro aws_logging_cloudwatch.logging_constraint} @@ -80,9 +79,8 @@ class LoggingConstraint with AWSDebuggable { String get runtimeTypeName => 'LoggingConstraint'; } -@JsonSerializable() - /// The logging constraint for user specific log level. +@JsonSerializable() class UserLogLevel { /// The logging constraint for user specific log level. const UserLogLevel({ From cb9a912c4cf4bd356b91ee2bd875b1a7a0a58425 Mon Sep 17 00:00:00 2001 From: Kha Truong <64438356+khatruong2009@users.noreply.github.com> Date: Thu, 7 Sep 2023 09:46:10 -0700 Subject: [PATCH 34/49] chore: removed the InSeconds part of the refreshIntervalInSeconds property because it's a Duration, which isn't specific to seconds --- .../lib/src/cloudwatch_logger_plugin.dart | 4 ++-- .../aws_logging_cloudwatch/lib/src/plugin_config.dart | 6 +++--- .../lib/src/remote_constraint_provider.dart | 6 +++--- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/packages/logging_cloudwatch/aws_logging_cloudwatch/lib/src/cloudwatch_logger_plugin.dart b/packages/logging_cloudwatch/aws_logging_cloudwatch/lib/src/cloudwatch_logger_plugin.dart index 22fe2c1cbed..7a28ea8aa0a 100644 --- a/packages/logging_cloudwatch/aws_logging_cloudwatch/lib/src/cloudwatch_logger_plugin.dart +++ b/packages/logging_cloudwatch/aws_logging_cloudwatch/lib/src/cloudwatch_logger_plugin.dart @@ -76,9 +76,9 @@ class CloudWatchLoggerPlugin extends AWSLoggerPlugin region: pluginConfig.region, credentialsProvider: credentialsProvider, ) { - _timer = pluginConfig.flushIntervalInSeconds > Duration.zero + _timer = pluginConfig.flushInterval > Duration.zero ? StoppableTimer( - duration: pluginConfig.flushIntervalInSeconds, + duration: pluginConfig.flushInterval, callback: _startSyncingIfNotInProgress, onError: _onTimerError, ) diff --git a/packages/logging_cloudwatch/aws_logging_cloudwatch/lib/src/plugin_config.dart b/packages/logging_cloudwatch/aws_logging_cloudwatch/lib/src/plugin_config.dart index 0b43428b50f..540036ba9f0 100644 --- a/packages/logging_cloudwatch/aws_logging_cloudwatch/lib/src/plugin_config.dart +++ b/packages/logging_cloudwatch/aws_logging_cloudwatch/lib/src/plugin_config.dart @@ -18,7 +18,7 @@ class CloudWatchLoggerPluginConfiguration with AWSDebuggable { required this.localLoggingConstraint, this.enable = true, this.localStoreMaxSizeInMB = 5, - this.flushIntervalInSeconds = const Duration(seconds: 60), + this.flushInterval = const Duration(seconds: 60), this.defaultRemoteConfiguration, }); @@ -34,8 +34,8 @@ class CloudWatchLoggerPluginConfiguration with AWSDebuggable { /// The max size of the local store in MB to be used for storing logs locally. final int localStoreMaxSizeInMB; - /// The duration in seconds for sending locally stored logs to CloudWatch. - final Duration flushIntervalInSeconds; + /// The duration for sending locally stored logs to CloudWatch. + final Duration flushInterval; /// {@macro aws_logging_cloudwatch.logging_constraint} final LoggingConstraint localLoggingConstraint; diff --git a/packages/logging_cloudwatch/aws_logging_cloudwatch/lib/src/remote_constraint_provider.dart b/packages/logging_cloudwatch/aws_logging_cloudwatch/lib/src/remote_constraint_provider.dart index e22dce74850..a7f50c43181 100644 --- a/packages/logging_cloudwatch/aws_logging_cloudwatch/lib/src/remote_constraint_provider.dart +++ b/packages/logging_cloudwatch/aws_logging_cloudwatch/lib/src/remote_constraint_provider.dart @@ -147,7 +147,7 @@ class DefaultRemoteLoggingConstraintProvider _timer?.cancel(); _timer = Timer.periodic( - _config.refreshIntervalInSeconds, + _config.refreshInterval, (Timer timer) async { await _fetchAndCacheConstraintFromEndpoint(); }, @@ -162,7 +162,7 @@ class DefaultRemoteConfiguration { /// {@macro aws_logging_cloudwatch.default_remote_configuration} const DefaultRemoteConfiguration({ required this.endpoint, - this.refreshIntervalInSeconds = const Duration(seconds: 1200), + this.refreshInterval = const Duration(seconds: 1200), required this.region, }); @@ -170,7 +170,7 @@ class DefaultRemoteConfiguration { final String endpoint; /// The referesh interval in seconds to fetch the `loggingConstraint`. - final Duration refreshIntervalInSeconds; + final Duration refreshInterval; /// The region of the endpoint. final String region; From c15fdca9d76644847aab3f0908ff2e9ca30474e2 Mon Sep 17 00:00:00 2001 From: Kha Truong <64438356+khatruong2009@users.noreply.github.com> Date: Thu, 7 Sep 2023 09:47:07 -0700 Subject: [PATCH 35/49] chore: fixed comment to reflect change in fetchInterval and flushInterval property name change --- .../lib/src/remote_constraint_provider.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/logging_cloudwatch/aws_logging_cloudwatch/lib/src/remote_constraint_provider.dart b/packages/logging_cloudwatch/aws_logging_cloudwatch/lib/src/remote_constraint_provider.dart index a7f50c43181..9501ed46b47 100644 --- a/packages/logging_cloudwatch/aws_logging_cloudwatch/lib/src/remote_constraint_provider.dart +++ b/packages/logging_cloudwatch/aws_logging_cloudwatch/lib/src/remote_constraint_provider.dart @@ -169,7 +169,7 @@ class DefaultRemoteConfiguration { /// The endpoint to fetch the `loggingConstraint`. final String endpoint; - /// The referesh interval in seconds to fetch the `loggingConstraint`. + /// The referesh interval to fetch the `loggingConstraint`. final Duration refreshInterval; /// The region of the endpoint. From cc069a65c8e23c8c7b2d28bbb83f87bddd8256cd Mon Sep 17 00:00:00 2001 From: Kha Truong <64438356+khatruong2009@users.noreply.github.com> Date: Thu, 7 Sep 2023 09:49:19 -0700 Subject: [PATCH 36/49] chore: make isRunning variable privatge --- .../lib/src/remote_constraint_provider.dart | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/logging_cloudwatch/aws_logging_cloudwatch/lib/src/remote_constraint_provider.dart b/packages/logging_cloudwatch/aws_logging_cloudwatch/lib/src/remote_constraint_provider.dart index 9501ed46b47..0f83ffa9e19 100644 --- a/packages/logging_cloudwatch/aws_logging_cloudwatch/lib/src/remote_constraint_provider.dart +++ b/packages/logging_cloudwatch/aws_logging_cloudwatch/lib/src/remote_constraint_provider.dart @@ -55,12 +55,12 @@ class DefaultRemoteLoggingConstraintProvider Timer? _timer; /// Whether the periodic fetch is running. - bool isRunning = false; + bool _isRunning = false; /// Stops the periodic fetch. void stop() { _timer?.cancel(); - isRunning = false; + _isRunning = false; } @override @@ -139,11 +139,11 @@ class DefaultRemoteLoggingConstraintProvider /// Refreshes the constraint from the endpoint periodically. Future _refreshConstraintPeriodically() async { - if (isRunning) { + if (_isRunning) { return; } - isRunning = true; + _isRunning = true; _timer?.cancel(); _timer = Timer.periodic( From dda946b533f43339df4b66b71e4ff6f9d6fefd3f Mon Sep 17 00:00:00 2001 From: Kha Truong <64438356+khatruong2009@users.noreply.github.com> Date: Thu, 7 Sep 2023 10:34:12 -0700 Subject: [PATCH 37/49] chore: corrected error handling in the fetchAndCacheConstraintFromEndpoint method --- .../lib/src/remote_constraint_provider.dart | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/packages/logging_cloudwatch/aws_logging_cloudwatch/lib/src/remote_constraint_provider.dart b/packages/logging_cloudwatch/aws_logging_cloudwatch/lib/src/remote_constraint_provider.dart index 0f83ffa9e19..224058e2326 100644 --- a/packages/logging_cloudwatch/aws_logging_cloudwatch/lib/src/remote_constraint_provider.dart +++ b/packages/logging_cloudwatch/aws_logging_cloudwatch/lib/src/remote_constraint_provider.dart @@ -77,9 +77,14 @@ class DefaultRemoteLoggingConstraintProvider _loggingConstraint = constraint; await _saveConstraintLocally(constraint); } - // ignore: avoid_catches_without_on_clauses - } catch (error) { - logger.error('Error fetching constraints: $error'); + } on Exception catch (exception) { + throw Exception( + 'Failed to fetch logging constraint from ${_config.endpoint}: $exception', + ); + } on Error catch (error) { + logger.error( + 'Error while fetching logging constraint from ${_config.endpoint}: $error', + ); } } From 3cda67c2b0146df5f50a28498581d546230c6cdb Mon Sep 17 00:00:00 2001 From: Kha Truong <64438356+khatruong2009@users.noreply.github.com> Date: Thu, 7 Sep 2023 10:38:45 -0700 Subject: [PATCH 38/49] chore: add license headers to storage implementations --- .../lib/src/file_storage/file_storage.vm.dart | 3 +++ .../lib/src/file_storage/file_storage.web.dart | 3 +++ 2 files changed, 6 insertions(+) diff --git a/packages/logging_cloudwatch/aws_logging_cloudwatch/lib/src/file_storage/file_storage.vm.dart b/packages/logging_cloudwatch/aws_logging_cloudwatch/lib/src/file_storage/file_storage.vm.dart index 5008115867a..094c5343151 100644 --- a/packages/logging_cloudwatch/aws_logging_cloudwatch/lib/src/file_storage/file_storage.vm.dart +++ b/packages/logging_cloudwatch/aws_logging_cloudwatch/lib/src/file_storage/file_storage.vm.dart @@ -1,3 +1,6 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + import 'dart:convert'; import 'dart:io'; diff --git a/packages/logging_cloudwatch/aws_logging_cloudwatch/lib/src/file_storage/file_storage.web.dart b/packages/logging_cloudwatch/aws_logging_cloudwatch/lib/src/file_storage/file_storage.web.dart index 95c3531958b..a0b5541bee6 100644 --- a/packages/logging_cloudwatch/aws_logging_cloudwatch/lib/src/file_storage/file_storage.web.dart +++ b/packages/logging_cloudwatch/aws_logging_cloudwatch/lib/src/file_storage/file_storage.web.dart @@ -1,3 +1,6 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + import 'dart:convert'; import 'dart:html'; From 9482c011799c1e1eec77098d549c1125e680601c Mon Sep 17 00:00:00 2001 From: Kha Truong <64438356+khatruong2009@users.noreply.github.com> Date: Thu, 7 Sep 2023 11:43:34 -0700 Subject: [PATCH 39/49] chore: added path for join() method to ensure windows compatibility --- .../lib/src/file_storage/file_storage.vm.dart | 3 ++- .../logging_cloudwatch/aws_logging_cloudwatch/pubspec.yaml | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/packages/logging_cloudwatch/aws_logging_cloudwatch/lib/src/file_storage/file_storage.vm.dart b/packages/logging_cloudwatch/aws_logging_cloudwatch/lib/src/file_storage/file_storage.vm.dart index 094c5343151..8d9e47437cd 100644 --- a/packages/logging_cloudwatch/aws_logging_cloudwatch/lib/src/file_storage/file_storage.vm.dart +++ b/packages/logging_cloudwatch/aws_logging_cloudwatch/lib/src/file_storage/file_storage.vm.dart @@ -4,13 +4,14 @@ import 'dart:convert'; import 'dart:io'; +import 'package:path/path.dart' as p; import 'package:path_provider/path_provider.dart'; /// Save constraint locally to file Future saveConstraintLocally(Map constraint) async { final directory = await getApplicationSupportDirectory(); final path = directory.path; - final file = File('$path/logging_constraint.json'); + final file = File(p.join(path, 'logging_constraint.json')); await file.writeAsString(jsonEncode(constraint)); } diff --git a/packages/logging_cloudwatch/aws_logging_cloudwatch/pubspec.yaml b/packages/logging_cloudwatch/aws_logging_cloudwatch/pubspec.yaml index 173e1560798..be48a42f01e 100644 --- a/packages/logging_cloudwatch/aws_logging_cloudwatch/pubspec.yaml +++ b/packages/logging_cloudwatch/aws_logging_cloudwatch/pubspec.yaml @@ -22,6 +22,7 @@ dependencies: intl: ">=0.18.0 <1.0.0" json_annotation: ^4.8.1 meta: ^1.9.1 + path: ^1.8.0 path_provider: ^2.0.1 smithy: ^0.5.0+3 smithy_aws: ^0.5.0+3 From dc4d088919d3b0501b26043159643817616578b2 Mon Sep 17 00:00:00 2001 From: Kha Truong <64438356+khatruong2009@users.noreply.github.com> Date: Thu, 7 Sep 2023 14:46:25 -0700 Subject: [PATCH 40/49] chore: removed dart:io dependency, changed HttpHeaders.acceptHeader to AWSHeaders.accept, changed getter to just retrieve from cache --- .../lib/src/remote_constraint_provider.dart | 21 ++++--------------- 1 file changed, 4 insertions(+), 17 deletions(-) diff --git a/packages/logging_cloudwatch/aws_logging_cloudwatch/lib/src/remote_constraint_provider.dart b/packages/logging_cloudwatch/aws_logging_cloudwatch/lib/src/remote_constraint_provider.dart index 224058e2326..56129deec37 100644 --- a/packages/logging_cloudwatch/aws_logging_cloudwatch/lib/src/remote_constraint_provider.dart +++ b/packages/logging_cloudwatch/aws_logging_cloudwatch/lib/src/remote_constraint_provider.dart @@ -3,12 +3,12 @@ import 'dart:async'; import 'dart:convert'; -import 'dart:io'; +import 'package:amplify_core/amplify_core.dart'; // TODO(nikahsn): remove after implementing the get loggingConstraint. // ignore_for_file: unused_field -import 'package:amplify_core/amplify_core.dart'; +import 'package:aws_common/aws_common.dart'; import 'package:aws_logging_cloudwatch/aws_logging_cloudwatch.dart'; import 'package:aws_logging_cloudwatch/src/file_storage/file_storage.vm.dart' if (dart.library.html) 'package:aws_logging_cloudwatch/src/file_storage/file_storage.web.dart' @@ -111,7 +111,7 @@ class DefaultRemoteLoggingConstraintProvider uri, headers: { ...headers, - HttpHeaders.acceptHeader: 'application/json; charset=utf-8', + AWSHeaders.accept: 'application/json; charset=utf-8', }, ); @@ -127,20 +127,7 @@ class DefaultRemoteLoggingConstraintProvider } @override - LoggingConstraint? get loggingConstraint { - if (_loggingConstraint != null) { - return _loggingConstraint; - } - // Load from local storage synchronously - final file = File('logging_constraint.json'); - if (file.existsSync()) { - final content = file.readAsStringSync(); - return LoggingConstraint.fromJson( - jsonDecode(content) as Map, - ); - } - return null; - } + LoggingConstraint? get loggingConstraint => _loggingConstraint; /// Refreshes the constraint from the endpoint periodically. Future _refreshConstraintPeriodically() async { From ca20db0c6e3cf1876e27d1ef32979b6380d102c1 Mon Sep 17 00:00:00 2001 From: Kha Truong <64438356+khatruong2009@users.noreply.github.com> Date: Thu, 7 Sep 2023 14:55:30 -0700 Subject: [PATCH 41/49] chore: remove flutter dependency --- packages/logging_cloudwatch/aws_logging_cloudwatch/pubspec.yaml | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/logging_cloudwatch/aws_logging_cloudwatch/pubspec.yaml b/packages/logging_cloudwatch/aws_logging_cloudwatch/pubspec.yaml index be48a42f01e..233241cecbe 100644 --- a/packages/logging_cloudwatch/aws_logging_cloudwatch/pubspec.yaml +++ b/packages/logging_cloudwatch/aws_logging_cloudwatch/pubspec.yaml @@ -6,7 +6,6 @@ repository: https://github.com/aws-amplify/amplify-flutter/tree/main/packages/aw issue_tracker: https://github.com/aws-amplify/amplify-flutter/issues environment: - flutter: ">=3.10.0" sdk: "^3.0.0" dependencies: From 284c9c09a61866ae40392547f6059c242e4109b3 Mon Sep 17 00:00:00 2001 From: Kha Truong <64438356+khatruong2009@users.noreply.github.com> Date: Thu, 7 Sep 2023 15:28:30 -0700 Subject: [PATCH 42/49] chore: removed http and replaced with AWSHttpClient --- .../aws_logging_cloudwatch/.flutter-plugins | 6 ++++ .../.flutter-plugins-dependencies | 1 + .../example/.flutter-plugins | 6 ++++ .../example/.flutter-plugins-dependencies | 1 + .../lib/src/remote_constraint_provider.dart | 30 ++++++++++++------- .../aws_logging_cloudwatch/pubspec.yaml | 1 - 6 files changed, 34 insertions(+), 11 deletions(-) create mode 100644 packages/logging_cloudwatch/aws_logging_cloudwatch/.flutter-plugins create mode 100644 packages/logging_cloudwatch/aws_logging_cloudwatch/.flutter-plugins-dependencies create mode 100644 packages/logging_cloudwatch/aws_logging_cloudwatch/example/.flutter-plugins create mode 100644 packages/logging_cloudwatch/aws_logging_cloudwatch/example/.flutter-plugins-dependencies diff --git a/packages/logging_cloudwatch/aws_logging_cloudwatch/.flutter-plugins b/packages/logging_cloudwatch/aws_logging_cloudwatch/.flutter-plugins new file mode 100644 index 00000000000..45b348ac281 --- /dev/null +++ b/packages/logging_cloudwatch/aws_logging_cloudwatch/.flutter-plugins @@ -0,0 +1,6 @@ +# This is a generated file; do not edit or check into version control. +path_provider=/Users/ktruon/.pub-cache/hosted/pub.dev/path_provider-2.1.1/ +path_provider_android=/Users/ktruon/.pub-cache/hosted/pub.dev/path_provider_android-2.2.0/ +path_provider_foundation=/Users/ktruon/.pub-cache/hosted/pub.dev/path_provider_foundation-2.3.1/ +path_provider_linux=/Users/ktruon/.pub-cache/hosted/pub.dev/path_provider_linux-2.2.1/ +path_provider_windows=/Users/ktruon/.pub-cache/hosted/pub.dev/path_provider_windows-2.2.1/ diff --git a/packages/logging_cloudwatch/aws_logging_cloudwatch/.flutter-plugins-dependencies b/packages/logging_cloudwatch/aws_logging_cloudwatch/.flutter-plugins-dependencies new file mode 100644 index 00000000000..92da5165468 --- /dev/null +++ b/packages/logging_cloudwatch/aws_logging_cloudwatch/.flutter-plugins-dependencies @@ -0,0 +1 @@ +{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"path_provider_foundation","path":"/Users/ktruon/.pub-cache/hosted/pub.dev/path_provider_foundation-2.3.1/","shared_darwin_source":true,"native_build":true,"dependencies":[]}],"android":[{"name":"path_provider_android","path":"/Users/ktruon/.pub-cache/hosted/pub.dev/path_provider_android-2.2.0/","native_build":true,"dependencies":[]}],"macos":[{"name":"path_provider_foundation","path":"/Users/ktruon/.pub-cache/hosted/pub.dev/path_provider_foundation-2.3.1/","shared_darwin_source":true,"native_build":true,"dependencies":[]}],"linux":[{"name":"path_provider_linux","path":"/Users/ktruon/.pub-cache/hosted/pub.dev/path_provider_linux-2.2.1/","native_build":false,"dependencies":[]}],"windows":[{"name":"path_provider_windows","path":"/Users/ktruon/.pub-cache/hosted/pub.dev/path_provider_windows-2.2.1/","native_build":false,"dependencies":[]}],"web":[]},"dependencyGraph":[{"name":"path_provider","dependencies":["path_provider_android","path_provider_foundation","path_provider_linux","path_provider_windows"]},{"name":"path_provider_android","dependencies":[]},{"name":"path_provider_foundation","dependencies":[]},{"name":"path_provider_linux","dependencies":[]},{"name":"path_provider_windows","dependencies":[]}],"date_created":"2023-09-07 15:25:43.661957","version":"3.10.6"} \ No newline at end of file diff --git a/packages/logging_cloudwatch/aws_logging_cloudwatch/example/.flutter-plugins b/packages/logging_cloudwatch/aws_logging_cloudwatch/example/.flutter-plugins new file mode 100644 index 00000000000..45b348ac281 --- /dev/null +++ b/packages/logging_cloudwatch/aws_logging_cloudwatch/example/.flutter-plugins @@ -0,0 +1,6 @@ +# This is a generated file; do not edit or check into version control. +path_provider=/Users/ktruon/.pub-cache/hosted/pub.dev/path_provider-2.1.1/ +path_provider_android=/Users/ktruon/.pub-cache/hosted/pub.dev/path_provider_android-2.2.0/ +path_provider_foundation=/Users/ktruon/.pub-cache/hosted/pub.dev/path_provider_foundation-2.3.1/ +path_provider_linux=/Users/ktruon/.pub-cache/hosted/pub.dev/path_provider_linux-2.2.1/ +path_provider_windows=/Users/ktruon/.pub-cache/hosted/pub.dev/path_provider_windows-2.2.1/ diff --git a/packages/logging_cloudwatch/aws_logging_cloudwatch/example/.flutter-plugins-dependencies b/packages/logging_cloudwatch/aws_logging_cloudwatch/example/.flutter-plugins-dependencies new file mode 100644 index 00000000000..bca0185956d --- /dev/null +++ b/packages/logging_cloudwatch/aws_logging_cloudwatch/example/.flutter-plugins-dependencies @@ -0,0 +1 @@ +{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"path_provider_foundation","path":"/Users/ktruon/.pub-cache/hosted/pub.dev/path_provider_foundation-2.3.1/","shared_darwin_source":true,"native_build":true,"dependencies":[]}],"android":[{"name":"path_provider_android","path":"/Users/ktruon/.pub-cache/hosted/pub.dev/path_provider_android-2.2.0/","native_build":true,"dependencies":[]}],"macos":[{"name":"path_provider_foundation","path":"/Users/ktruon/.pub-cache/hosted/pub.dev/path_provider_foundation-2.3.1/","shared_darwin_source":true,"native_build":true,"dependencies":[]}],"linux":[{"name":"path_provider_linux","path":"/Users/ktruon/.pub-cache/hosted/pub.dev/path_provider_linux-2.2.1/","native_build":false,"dependencies":[]}],"windows":[{"name":"path_provider_windows","path":"/Users/ktruon/.pub-cache/hosted/pub.dev/path_provider_windows-2.2.1/","native_build":false,"dependencies":[]}],"web":[]},"dependencyGraph":[{"name":"path_provider","dependencies":["path_provider_android","path_provider_foundation","path_provider_linux","path_provider_windows"]},{"name":"path_provider_android","dependencies":[]},{"name":"path_provider_foundation","dependencies":[]},{"name":"path_provider_linux","dependencies":[]},{"name":"path_provider_windows","dependencies":[]}],"date_created":"2023-09-07 15:25:43.712619","version":"3.10.6"} \ No newline at end of file diff --git a/packages/logging_cloudwatch/aws_logging_cloudwatch/lib/src/remote_constraint_provider.dart b/packages/logging_cloudwatch/aws_logging_cloudwatch/lib/src/remote_constraint_provider.dart index 56129deec37..9a9491e0715 100644 --- a/packages/logging_cloudwatch/aws_logging_cloudwatch/lib/src/remote_constraint_provider.dart +++ b/packages/logging_cloudwatch/aws_logging_cloudwatch/lib/src/remote_constraint_provider.dart @@ -14,7 +14,6 @@ import 'package:aws_logging_cloudwatch/src/file_storage/file_storage.vm.dart' if (dart.library.html) 'package:aws_logging_cloudwatch/src/file_storage/file_storage.web.dart' as storage; import 'package:aws_signature_v4/aws_signature_v4.dart'; -import 'package:http/http.dart' as http; /// {@template aws_logging_cloudwatch.remote_logging_constraint_provider} /// An Interface to provide custom implementation for @@ -51,6 +50,8 @@ class DefaultRemoteLoggingConstraintProvider /// The signer to sign the request. static const _signer = AWSSigV4Signer(); + final AWSHttpClient _awsHttpClient = AWSHttpClient(); + // The timer to refresh the constraint periodically. Timer? _timer; @@ -91,7 +92,13 @@ class DefaultRemoteLoggingConstraintProvider Future _fetchConstraintFromEndpoint() async { final uri = Uri.parse(_config.endpoint); - final request = AWSHttpRequest.get(uri); + final request = AWSHttpRequest( + method: AWSHttpMethod.get, + uri: uri, + headers: { + AWSHeaders.host: uri.host, + }, + ); final scope = AWSCredentialScope( region: _config.region, @@ -103,21 +110,24 @@ class DefaultRemoteLoggingConstraintProvider credentialScope: scope, ); - final headers = signedRequest.headers.map( - MapEntry.new, - ); - - final response = await http.get( - uri, + final newRequest = AWSHttpRequest( + method: signedRequest.method, + uri: signedRequest.uri, headers: { - ...headers, + ...signedRequest.headers, AWSHeaders.accept: 'application/json; charset=utf-8', }, ); + final operation = _awsHttpClient.send(newRequest); + + final response = await operation.response; + + final body = await response.decodeBody(); + if (response.statusCode == 200) { final fetchedConstraint = LoggingConstraint.fromJson( - jsonDecode(response.body) as Map, + jsonDecode(body) as Map, ); return fetchedConstraint; } diff --git a/packages/logging_cloudwatch/aws_logging_cloudwatch/pubspec.yaml b/packages/logging_cloudwatch/aws_logging_cloudwatch/pubspec.yaml index 233241cecbe..df00842c671 100644 --- a/packages/logging_cloudwatch/aws_logging_cloudwatch/pubspec.yaml +++ b/packages/logging_cloudwatch/aws_logging_cloudwatch/pubspec.yaml @@ -17,7 +17,6 @@ dependencies: fixnum: ^1.1.0 flutter: sdk: flutter - http: ^1.0.0 intl: ">=0.18.0 <1.0.0" json_annotation: ^4.8.1 meta: ^1.9.1 From 54988d48ae43ac43f82da8a1bd282475751c4732 Mon Sep 17 00:00:00 2001 From: Kha Truong <64438356+khatruong2009@users.noreply.github.com> Date: Thu, 7 Sep 2023 15:44:43 -0700 Subject: [PATCH 43/49] chore: removed unnecessary stop method --- .../lib/src/remote_constraint_provider.dart | 6 ------ 1 file changed, 6 deletions(-) diff --git a/packages/logging_cloudwatch/aws_logging_cloudwatch/lib/src/remote_constraint_provider.dart b/packages/logging_cloudwatch/aws_logging_cloudwatch/lib/src/remote_constraint_provider.dart index 9a9491e0715..57a73a3086c 100644 --- a/packages/logging_cloudwatch/aws_logging_cloudwatch/lib/src/remote_constraint_provider.dart +++ b/packages/logging_cloudwatch/aws_logging_cloudwatch/lib/src/remote_constraint_provider.dart @@ -58,12 +58,6 @@ class DefaultRemoteLoggingConstraintProvider /// Whether the periodic fetch is running. bool _isRunning = false; - /// Stops the periodic fetch. - void stop() { - _timer?.cancel(); - _isRunning = false; - } - @override String get runtimeTypeName => 'DefaultRemoteLoggingConstraintProvider'; From a53841f49b195591e7cef8abb1afe85d3865fe10 Mon Sep 17 00:00:00 2001 From: Kha Truong <64438356+khatruong2009@users.noreply.github.com> Date: Thu, 7 Sep 2023 16:02:38 -0700 Subject: [PATCH 44/49] chore: remove .flutter-plugins files --- .../aws_logging_cloudwatch/.flutter-plugins | 6 ------ .../aws_logging_cloudwatch/.flutter-plugins-dependencies | 1 - .../aws_logging_cloudwatch/example/.flutter-plugins | 6 ------ .../example/.flutter-plugins-dependencies | 1 - 4 files changed, 14 deletions(-) delete mode 100644 packages/logging_cloudwatch/aws_logging_cloudwatch/.flutter-plugins delete mode 100644 packages/logging_cloudwatch/aws_logging_cloudwatch/.flutter-plugins-dependencies delete mode 100644 packages/logging_cloudwatch/aws_logging_cloudwatch/example/.flutter-plugins delete mode 100644 packages/logging_cloudwatch/aws_logging_cloudwatch/example/.flutter-plugins-dependencies diff --git a/packages/logging_cloudwatch/aws_logging_cloudwatch/.flutter-plugins b/packages/logging_cloudwatch/aws_logging_cloudwatch/.flutter-plugins deleted file mode 100644 index 45b348ac281..00000000000 --- a/packages/logging_cloudwatch/aws_logging_cloudwatch/.flutter-plugins +++ /dev/null @@ -1,6 +0,0 @@ -# This is a generated file; do not edit or check into version control. -path_provider=/Users/ktruon/.pub-cache/hosted/pub.dev/path_provider-2.1.1/ -path_provider_android=/Users/ktruon/.pub-cache/hosted/pub.dev/path_provider_android-2.2.0/ -path_provider_foundation=/Users/ktruon/.pub-cache/hosted/pub.dev/path_provider_foundation-2.3.1/ -path_provider_linux=/Users/ktruon/.pub-cache/hosted/pub.dev/path_provider_linux-2.2.1/ -path_provider_windows=/Users/ktruon/.pub-cache/hosted/pub.dev/path_provider_windows-2.2.1/ diff --git a/packages/logging_cloudwatch/aws_logging_cloudwatch/.flutter-plugins-dependencies b/packages/logging_cloudwatch/aws_logging_cloudwatch/.flutter-plugins-dependencies deleted file mode 100644 index 92da5165468..00000000000 --- a/packages/logging_cloudwatch/aws_logging_cloudwatch/.flutter-plugins-dependencies +++ /dev/null @@ -1 +0,0 @@ -{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"path_provider_foundation","path":"/Users/ktruon/.pub-cache/hosted/pub.dev/path_provider_foundation-2.3.1/","shared_darwin_source":true,"native_build":true,"dependencies":[]}],"android":[{"name":"path_provider_android","path":"/Users/ktruon/.pub-cache/hosted/pub.dev/path_provider_android-2.2.0/","native_build":true,"dependencies":[]}],"macos":[{"name":"path_provider_foundation","path":"/Users/ktruon/.pub-cache/hosted/pub.dev/path_provider_foundation-2.3.1/","shared_darwin_source":true,"native_build":true,"dependencies":[]}],"linux":[{"name":"path_provider_linux","path":"/Users/ktruon/.pub-cache/hosted/pub.dev/path_provider_linux-2.2.1/","native_build":false,"dependencies":[]}],"windows":[{"name":"path_provider_windows","path":"/Users/ktruon/.pub-cache/hosted/pub.dev/path_provider_windows-2.2.1/","native_build":false,"dependencies":[]}],"web":[]},"dependencyGraph":[{"name":"path_provider","dependencies":["path_provider_android","path_provider_foundation","path_provider_linux","path_provider_windows"]},{"name":"path_provider_android","dependencies":[]},{"name":"path_provider_foundation","dependencies":[]},{"name":"path_provider_linux","dependencies":[]},{"name":"path_provider_windows","dependencies":[]}],"date_created":"2023-09-07 15:25:43.661957","version":"3.10.6"} \ No newline at end of file diff --git a/packages/logging_cloudwatch/aws_logging_cloudwatch/example/.flutter-plugins b/packages/logging_cloudwatch/aws_logging_cloudwatch/example/.flutter-plugins deleted file mode 100644 index 45b348ac281..00000000000 --- a/packages/logging_cloudwatch/aws_logging_cloudwatch/example/.flutter-plugins +++ /dev/null @@ -1,6 +0,0 @@ -# This is a generated file; do not edit or check into version control. -path_provider=/Users/ktruon/.pub-cache/hosted/pub.dev/path_provider-2.1.1/ -path_provider_android=/Users/ktruon/.pub-cache/hosted/pub.dev/path_provider_android-2.2.0/ -path_provider_foundation=/Users/ktruon/.pub-cache/hosted/pub.dev/path_provider_foundation-2.3.1/ -path_provider_linux=/Users/ktruon/.pub-cache/hosted/pub.dev/path_provider_linux-2.2.1/ -path_provider_windows=/Users/ktruon/.pub-cache/hosted/pub.dev/path_provider_windows-2.2.1/ diff --git a/packages/logging_cloudwatch/aws_logging_cloudwatch/example/.flutter-plugins-dependencies b/packages/logging_cloudwatch/aws_logging_cloudwatch/example/.flutter-plugins-dependencies deleted file mode 100644 index bca0185956d..00000000000 --- a/packages/logging_cloudwatch/aws_logging_cloudwatch/example/.flutter-plugins-dependencies +++ /dev/null @@ -1 +0,0 @@ -{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"path_provider_foundation","path":"/Users/ktruon/.pub-cache/hosted/pub.dev/path_provider_foundation-2.3.1/","shared_darwin_source":true,"native_build":true,"dependencies":[]}],"android":[{"name":"path_provider_android","path":"/Users/ktruon/.pub-cache/hosted/pub.dev/path_provider_android-2.2.0/","native_build":true,"dependencies":[]}],"macos":[{"name":"path_provider_foundation","path":"/Users/ktruon/.pub-cache/hosted/pub.dev/path_provider_foundation-2.3.1/","shared_darwin_source":true,"native_build":true,"dependencies":[]}],"linux":[{"name":"path_provider_linux","path":"/Users/ktruon/.pub-cache/hosted/pub.dev/path_provider_linux-2.2.1/","native_build":false,"dependencies":[]}],"windows":[{"name":"path_provider_windows","path":"/Users/ktruon/.pub-cache/hosted/pub.dev/path_provider_windows-2.2.1/","native_build":false,"dependencies":[]}],"web":[]},"dependencyGraph":[{"name":"path_provider","dependencies":["path_provider_android","path_provider_foundation","path_provider_linux","path_provider_windows"]},{"name":"path_provider_android","dependencies":[]},{"name":"path_provider_foundation","dependencies":[]},{"name":"path_provider_linux","dependencies":[]},{"name":"path_provider_windows","dependencies":[]}],"date_created":"2023-09-07 15:25:43.712619","version":"3.10.6"} \ No newline at end of file From a157210848a0e6825467bbf1b2ffd1f32ba5f7aa Mon Sep 17 00:00:00 2001 From: Kha Truong <64438356+khatruong2009@users.noreply.github.com> Date: Fri, 8 Sep 2023 09:29:39 -0700 Subject: [PATCH 45/49] chore: moved constructor initializers into a separate init function so that I can use async await --- .../lib/src/remote_constraint_provider.dart | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/packages/logging_cloudwatch/aws_logging_cloudwatch/lib/src/remote_constraint_provider.dart b/packages/logging_cloudwatch/aws_logging_cloudwatch/lib/src/remote_constraint_provider.dart index 57a73a3086c..799ae159ff1 100644 --- a/packages/logging_cloudwatch/aws_logging_cloudwatch/lib/src/remote_constraint_provider.dart +++ b/packages/logging_cloudwatch/aws_logging_cloudwatch/lib/src/remote_constraint_provider.dart @@ -38,8 +38,7 @@ class DefaultRemoteLoggingConstraintProvider required AWSCredentialsProvider credentialsProvider, }) : _config = config, _credentialsProvider = credentialsProvider { - _fetchAndCacheConstraintFromEndpoint(); // Fetch once immediately on initialize - _refreshConstraintPeriodically(); + init(); } final DefaultRemoteConfiguration _config; @@ -61,6 +60,15 @@ class DefaultRemoteLoggingConstraintProvider @override String get runtimeTypeName => 'DefaultRemoteLoggingConstraintProvider'; + /// Initializes the [DefaultRemoteLoggingConstraintProvider] by fetching + /// the constraint from the endpoint initially and then + /// starting the refresh timer afterwards. + Future init() async { + await _fetchAndCacheConstraintFromEndpoint(); + await _refreshConstraintPeriodically(); + return null; + } + Future _saveConstraintLocally(LoggingConstraint constraint) async { await storage.saveConstraintLocally(constraint.toJson()); } From 524cf9f5a06d9165542cbb493b9ec8ad49eaadf8 Mon Sep 17 00:00:00 2001 From: Kha Truong <64438356+khatruong2009@users.noreply.github.com> Date: Fri, 8 Sep 2023 09:42:45 -0700 Subject: [PATCH 46/49] chore: added local storage check before fetching in the initialize function --- .../lib/src/remote_constraint_provider.dart | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/packages/logging_cloudwatch/aws_logging_cloudwatch/lib/src/remote_constraint_provider.dart b/packages/logging_cloudwatch/aws_logging_cloudwatch/lib/src/remote_constraint_provider.dart index 799ae159ff1..66fb93e0bcc 100644 --- a/packages/logging_cloudwatch/aws_logging_cloudwatch/lib/src/remote_constraint_provider.dart +++ b/packages/logging_cloudwatch/aws_logging_cloudwatch/lib/src/remote_constraint_provider.dart @@ -64,6 +64,11 @@ class DefaultRemoteLoggingConstraintProvider /// the constraint from the endpoint initially and then /// starting the refresh timer afterwards. Future init() async { + // Check local storage first. + final localConstraint = await storage.loadConstraint(); + if (localConstraint != null) { + _loggingConstraint = LoggingConstraint.fromJson(localConstraint); + } await _fetchAndCacheConstraintFromEndpoint(); await _refreshConstraintPeriodically(); return null; From 950a75895bc94bb4861df0151d13d4d9cee4e79c Mon Sep 17 00:00:00 2001 From: Kha Truong <64438356+khatruong2009@users.noreply.github.com> Date: Fri, 8 Sep 2023 14:59:35 -0700 Subject: [PATCH 47/49] chore: refactored DefaultRemoteLoggingConstraintProvider to separate createRequest from the rest of the class, allowing for signed and unsigned requests to be sent --- .../lib/src/remote_constraint_provider.dart | 137 +++++++++--------- 1 file changed, 72 insertions(+), 65 deletions(-) diff --git a/packages/logging_cloudwatch/aws_logging_cloudwatch/lib/src/remote_constraint_provider.dart b/packages/logging_cloudwatch/aws_logging_cloudwatch/lib/src/remote_constraint_provider.dart index 66fb93e0bcc..1e67721d5d5 100644 --- a/packages/logging_cloudwatch/aws_logging_cloudwatch/lib/src/remote_constraint_provider.dart +++ b/packages/logging_cloudwatch/aws_logging_cloudwatch/lib/src/remote_constraint_provider.dart @@ -14,6 +14,7 @@ import 'package:aws_logging_cloudwatch/src/file_storage/file_storage.vm.dart' if (dart.library.html) 'package:aws_logging_cloudwatch/src/file_storage/file_storage.web.dart' as storage; import 'package:aws_signature_v4/aws_signature_v4.dart'; +import 'package:meta/meta.dart'; /// {@template aws_logging_cloudwatch.remote_logging_constraint_provider} /// An Interface to provide custom implementation for @@ -25,15 +26,15 @@ abstract class RemoteLoggingConstraintProvider { LoggingConstraint? get loggingConstraint; } -/// {@template aws_logging_cloudwatch.default_remote_logging_constraint_provider} -/// Default implementation of [RemoteLoggingConstraintProvider] to fetch -/// [LoggingConstraint] from an http endpoint periodically. +/// {@template aws_logging_cloudwatch.base_remote_constraints_provider} +/// Base class for [RemoteLoggingConstraintProvider] to provide +/// [LoggingConstraint] from a remote location and cache it. /// {@endtemplate} -class DefaultRemoteLoggingConstraintProvider +base class BaseRemoteLoggingConstraintProvider with AWSDebuggable, AWSLoggerMixin implements RemoteLoggingConstraintProvider { - /// {@macro aws_logging_cloudwatch.default_remote_logging_constraint_provider} - DefaultRemoteLoggingConstraintProvider({ + /// {@macro aws_logging_cloudwatch.base_remote_constraints_provider} + BaseRemoteLoggingConstraintProvider({ required DefaultRemoteConfiguration config, required AWSCredentialsProvider credentialsProvider, }) : _config = config, @@ -46,9 +47,6 @@ class DefaultRemoteLoggingConstraintProvider LoggingConstraint? _loggingConstraint; - /// The signer to sign the request. - static const _signer = AWSSigV4Signer(); - final AWSHttpClient _awsHttpClient = AWSHttpClient(); // The timer to refresh the constraint periodically. @@ -57,10 +55,11 @@ class DefaultRemoteLoggingConstraintProvider /// Whether the periodic fetch is running. bool _isRunning = false; + /// Retrives the runtime type name used for logging. @override - String get runtimeTypeName => 'DefaultRemoteLoggingConstraintProvider'; + String get runtimeTypeName => 'BaseRemoteConstraintsProvider'; - /// Initializes the [DefaultRemoteLoggingConstraintProvider] by fetching + /// Initializes the [BaseRemoteLoggingConstraintProvider] by fetching /// the constraint from the endpoint initially and then /// starting the refresh timer afterwards. Future init() async { @@ -74,16 +73,32 @@ class DefaultRemoteLoggingConstraintProvider return null; } - Future _saveConstraintLocally(LoggingConstraint constraint) async { - await storage.saveConstraintLocally(constraint.toJson()); + /// Creates a request to fetch the constraint from the endpoint. + @protected + Future createRequest() async { + final uri = Uri.parse(_config.endpoint); + return AWSHttpRequest( + method: AWSHttpMethod.get, + uri: uri, + headers: const { + AWSHeaders.accept: 'application/json; charset=utf-8', + }, + ); } + /// Fetches the constraint from the endpoint and caches it. Future _fetchAndCacheConstraintFromEndpoint() async { try { - final constraint = await _fetchConstraintFromEndpoint(); - if (constraint != null) { - _loggingConstraint = constraint; - await _saveConstraintLocally(constraint); + final request = await createRequest(); + final operation = _awsHttpClient.send(request); + final response = await operation.response; + final body = await response.decodeBody(); + if (response.statusCode == 200) { + final fetchedConstraint = LoggingConstraint.fromJson( + jsonDecode(body) as Map, + ); + _loggingConstraint = fetchedConstraint; + await storage.saveConstraintLocally(fetchedConstraint.toJson()); } } on Exception catch (exception) { throw Exception( @@ -96,53 +111,7 @@ class DefaultRemoteLoggingConstraintProvider } } - Future _fetchConstraintFromEndpoint() async { - final uri = Uri.parse(_config.endpoint); - - final request = AWSHttpRequest( - method: AWSHttpMethod.get, - uri: uri, - headers: { - AWSHeaders.host: uri.host, - }, - ); - - final scope = AWSCredentialScope( - region: _config.region, - service: AWSService.apiGatewayManagementApi, - ); - - final signedRequest = await _signer.sign( - request, - credentialScope: scope, - ); - - final newRequest = AWSHttpRequest( - method: signedRequest.method, - uri: signedRequest.uri, - headers: { - ...signedRequest.headers, - AWSHeaders.accept: 'application/json; charset=utf-8', - }, - ); - - final operation = _awsHttpClient.send(newRequest); - - final response = await operation.response; - - final body = await response.decodeBody(); - - if (response.statusCode == 200) { - final fetchedConstraint = LoggingConstraint.fromJson( - jsonDecode(body) as Map, - ); - return fetchedConstraint; - } - throw Exception( - 'Failed to fetch logging constraint from ${_config.endpoint}', - ); - } - + /// Returns [LoggingConstraint] from cache or `null` if cache is missing. @override LoggingConstraint? get loggingConstraint => _loggingConstraint; @@ -164,8 +133,46 @@ class DefaultRemoteLoggingConstraintProvider } } +/// {@template aws_logging_cloudwatch.default_remote_logging_constraint_provider} +/// Default implementation of [RemoteLoggingConstraintProvider] to fetch +/// [LoggingConstraint] from an http endpoint periodically. +/// {@endtemplate} +final class DefaultRemoteLoggingConstraintProvider + extends BaseRemoteLoggingConstraintProvider { + /// {@macro aws_logging_cloudwatch.default_remote_logging_constraint_provider} + DefaultRemoteLoggingConstraintProvider({ + required super.config, + required this.credentialsProvider, + }) : super(credentialsProvider: credentialsProvider); + + /// The credentials provider to use for signing the request. + final AWSCredentialsProvider credentialsProvider; + + /// The signer to use for signing the request. + final AWSSigV4Signer _signer = const AWSSigV4Signer(); + + @override + Future createRequest() async { + final baseRequest = await super.createRequest(); + final scope = AWSCredentialScope( + region: _config.region, + service: AWSService.apiGatewayManagementApi, + ); + + final signedRequest = await _signer.sign( + baseRequest, + credentialScope: scope, + ); + + final newRequest = + AWSHttpRequest(method: signedRequest.method, uri: signedRequest.uri); + + return newRequest; + } +} + /// {@template aws_logging_cloudwatch.default_remote_configuration} -/// The configuration for [DefaultRemoteLoggingConstraintProvider] +/// The configuration for [BaseRemoteLoggingConstraintProvider] /// {@endtemplate} class DefaultRemoteConfiguration { /// {@macro aws_logging_cloudwatch.default_remote_configuration} From 6f426eed1d43e8f0aaf5264efb4b75225104ee29 Mon Sep 17 00:00:00 2001 From: Kha Truong <64438356+khatruong2009@users.noreply.github.com> Date: Mon, 11 Sep 2023 09:31:33 -0700 Subject: [PATCH 48/49] chore: used private global variable for local storage key --- .../lib/src/file_storage/file_storage.web.dart | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/packages/logging_cloudwatch/aws_logging_cloudwatch/lib/src/file_storage/file_storage.web.dart b/packages/logging_cloudwatch/aws_logging_cloudwatch/lib/src/file_storage/file_storage.web.dart index a0b5541bee6..37d135d4539 100644 --- a/packages/logging_cloudwatch/aws_logging_cloudwatch/lib/src/file_storage/file_storage.web.dart +++ b/packages/logging_cloudwatch/aws_logging_cloudwatch/lib/src/file_storage/file_storage.web.dart @@ -4,14 +4,17 @@ import 'dart:convert'; import 'dart:html'; +// Declare a constant global private variable for the key +const String _localStorageKey = 'aws.cloudwatch.logging_constraint'; + /// Save constraint locally to web storage Future saveConstraintLocally(Map constraint) async { - window.localStorage['logging_constraint'] = jsonEncode(constraint); + window.localStorage[_localStorageKey] = jsonEncode(constraint); } /// Load constraint from web storage Map? loadConstraint() { - final content = window.localStorage['logging_constraint']; + final content = window.localStorage[_localStorageKey]; if (content != null) { return jsonDecode(content) as Map; } From 5085ed1a8bca96b206657e6fa86d17263d90274c Mon Sep 17 00:00:00 2001 From: Kha Truong <64438356+khatruong2009@users.noreply.github.com> Date: Mon, 11 Sep 2023 16:13:03 -0700 Subject: [PATCH 49/49] chore: refacted fileStore dart implementation --- .../lib/src/cloudwatch_logger_plugin.dart | 2 +- .../lib/src/file_storage/file_storage.dart | 13 ++++++ .../lib/src/file_storage/file_storage.vm.dart | 41 +++++++++++-------- .../src/file_storage/file_storage.web.dart | 30 ++++++++------ .../lib/src/remote_constraint_provider.dart | 34 ++++++++++----- .../aws_logging_cloudwatch/pubspec.yaml | 1 - 6 files changed, 77 insertions(+), 44 deletions(-) create mode 100644 packages/logging_cloudwatch/aws_logging_cloudwatch/lib/src/file_storage/file_storage.dart diff --git a/packages/logging_cloudwatch/aws_logging_cloudwatch/lib/src/cloudwatch_logger_plugin.dart b/packages/logging_cloudwatch/aws_logging_cloudwatch/lib/src/cloudwatch_logger_plugin.dart index 7a28ea8aa0a..b3eecf74bbd 100644 --- a/packages/logging_cloudwatch/aws_logging_cloudwatch/lib/src/cloudwatch_logger_plugin.dart +++ b/packages/logging_cloudwatch/aws_logging_cloudwatch/lib/src/cloudwatch_logger_plugin.dart @@ -4,7 +4,7 @@ import 'dart:async'; import 'dart:math'; -import 'package:aws_common/aws_common.dart'; +import 'package:amplify_core/amplify_core.dart'; import 'package:aws_logging_cloudwatch/aws_logging_cloudwatch.dart'; import 'package:aws_logging_cloudwatch/src/sdk/cloud_watch_logs.dart'; import 'package:aws_logging_cloudwatch/src/stoppable_timer.dart'; diff --git a/packages/logging_cloudwatch/aws_logging_cloudwatch/lib/src/file_storage/file_storage.dart b/packages/logging_cloudwatch/aws_logging_cloudwatch/lib/src/file_storage/file_storage.dart new file mode 100644 index 00000000000..0070be9b5ab --- /dev/null +++ b/packages/logging_cloudwatch/aws_logging_cloudwatch/lib/src/file_storage/file_storage.dart @@ -0,0 +1,13 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +export 'file_storage.vm.dart' if (dart.library.html) 'file_storage.web.dart'; + +/// File storage interface for saving and loading constraint locally +abstract interface class FileStorage { + /// Save constraint locally to file + Future saveConstraintLocally(String filename, String data); + + /// Load constraint from file + Future loadConstraint(String filename); +} diff --git a/packages/logging_cloudwatch/aws_logging_cloudwatch/lib/src/file_storage/file_storage.vm.dart b/packages/logging_cloudwatch/aws_logging_cloudwatch/lib/src/file_storage/file_storage.vm.dart index 8d9e47437cd..05e51fd45ce 100644 --- a/packages/logging_cloudwatch/aws_logging_cloudwatch/lib/src/file_storage/file_storage.vm.dart +++ b/packages/logging_cloudwatch/aws_logging_cloudwatch/lib/src/file_storage/file_storage.vm.dart @@ -1,29 +1,34 @@ // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. // SPDX-License-Identifier: Apache-2.0 -import 'dart:convert'; import 'dart:io'; +import 'package:amplify_core/amplify_core.dart'; +import 'package:aws_logging_cloudwatch/src/file_storage/file_storage.dart'; import 'package:path/path.dart' as p; -import 'package:path_provider/path_provider.dart'; -/// Save constraint locally to file -Future saveConstraintLocally(Map constraint) async { - final directory = await getApplicationSupportDirectory(); - final path = directory.path; - final file = File(p.join(path, 'logging_constraint.json')); - await file.writeAsString(jsonEncode(constraint)); -} +/// File storage implementation for saving and loading constraint locally +final class FileStorageImpl implements FileStorage { + /// File storage implementation for saving and loading constraint locally + FileStorageImpl(this.pathProvider); + + /// Path provider to get the application support path + final AppPathProvider pathProvider; -/// Load constraint from file -Future?> loadConstraint() async { - final directory = await getApplicationSupportDirectory(); - final path = directory.path; - final file = File('$path/logging_constraint.json'); + @override + Future loadConstraint(String fileName) async { + final file = + File(p.join(await pathProvider.getApplicationSupportPath(), fileName)); + if (await file.exists()) { + return file.readAsString(); + } + return null; + } - if (file.existsSync()) { - final content = await file.readAsString(); - return jsonDecode(content) as Map; + @override + Future saveConstraintLocally(String fileName, String content) async { + final file = + File(p.join(await pathProvider.getApplicationSupportPath(), fileName)); + await file.writeAsString(content); } - return null; } diff --git a/packages/logging_cloudwatch/aws_logging_cloudwatch/lib/src/file_storage/file_storage.web.dart b/packages/logging_cloudwatch/aws_logging_cloudwatch/lib/src/file_storage/file_storage.web.dart index 37d135d4539..bbed8305b89 100644 --- a/packages/logging_cloudwatch/aws_logging_cloudwatch/lib/src/file_storage/file_storage.web.dart +++ b/packages/logging_cloudwatch/aws_logging_cloudwatch/lib/src/file_storage/file_storage.web.dart @@ -1,22 +1,26 @@ // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. // SPDX-License-Identifier: Apache-2.0 -import 'dart:convert'; import 'dart:html'; -// Declare a constant global private variable for the key -const String _localStorageKey = 'aws.cloudwatch.logging_constraint'; +import 'package:amplify_core/amplify_core.dart'; +import 'package:aws_logging_cloudwatch/src/file_storage/file_storage.dart'; -/// Save constraint locally to web storage -Future saveConstraintLocally(Map constraint) async { - window.localStorage[_localStorageKey] = jsonEncode(constraint); -} +/// File storage implementation for saving and loading constraint locally +final class FileStorageImpl implements FileStorage { + /// File storage implementation for saving and loading constraint locally + // ignore: avoid_unused_constructor_parameters + FileStorageImpl(AppPathProvider pathProvider); + + static const _prefix = 'aws.cloudwatch'; + + @override + Future loadConstraint(String fileName) async { + return window.localStorage['$_prefix.$fileName']; + } -/// Load constraint from web storage -Map? loadConstraint() { - final content = window.localStorage[_localStorageKey]; - if (content != null) { - return jsonDecode(content) as Map; + @override + Future saveConstraintLocally(String fileName, String content) async { + window.localStorage['$_prefix.$fileName'] = content; } - return null; } diff --git a/packages/logging_cloudwatch/aws_logging_cloudwatch/lib/src/remote_constraint_provider.dart b/packages/logging_cloudwatch/aws_logging_cloudwatch/lib/src/remote_constraint_provider.dart index 1e67721d5d5..8f7a0e4e4ea 100644 --- a/packages/logging_cloudwatch/aws_logging_cloudwatch/lib/src/remote_constraint_provider.dart +++ b/packages/logging_cloudwatch/aws_logging_cloudwatch/lib/src/remote_constraint_provider.dart @@ -10,9 +10,7 @@ import 'package:amplify_core/amplify_core.dart'; import 'package:aws_common/aws_common.dart'; import 'package:aws_logging_cloudwatch/aws_logging_cloudwatch.dart'; -import 'package:aws_logging_cloudwatch/src/file_storage/file_storage.vm.dart' - if (dart.library.html) 'package:aws_logging_cloudwatch/src/file_storage/file_storage.web.dart' - as storage; +import 'package:aws_logging_cloudwatch/src/file_storage/file_storage.dart'; import 'package:aws_signature_v4/aws_signature_v4.dart'; import 'package:meta/meta.dart'; @@ -37,11 +35,15 @@ base class BaseRemoteLoggingConstraintProvider BaseRemoteLoggingConstraintProvider({ required DefaultRemoteConfiguration config, required AWSCredentialsProvider credentialsProvider, - }) : _config = config, + FileStorage? fileStorage, + }) : _fileStorage = fileStorage, + _config = config, _credentialsProvider = credentialsProvider { init(); } + final FileStorage? _fileStorage; + final DefaultRemoteConfiguration _config; final AWSCredentialsProvider _credentialsProvider; @@ -64,9 +66,14 @@ base class BaseRemoteLoggingConstraintProvider /// starting the refresh timer afterwards. Future init() async { // Check local storage first. - final localConstraint = await storage.loadConstraint(); - if (localConstraint != null) { - _loggingConstraint = LoggingConstraint.fromJson(localConstraint); + if (_fileStorage != null) { + final localConstraint = + await _fileStorage!.loadConstraint('remoteloggingconstraints.json'); + if (localConstraint != null) { + _loggingConstraint = LoggingConstraint.fromJson( + jsonDecode(localConstraint) as Map, + ); + } } await _fetchAndCacheConstraintFromEndpoint(); await _refreshConstraintPeriodically(); @@ -98,7 +105,13 @@ base class BaseRemoteLoggingConstraintProvider jsonDecode(body) as Map, ); _loggingConstraint = fetchedConstraint; - await storage.saveConstraintLocally(fetchedConstraint.toJson()); + + if (_fileStorage != null) { + await _fileStorage!.saveConstraintLocally( + 'remoteloggingconstraints.json', + jsonEncode(fetchedConstraint.toJson()), + ); + } } } on Exception catch (exception) { throw Exception( @@ -126,9 +139,7 @@ base class BaseRemoteLoggingConstraintProvider _timer = Timer.periodic( _config.refreshInterval, - (Timer timer) async { - await _fetchAndCacheConstraintFromEndpoint(); - }, + (_) => _fetchAndCacheConstraintFromEndpoint(), ); } } @@ -143,6 +154,7 @@ final class DefaultRemoteLoggingConstraintProvider DefaultRemoteLoggingConstraintProvider({ required super.config, required this.credentialsProvider, + super.fileStorage, }) : super(credentialsProvider: credentialsProvider); /// The credentials provider to use for signing the request. diff --git a/packages/logging_cloudwatch/aws_logging_cloudwatch/pubspec.yaml b/packages/logging_cloudwatch/aws_logging_cloudwatch/pubspec.yaml index df00842c671..d14eda80e86 100644 --- a/packages/logging_cloudwatch/aws_logging_cloudwatch/pubspec.yaml +++ b/packages/logging_cloudwatch/aws_logging_cloudwatch/pubspec.yaml @@ -21,7 +21,6 @@ dependencies: json_annotation: ^4.8.1 meta: ^1.9.1 path: ^1.8.0 - path_provider: ^2.0.1 smithy: ^0.5.0+3 smithy_aws: ^0.5.0+3