diff --git a/packages/amplify_core/lib/amplify_core.dart b/packages/amplify_core/lib/amplify_core.dart index 4add5a25ab..f3dba4d61a 100644 --- a/packages/amplify_core/lib/amplify_core.dart +++ b/packages/amplify_core/lib/amplify_core.dart @@ -24,6 +24,7 @@ export 'src/config/analytics/analytics_config.dart'; export 'src/config/api/api_config.dart'; export 'src/config/auth/auth_config.dart'; export 'src/config/config_map.dart'; +export 'src/config/logging/logging_config.dart'; export 'src/config/notifications/notifications_config.dart'; export 'src/config/storage/storage_config.dart'; diff --git a/packages/amplify_core/lib/src/config/amplify_config.dart b/packages/amplify_core/lib/src/config/amplify_config.dart index 29ddb0dea1..eca3bdb007 100644 --- a/packages/amplify_core/lib/src/config/amplify_config.dart +++ b/packages/amplify_core/lib/src/config/amplify_config.dart @@ -18,6 +18,7 @@ class AmplifyConfig with AWSEquatable, AWSSerializable { this.api, this.analytics, this.auth, + this.logging, this.notifications, this.storage, }); @@ -39,6 +40,9 @@ class AmplifyConfig with AWSEquatable, AWSSerializable { /// The Auth category configuration, if available. final AuthConfig? auth; + /// The Logging configuration, if available. + final LoggingConfig? logging; + /// The Notifications category configuration, if available. final NotificationsConfig? notifications; @@ -52,6 +56,7 @@ class AmplifyConfig with AWSEquatable, AWSSerializable { api, analytics, auth, + logging, notifications, storage, ]; @@ -60,6 +65,7 @@ class AmplifyConfig with AWSEquatable, AWSSerializable { ApiConfig? api, AnalyticsConfig? analytics, AuthConfig? auth, + LoggingConfig? logging, NotificationsConfig? notifications, StorageConfig? storage, }) { @@ -69,6 +75,7 @@ class AmplifyConfig with AWSEquatable, AWSSerializable { api: api ?? this.api, analytics: analytics ?? this.analytics, auth: auth ?? this.auth, + logging: logging ?? this.logging, notifications: notifications ?? this.notifications, storage: storage ?? this.storage, ); diff --git a/packages/amplify_core/lib/src/config/amplify_config.g.dart b/packages/amplify_core/lib/src/config/amplify_config.g.dart index c94be213cc..27d692250f 100644 --- a/packages/amplify_core/lib/src/config/amplify_config.g.dart +++ b/packages/amplify_core/lib/src/config/amplify_config.g.dart @@ -21,6 +21,9 @@ AmplifyConfig _$AmplifyConfigFromJson(Map json) => auth: json['auth'] == null ? null : AuthConfig.fromJson(json['auth'] as Map), + logging: json['logging'] == null + ? null + : LoggingConfig.fromJson(json['logging'] as Map), notifications: json['notifications'] == null ? null : NotificationsConfig.fromJson( @@ -45,6 +48,7 @@ Map _$AmplifyConfigToJson(AmplifyConfig instance) { writeNotNull('api', instance.api?.toJson()); writeNotNull('analytics', instance.analytics?.toJson()); writeNotNull('auth', instance.auth?.toJson()); + writeNotNull('logging', instance.logging?.toJson()); writeNotNull('notifications', instance.notifications?.toJson()); writeNotNull('storage', instance.storage?.toJson()); return val; diff --git a/packages/amplify_core/lib/src/config/amplify_plugin_registry.dart b/packages/amplify_core/lib/src/config/amplify_plugin_registry.dart index 10e8c6127e..84553afd77 100644 --- a/packages/amplify_core/lib/src/config/amplify_plugin_registry.dart +++ b/packages/amplify_core/lib/src/config/amplify_plugin_registry.dart @@ -5,6 +5,7 @@ import 'package:amplify_core/src/config/amplify_plugin_config.dart'; import 'package:amplify_core/src/config/analytics/pinpoint_config.dart'; import 'package:amplify_core/src/config/api/aws_api_config.dart'; import 'package:amplify_core/src/config/auth/cognito_config.dart'; +import 'package:amplify_core/src/config/logging/cloudwatch_logging_config.dart'; import 'package:amplify_core/src/config/notifications/notifications_pinpoint_config.dart'; import 'package:amplify_core/src/config/storage/s3_config.dart'; @@ -25,6 +26,9 @@ const _defaultPlugins = [ // Storage S3PluginConfigFactory(), + + // Logging + CloudWatchPluginConfigFactory(), ]; /// {@template amplify_core.amplify_plugin_config_factory} diff --git a/packages/amplify_core/lib/src/config/logging/cloudwatch_logging_config.dart b/packages/amplify_core/lib/src/config/logging/cloudwatch_logging_config.dart new file mode 100644 index 0000000000..3012fc94a2 --- /dev/null +++ b/packages/amplify_core/lib/src/config/logging/cloudwatch_logging_config.dart @@ -0,0 +1,171 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +import 'package:amplify_core/amplify_core.dart'; +import 'package:meta/meta.dart'; + +part 'cloudwatch_logging_config.g.dart'; + +/// {@template amplify_core.cloudwatch_plugin_config_factory} +/// Configuration factory for [CloudWatchPluginConfig]. +/// {@endtemplate} +@internal +class CloudWatchPluginConfigFactory + extends AmplifyPluginConfigFactory { + /// {@macro amplify_core.cloudwatch_plugin_config_factory} + const CloudWatchPluginConfigFactory(); + + @override + CloudWatchPluginConfig build(Map json) { + return CloudWatchPluginConfig.fromJson(json); + } + + @override + String get name => CloudWatchPluginConfig.pluginKey; +} + +/// {@template amplify_core.cloudwatch_plugin_config} +/// The AWS CloudWatch plugin configuration. +/// {@endtemplate} +@zAmplifySerializable +class CloudWatchPluginConfig + with AWSEquatable, AWSSerializable + implements AmplifyPluginConfig { + /// {@macro amplify_core.cloudwatch_plugin_config} + const CloudWatchPluginConfig({ + this.enable = true, + required this.logGroupName, + required this.region, + this.localStoreMaxSizeInMB = 5, + this.flushIntervalInSeconds = 60, + this.defaultRemoteConfiguration, + this.loggingConstraints = const LoggingConstraints(), + }); + + factory CloudWatchPluginConfig.fromJson(Map json) => + _$CloudWatchPluginConfigFromJson(json); + + /// The plugin's configuration key. + static const pluginKey = 'cloudWatchLoggerPluginConfiguration'; + + final bool enable; + final String logGroupName; + final String region; + final int localStoreMaxSizeInMB; + final int flushIntervalInSeconds; + final DefaultRemoteConfiguration? defaultRemoteConfiguration; + final LoggingConstraints loggingConstraints; + + @override + String get name => pluginKey; + + @override + List get props => [ + enable, + logGroupName, + region, + localStoreMaxSizeInMB, + flushIntervalInSeconds, + defaultRemoteConfiguration, + loggingConstraints, + ]; + + CloudWatchPluginConfig copyWith({ + bool? enable, + String? logGroupName, + String? region, + int? localStoreMaxSizeInMB, + int? flushIntervalInSeconds, + DefaultRemoteConfiguration? defaultRemoteConfiguration, + LoggingConstraints? loggingConstraints, + }) { + return CloudWatchPluginConfig( + enable: enable ?? this.enable, + logGroupName: logGroupName ?? this.logGroupName, + region: region ?? this.region, + localStoreMaxSizeInMB: + localStoreMaxSizeInMB ?? this.localStoreMaxSizeInMB, + flushIntervalInSeconds: + flushIntervalInSeconds ?? this.flushIntervalInSeconds, + defaultRemoteConfiguration: + defaultRemoteConfiguration ?? this.defaultRemoteConfiguration, + loggingConstraints: loggingConstraints ?? this.loggingConstraints, + ); + } + + @override + Map toJson() => _$CloudWatchPluginConfigToJson(this); +} + +@zAmplifySerializable +class DefaultRemoteConfiguration + with + AWSEquatable, + AWSSerializable> { + const DefaultRemoteConfiguration({ + required this.endpoint, + this.refreshIntervalInSeconds = 1200, + }); + + factory DefaultRemoteConfiguration.fromJson(Map json) => + _$DefaultRemoteConfigurationFromJson(json); + + final String endpoint; + final int refreshIntervalInSeconds; + + @override + List get props => [endpoint, refreshIntervalInSeconds]; + + @override + Map toJson() => _$DefaultRemoteConfigurationToJson(this); +} + +@zAmplifySerializable +class LoggingConstraints + with + AWSEquatable, + AWSSerializable> { + const LoggingConstraints({ + this.defaultLogLevel = LogLevel.error, + this.categoryLogLevel = const {}, + this.userLogLevel = const {}, + }); + + factory LoggingConstraints.fromJson(Map json) => + _$LoggingConstraintsFromJson(json); + + final LogLevel defaultLogLevel; + final Map categoryLogLevel; + final Map userLogLevel; + + @override + List get props => [ + defaultLogLevel, + categoryLogLevel, + userLogLevel, + ]; + + @override + Map toJson() => _$LoggingConstraintsToJson(this); +} + +@zAmplifySerializable +class UserLogLevel + with AWSEquatable, AWSSerializable> { + const UserLogLevel({ + this.defaultLogLevel = LogLevel.error, + this.categoryLogLevel = const {}, + }); + + factory UserLogLevel.fromJson(Map json) => + _$UserLogLevelFromJson(json); + + final LogLevel defaultLogLevel; + final Map categoryLogLevel; + + @override + List get props => [defaultLogLevel, categoryLogLevel]; + + @override + Map toJson() => _$UserLogLevelToJson(this); +} diff --git a/packages/amplify_core/lib/src/config/logging/cloudwatch_logging_config.g.dart b/packages/amplify_core/lib/src/config/logging/cloudwatch_logging_config.g.dart new file mode 100644 index 0000000000..72ab29ce57 --- /dev/null +++ b/packages/amplify_core/lib/src/config/logging/cloudwatch_logging_config.g.dart @@ -0,0 +1,116 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +// ignore_for_file: deprecated_member_use_from_same_package + +part of 'cloudwatch_logging_config.dart'; + +// ************************************************************************** +// JsonSerializableGenerator +// ************************************************************************** + +CloudWatchPluginConfig _$CloudWatchPluginConfigFromJson( + Map json) => + CloudWatchPluginConfig( + enable: json['enable'] as bool? ?? true, + logGroupName: json['logGroupName'] as String, + region: json['region'] as String, + localStoreMaxSizeInMB: json['localStoreMaxSizeInMB'] as int? ?? 5, + flushIntervalInSeconds: json['flushIntervalInSeconds'] as int? ?? 60, + defaultRemoteConfiguration: json['defaultRemoteConfiguration'] == null + ? null + : DefaultRemoteConfiguration.fromJson( + json['defaultRemoteConfiguration'] as Map), + loggingConstraints: json['loggingConstraints'] == null + ? const LoggingConstraints() + : LoggingConstraints.fromJson( + json['loggingConstraints'] as Map), + ); + +Map _$CloudWatchPluginConfigToJson( + CloudWatchPluginConfig instance) { + final val = { + 'enable': instance.enable, + 'logGroupName': instance.logGroupName, + 'region': instance.region, + 'localStoreMaxSizeInMB': instance.localStoreMaxSizeInMB, + 'flushIntervalInSeconds': instance.flushIntervalInSeconds, + }; + + void writeNotNull(String key, dynamic value) { + if (value != null) { + val[key] = value; + } + } + + writeNotNull('defaultRemoteConfiguration', + instance.defaultRemoteConfiguration?.toJson()); + val['loggingConstraints'] = instance.loggingConstraints.toJson(); + return val; +} + +DefaultRemoteConfiguration _$DefaultRemoteConfigurationFromJson( + Map json) => + DefaultRemoteConfiguration( + endpoint: json['endpoint'] as String, + refreshIntervalInSeconds: + json['refreshIntervalInSeconds'] as int? ?? 1200, + ); + +Map _$DefaultRemoteConfigurationToJson( + DefaultRemoteConfiguration instance) => + { + 'endpoint': instance.endpoint, + 'refreshIntervalInSeconds': instance.refreshIntervalInSeconds, + }; + +LoggingConstraints _$LoggingConstraintsFromJson(Map json) => + LoggingConstraints( + defaultLogLevel: + $enumDecodeNullable(_$LogLevelEnumMap, json['defaultLogLevel']) ?? + LogLevel.error, + categoryLogLevel: + (json['categoryLogLevel'] as Map?)?.map( + (k, e) => MapEntry(k, $enumDecode(_$LogLevelEnumMap, e)), + ) ?? + const {}, + userLogLevel: (json['userLogLevel'] as Map?)?.map( + (k, e) => + MapEntry(k, UserLogLevel.fromJson(e as Map)), + ) ?? + const {}, + ); + +Map _$LoggingConstraintsToJson(LoggingConstraints instance) => + { + 'defaultLogLevel': _$LogLevelEnumMap[instance.defaultLogLevel]!, + 'categoryLogLevel': instance.categoryLogLevel + .map((k, e) => MapEntry(k, _$LogLevelEnumMap[e]!)), + 'userLogLevel': + instance.userLogLevel.map((k, e) => MapEntry(k, e.toJson())), + }; + +const _$LogLevelEnumMap = { + LogLevel.verbose: 'VERBOSE', + LogLevel.debug: 'DEBUG', + LogLevel.info: 'INFO', + LogLevel.warn: 'WARN', + LogLevel.error: 'ERROR', + LogLevel.none: 'NONE', +}; + +UserLogLevel _$UserLogLevelFromJson(Map json) => UserLogLevel( + defaultLogLevel: + $enumDecodeNullable(_$LogLevelEnumMap, json['defaultLogLevel']) ?? + LogLevel.error, + categoryLogLevel: + (json['categoryLogLevel'] as Map?)?.map( + (k, e) => MapEntry(k, e as String), + ) ?? + const {}, + ); + +Map _$UserLogLevelToJson(UserLogLevel instance) => + { + 'defaultLogLevel': _$LogLevelEnumMap[instance.defaultLogLevel]!, + 'categoryLogLevel': instance.categoryLogLevel, + }; diff --git a/packages/amplify_core/lib/src/config/logging/logging_config.dart b/packages/amplify_core/lib/src/config/logging/logging_config.dart new file mode 100644 index 0000000000..eb5e296135 --- /dev/null +++ b/packages/amplify_core/lib/src/config/logging/logging_config.dart @@ -0,0 +1,33 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +import 'package:amplify_core/amplify_core.dart'; + +export 'cloudwatch_logging_config.dart' hide CloudWatchPluginConfigFactory; + +part 'logging_config.g.dart'; + +/// {@template amplify_core.logging_config} +/// The Logging configuration. +/// {@endtemplate} +@zAmplifySerializable +class LoggingConfig extends AmplifyPluginConfigMap { + /// {@macro amplify_core.logging_config} + const LoggingConfig({ + required Map plugins, + }) : super(plugins); + + factory LoggingConfig.fromJson(Map json) => + _$LoggingConfigFromJson(json); + + /// The AWS CloudWatch plugin configuration, if available. + @override + CloudWatchPluginConfig? get awsPlugin => + plugins[CloudWatchPluginConfig.pluginKey] as CloudWatchPluginConfig?; + + @override + LoggingConfig copy() => LoggingConfig(plugins: Map.of(plugins)); + + @override + Map toJson() => _$LoggingConfigToJson(this); +} diff --git a/packages/amplify_core/lib/src/config/logging/logging_config.g.dart b/packages/amplify_core/lib/src/config/logging/logging_config.g.dart new file mode 100644 index 0000000000..2c88483fa8 --- /dev/null +++ b/packages/amplify_core/lib/src/config/logging/logging_config.g.dart @@ -0,0 +1,19 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +// ignore_for_file: deprecated_member_use_from_same_package + +part of 'logging_config.dart'; + +// ************************************************************************** +// JsonSerializableGenerator +// ************************************************************************** + +LoggingConfig _$LoggingConfigFromJson(Map json) => + LoggingConfig( + plugins: AmplifyPluginRegistry.pluginConfigsFromJson(json['plugins']), + ); + +Map _$LoggingConfigToJson(LoggingConfig instance) => + { + 'plugins': instance.plugins.map((k, e) => MapEntry(k, e.toJson())), + }; diff --git a/packages/aws_common/lib/src/logging/log_level.dart b/packages/aws_common/lib/src/logging/log_level.dart index 6f12173aa9..90d1c02469 100644 --- a/packages/aws_common/lib/src/logging/log_level.dart +++ b/packages/aws_common/lib/src/logging/log_level.dart @@ -3,30 +3,38 @@ // ignore_for_file: public_member_api_docs +import 'package:json_annotation/json_annotation.dart'; + /// The different levels of logging. enum LogLevel implements Comparable { /// Logs for showing behavior of particular components/flows. /// /// **Note**: May contain information inappropriate for emission into /// production environments. + @JsonValue('VERBOSE') verbose, /// Logs for understanding system behavior. /// /// **Note**: May contain information inappropriate for emission into /// production environments. + @JsonValue('DEBUG') debug, /// Logs providing terse info about general operation and flow of software. + @JsonValue('INFO') info, /// Logs indicating potential issues. + @JsonValue('WARN') warn, /// Logs when system is not operating as expected. + @JsonValue('ERROR') error, /// Prevents any logs from being emitted. + @JsonValue('NONE') none; @override 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 9e9fd28c3f..fd2bd1fee4 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 @@ -4,7 +4,8 @@ import 'dart:async'; import 'package:aws_common/aws_common.dart'; -import 'package:aws_logging_cloudwatch/aws_logging_cloudwatch.dart'; +// ignore: implementation_imports +import 'package:aws_logging_cloudwatch/src/queued_item_store/queued_item_store.dart'; import 'package:meta/meta.dart'; /// {@template amplify_logging_cloudwatch.dart_queued_item_store} 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 7acc8ee13c..c4cb9ef090 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 @@ -5,7 +5,8 @@ import 'dart:async'; import 'package:amplify_logging_cloudwatch/src/queued_item_store/drift/drift_queued_item_store.dart'; import 'package:aws_common/aws_common.dart'; -import 'package:aws_logging_cloudwatch/aws_logging_cloudwatch.dart'; +// ignore: implementation_imports +import 'package:aws_logging_cloudwatch/src/queued_item_store/queued_item_store.dart'; import 'package:meta/meta.dart'; import 'package:path_provider/path_provider.dart'; 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 c20db8c60b..656556950b 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 @@ -1,9 +1,12 @@ // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. // SPDX-License-Identifier: Apache-2.0 +// ignore_for_file: implementation_imports + import 'package:amplify_logging_cloudwatch/src/queued_item_store/index_db/indexed_db_adapter.dart'; import 'package:aws_common/aws_common.dart'; -import 'package:aws_logging_cloudwatch/aws_logging_cloudwatch.dart'; +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:meta/meta.dart'; /// {@macro amplify_logging_cloudwatch.dart_queued_item_store} 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 d29f32777c..653d36350c 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 @@ -4,7 +4,8 @@ import 'dart:async'; import 'package:amplify_db_common_dart/amplify_db_common_dart.dart'; -import 'package:aws_logging_cloudwatch/aws_logging_cloudwatch.dart'; +// ignore: implementation_imports +import 'package:aws_logging_cloudwatch/src/queued_item_store/queued_item_store.dart'; import 'package:drift/drift.dart'; part 'drift_queued_item_store.g.dart'; 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 c4e4c13763..050e1ef1eb 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 @@ -1,13 +1,14 @@ // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. // SPDX-License-Identifier: Apache-2.0 +// ignore_for_file: implementation_imports + import 'dart:async'; import 'dart:js_util'; import 'package:amplify_core/amplify_core.dart'; -// ignore: implementation_imports import 'package:aws_common/src/js/indexed_db.dart'; -import 'package:aws_logging_cloudwatch/aws_logging_cloudwatch.dart'; +import 'package:aws_logging_cloudwatch/src/queued_item_store/queued_item_store.dart'; import 'package:collection/collection.dart'; // TODO(kylechen): Consider merging/refactoring with existing 'amplify_secure_storage_web - _IndexedDBStorage' class diff --git a/packages/logging_cloudwatch/aws_logging_cloudwatch/lib/aws_logging_cloudwatch.dart b/packages/logging_cloudwatch/aws_logging_cloudwatch/lib/aws_logging_cloudwatch.dart index 5af0cf6bcf..0f4f3d075b 100644 --- a/packages/logging_cloudwatch/aws_logging_cloudwatch/lib/aws_logging_cloudwatch.dart +++ b/packages/logging_cloudwatch/aws_logging_cloudwatch/lib/aws_logging_cloudwatch.dart @@ -6,7 +6,4 @@ library aws_logging_cloudwatch; export 'src/cloudwatch_logger_plugin.dart'; export 'src/log_stream_provider.dart'; -export 'src/plugin_config.dart'; -export 'src/queued_item_store/in_memory_queued_item_store.dart'; -export 'src/queued_item_store/queued_item_store.dart'; export 'src/remote_constraint_provider.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 b3eecf74bb..835a2e2328 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 @@ -6,6 +6,8 @@ import 'dart:math'; import 'package:amplify_core/amplify_core.dart'; import 'package:aws_logging_cloudwatch/aws_logging_cloudwatch.dart'; +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:aws_logging_cloudwatch/src/sdk/cloud_watch_logs.dart'; import 'package:aws_logging_cloudwatch/src/stoppable_timer.dart'; import 'package:fixnum/fixnum.dart'; @@ -47,7 +49,7 @@ class CloudWatchLoggerPlugin extends AWSLoggerPlugin /// {@macro aws_logging_cloudwatch.cloudwatch_logger_plugin} CloudWatchLoggerPlugin({ required AWSCredentialsProvider credentialsProvider, - required CloudWatchLoggerPluginConfiguration pluginConfig, + required CloudWatchPluginConfig pluginConfig, RemoteLoggingConstraintProvider? remoteLoggingConstraintProvider, CloudWatchLogStreamProvider? logStreamProvider, // TODO(nikahsn): remove after moving queued item store implementation from @@ -60,6 +62,7 @@ class CloudWatchLoggerPlugin extends AWSLoggerPlugin ? DefaultRemoteLoggingConstraintProvider( config: pluginConfig.defaultRemoteConfiguration!, credentialsProvider: credentialsProvider, + region: pluginConfig.region, ) : null), _client = CloudWatchLogsClient( @@ -76,9 +79,9 @@ class CloudWatchLoggerPlugin extends AWSLoggerPlugin region: pluginConfig.region, credentialsProvider: credentialsProvider, ) { - _timer = pluginConfig.flushInterval > Duration.zero + _timer = pluginConfig.flushIntervalInSeconds > 0 ? StoppableTimer( - duration: pluginConfig.flushInterval, + duration: Duration(seconds: pluginConfig.flushIntervalInSeconds), callback: _startSyncingIfNotInProgress, onError: _onTimerError, ) @@ -93,7 +96,7 @@ class CloudWatchLoggerPlugin extends AWSLoggerPlugin @visibleForTesting CloudWatchLoggerPlugin.testPlugin({ required CloudWatchLogsClient client, - required CloudWatchLoggerPluginConfiguration pluginConfig, + required CloudWatchPluginConfig pluginConfig, required CloudWatchLogStreamProvider logStreamProvider, required QueuedItemStore logStore, RemoteLoggingConstraintProvider? remoteLoggingConstraintProvider, @@ -104,7 +107,7 @@ class CloudWatchLoggerPlugin extends AWSLoggerPlugin _logStreamProvider = logStreamProvider, _client = client; - final CloudWatchLoggerPluginConfiguration _pluginConfig; + final CloudWatchPluginConfig _pluginConfig; final CloudWatchLogsClient _client; final CloudWatchLogStreamProvider _logStreamProvider; final QueuedItemStore _logStore; @@ -216,9 +219,9 @@ class CloudWatchLoggerPlugin extends AWSLoggerPlugin logger.error('Failed to sync logs to CloudWatch.', e); } - LoggingConstraint _getLoggingConstraint() { + LoggingConstraints _getLoggingConstraint() { final result = _remoteLoggingConstraintProvider?.loggingConstraint; - return result ?? _pluginConfig.localLoggingConstraint; + return result ?? _pluginConfig.loggingConstraints; } Future _sendToCloudWatch( 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 deleted file mode 100644 index 3367eb505c..0000000000 --- a/packages/logging_cloudwatch/aws_logging_cloudwatch/lib/src/plugin_config.dart +++ /dev/null @@ -1,107 +0,0 @@ -// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. -// SPDX-License-Identifier: Apache-2.0 - -import 'package:amplify_core/amplify_core.dart'; -import 'package:aws_logging_cloudwatch/aws_logging_cloudwatch.dart'; - -part 'plugin_config.g.dart'; - -/// {@template aws_logging_cloudwatch.cloudwatch_logger_plugin_configuration} -/// The configuration for `CloudWatchLoggerPlugin`. -/// {@endtemplate} -class CloudWatchLoggerPluginConfiguration with AWSDebuggable { - /// {@macro aws_logging_cloudwatch.cloudwatch_logger_plugin_configuration} - const CloudWatchLoggerPluginConfiguration({ - required this.logGroupName, - required this.region, - required this.localLoggingConstraint, - this.enable = true, - this.localStoreMaxSizeInMB = 5, - this.flushInterval = const Duration(seconds: 60), - this.defaultRemoteConfiguration, - }); - - /// Whether the plugin is enabled. - final bool enable; - - /// The log group name to use for sending logs to CloudWatch. - final String logGroupName; - - /// The region to use for sending logs to CloudWatch. - final String region; - - /// The max size of the local store in MB to be used for storing logs locally. - final int localStoreMaxSizeInMB; - - /// The duration for sending locally stored logs to CloudWatch. - final Duration flushInterval; - - /// {@macro aws_logging_cloudwatch.logging_constraint} - final LoggingConstraint localLoggingConstraint; - - /// {@macro aws_logging_cloudwatch.default_remote_configuration} - final DefaultRemoteConfiguration? defaultRemoteConfiguration; - - @override - String get runtimeTypeName => 'CloudWatchLoggerPluginConfiguration'; -} - -/// {@template aws_logging_cloudwatch.logging_constraint} -/// The logging constraint for sending logs to CloudWatch. -/// {@endtemplate} -@zAmplifySerializable -class LoggingConstraint with AWSDebuggable, AWSSerializable { - /// {@macro aws_logging_cloudwatch.logging_constraint} - const LoggingConstraint({ - this.defaultLogLevel = LogLevel.error, - this.categoryLogLevel, - this.userLogLevel, - }); - - /// Converts a [Map] to an [LoggingConstraint] instance. - factory LoggingConstraint.fromJson(Map json) => - _$LoggingConstraintFromJson(json); - - /// Converts an [LoggingConstraint] instance to a [Map]. - @override - Map toJson() => _$LoggingConstraintToJson(this); - - /// 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'; -} - -/// The logging constraint for user specific log level. -@zAmplifySerializable -class UserLogLevel with AWSDebuggable, AWSSerializable { - /// 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]. - @override - Map toJson() => _$UserLogLevelToJson(this); - - /// The default [LogLevel] for sending logs to CloudWatch. - final LogLevel? defaultLogLevel; - - /// The [LogLevel] for different categories. - final Map? categoryLogLevel; - - @override - String get runtimeTypeName => 'UserLogLevel'; -} 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 deleted file mode 100644 index 64733e29d2..0000000000 --- a/packages/logging_cloudwatch/aws_logging_cloudwatch/lib/src/plugin_config.g.dart +++ /dev/null @@ -1,76 +0,0 @@ -// 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, - categoryLogLevel: - (json['categoryLogLevel'] as Map?)?.map( - (k, e) => MapEntry(k, $enumDecode(_$LogLevelEnumMap, e)), - ), - userLogLevel: (json['userLogLevel'] as Map?)?.map( - (k, e) => MapEntry(k, UserLogLevel.fromJson(e as Map)), - ), - ); - -Map _$LoggingConstraintToJson(LoggingConstraint instance) { - final val = { - 'defaultLogLevel': _$LogLevelEnumMap[instance.defaultLogLevel]!, - }; - - void writeNotNull(String key, dynamic value) { - if (value != null) { - val[key] = value; - } - } - - writeNotNull( - 'categoryLogLevel', - instance.categoryLogLevel - ?.map((k, e) => MapEntry(k, _$LogLevelEnumMap[e]!))); - writeNotNull('userLogLevel', - instance.userLogLevel?.map((k, e) => MapEntry(k, e.toJson()))); - return val; -} - -const _$LogLevelEnumMap = { - LogLevel.verbose: 'verbose', - LogLevel.debug: 'debug', - LogLevel.info: 'info', - LogLevel.warn: 'warn', - 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) { - final val = {}; - - void writeNotNull(String key, dynamic value) { - if (value != null) { - val[key] = value; - } - } - - writeNotNull('defaultLogLevel', _$LogLevelEnumMap[instance.defaultLogLevel]); - writeNotNull( - 'categoryLogLevel', - instance.categoryLogLevel - ?.map((k, e) => MapEntry(k, _$LogLevelEnumMap[e]!))); - return val; -} 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 ff6e0b31a1..9d35b09820 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 @@ -5,8 +5,6 @@ import 'dart:async'; import 'dart:convert'; 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.dart'; import 'package:aws_signature_v4/aws_signature_v4.dart'; import 'package:meta/meta.dart'; @@ -14,16 +12,16 @@ import 'package:meta/meta.dart'; /// {@template aws_logging_cloudwatch.remote_logging_constraint_provider} /// An Interface to provide custom implementation for /// [RemoteLoggingConstraintProvider] -/// It gets the [LoggingConstraint] from a remote location and cache it. +/// It gets the [LoggingConstraints] from a remote location and cache it. /// {@endtemplate} abstract class RemoteLoggingConstraintProvider { /// Returns logging constraint from cache or `null` if cache is missing. - LoggingConstraint? get loggingConstraint; + LoggingConstraints? get loggingConstraint; } /// {@template aws_logging_cloudwatch.base_remote_constraints_provider} /// Base class for [RemoteLoggingConstraintProvider] to provide -/// [LoggingConstraint] from a remote location and cache it. +/// [LoggingConstraints] from a remote location and cache it. /// {@endtemplate} base class BaseRemoteLoggingConstraintProvider with AWSDebuggable, AWSLoggerMixin @@ -55,7 +53,7 @@ base class BaseRemoteLoggingConstraintProvider final DefaultRemoteConfiguration _config; - LoggingConstraint? _loggingConstraint; + LoggingConstraints? _loggingConstraint; final AWSHttpClient _awsHttpClient; @@ -108,7 +106,7 @@ base class BaseRemoteLoggingConstraintProvider .error('Failed to fetch constraints', (response.statusCode, body)); return; } - final fetchedConstraint = LoggingConstraint.fromJson( + final fetchedConstraint = LoggingConstraints.fromJson( jsonDecode(body) as Map, ); _loggingConstraint = fetchedConstraint; @@ -126,15 +124,15 @@ base class BaseRemoteLoggingConstraintProvider } } - /// Returns [LoggingConstraint] from the cache or `null` if the cache is missing + /// Returns [LoggingConstraints] from the cache or `null` if the cache is missing /// or if the constraints could not be retrieved from the remote server. @override - LoggingConstraint? get loggingConstraint => _loggingConstraint; + LoggingConstraints? get loggingConstraint => _loggingConstraint; Future _loadConstraintFromLocalStorage() async { final localConstraint = await _fileStorage?.load(_cacheFileName); if (localConstraint != null) { - _loggingConstraint = LoggingConstraint.fromJson( + _loggingConstraint = LoggingConstraints.fromJson( jsonDecode(localConstraint) as Map, ); } @@ -144,7 +142,7 @@ base class BaseRemoteLoggingConstraintProvider Future _refreshConstraintPeriodically() async { await _loadConstraintFromLocalStorage(); _timer = Timer.periodic( - _config.refreshInterval, + Duration(seconds: _config.refreshIntervalInSeconds), (_) => _fetchAndCacheConstraintFromEndpoint(), ); await _fetchAndCacheConstraintFromEndpoint(); @@ -159,30 +157,34 @@ base class BaseRemoteLoggingConstraintProvider /// {@template aws_logging_cloudwatch.default_remote_logging_constraint_provider} /// Default implementation of [RemoteLoggingConstraintProvider] to fetch -/// [LoggingConstraint] from an http endpoint periodically. +/// [LoggingConstraints] 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, + required String region, + required AWSCredentialsProvider credentialsProvider, super.fileStorage, - }); + }) : _region = region, + _credentialsProvider = credentialsProvider; /// The credentials provider to use for signing the request. - final AWSCredentialsProvider credentialsProvider; + final AWSCredentialsProvider _credentialsProvider; + + final String _region; /// The signer to use for signing the request. late final AWSSigV4Signer _signer = AWSSigV4Signer( - credentialsProvider: credentialsProvider, + credentialsProvider: _credentialsProvider, ); @override Future createRequest() async { final baseRequest = await super.createRequest(); final scope = AWSCredentialScope( - region: _config.region, + region: _region, service: AWSService.apiGatewayManagementApi, ); @@ -194,24 +196,3 @@ final class DefaultRemoteLoggingConstraintProvider return signedRequest; } } - -/// {@template aws_logging_cloudwatch.default_remote_configuration} -/// The configuration for [BaseRemoteLoggingConstraintProvider] -/// {@endtemplate} -class DefaultRemoteConfiguration { - /// {@macro aws_logging_cloudwatch.default_remote_configuration} - const DefaultRemoteConfiguration({ - required this.endpoint, - this.refreshInterval = const Duration(seconds: 1200), - required this.region, - }); - - /// The endpoint to fetch the `loggingConstraint`. - final String endpoint; - - /// The referesh interval to fetch the `loggingConstraint`. - final Duration refreshInterval; - - /// The region of the endpoint. - final String region; -} 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 4e4f57f39e..346831e42e 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 @@ -3,8 +3,9 @@ import 'dart:async'; -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/queued_item_store/queued_item_store.dart'; import 'package:aws_logging_cloudwatch/src/sdk/cloud_watch_logs.dart'; import 'package:mocktail/mocktail.dart'; import 'package:test/test.dart'; @@ -18,11 +19,11 @@ void main() { late CloudWatchLoggerPlugin plugin; late MockSmithyOperation mockPutLogEventsOperation; - const loggingConstraint = LoggingConstraint(); - const pluginConfig = CloudWatchLoggerPluginConfiguration( + const loggingConstraint = LoggingConstraints(); + const pluginConfig = CloudWatchPluginConfig( logGroupName: 'logGroupName', region: 'region', - localLoggingConstraint: loggingConstraint, + loggingConstraints: loggingConstraint, enable: false, ); final errorLog = LogEntry( diff --git a/packages/logging_cloudwatch/aws_logging_cloudwatch/test/mocks.dart b/packages/logging_cloudwatch/aws_logging_cloudwatch/test/mocks.dart index 9a88dca02b..49238ea567 100644 --- a/packages/logging_cloudwatch/aws_logging_cloudwatch/test/mocks.dart +++ b/packages/logging_cloudwatch/aws_logging_cloudwatch/test/mocks.dart @@ -1,4 +1,6 @@ -import 'package:aws_logging_cloudwatch/aws_logging_cloudwatch.dart'; +import 'package:aws_logging_cloudwatch/aws_logging_cloudwatch.dart' + show CloudWatchLogStreamProvider, RemoteLoggingConstraintProvider; +import 'package:aws_logging_cloudwatch/src/queued_item_store/queued_item_store.dart'; import 'package:aws_logging_cloudwatch/src/sdk/cloud_watch_logs.dart'; import 'package:mocktail/mocktail.dart'; import 'package:smithy/smithy.dart'; diff --git a/packages/logging_cloudwatch/aws_logging_cloudwatch/test/remote_constraint_provider_test.dart b/packages/logging_cloudwatch/aws_logging_cloudwatch/test/remote_constraint_provider_test.dart index cd1e4ba6ce..4cee7c64c0 100644 --- a/packages/logging_cloudwatch/aws_logging_cloudwatch/test/remote_constraint_provider_test.dart +++ b/packages/logging_cloudwatch/aws_logging_cloudwatch/test/remote_constraint_provider_test.dart @@ -12,17 +12,17 @@ import 'package:test/test.dart'; const sampleJson = ''' { - "defaultLogLevel": "error", + "defaultLogLevel": "ERROR", "categoryLogLevel": { - "API": "debug", - "AUTH": "debug" + "API": "DEBUG", + "AUTH": "DEBUG" }, "userLogLevel": { "cognito-sub-xyz-123": { - "defaultLogLevel": "verbose", + "defaultLogLevel": "VERBOSE", "categoryLogLevel": { - "API": "verbose", - "AUTH": "verbose" + "API": "VERBOSE", + "AUTH": "VERBOSE" } } } @@ -59,7 +59,7 @@ void main() { late MockAWSHttpClient mockAWSHttpClient; test('LoggingConstraint', () { final sampleJsonMap = jsonDecode(sampleJson) as Map; - final loggingConstraint = LoggingConstraint.fromJson(sampleJsonMap); + final loggingConstraint = LoggingConstraints.fromJson(sampleJsonMap); expect( loggingConstraint.toJson(), sampleJsonMap, @@ -86,9 +86,8 @@ void main() { }); provider = BaseRemoteLoggingConstraintProvider.forTesting( config: const DefaultRemoteConfiguration( - refreshInterval: Duration(seconds: 1200), + refreshIntervalInSeconds: 1200, endpoint: 'https://example.com', - region: 'us-west-2', ), fileStorage: mockFileStorage, awsHttpClient: mockAWSHttpClient, @@ -114,9 +113,8 @@ void main() { }); provider = BaseRemoteLoggingConstraintProvider.forTesting( config: const DefaultRemoteConfiguration( - refreshInterval: Duration(seconds: 10), + refreshIntervalInSeconds: 10, endpoint: 'https://example.com', - region: 'us-west-2', ), fileStorage: mockFileStorage, awsHttpClient: mockAWSHttpClient, @@ -134,14 +132,14 @@ void main() { () async { const updatedJson = ''' { - "defaultLogLevel": "debug", + "defaultLogLevel": "DEBUG", "categoryLogLevel": { - "API": "debug", - "AUTH": "error" + "API": "DEBUG", + "AUTH": "ERROR" }, "userLogLevel": { "cognito-sub-xyz-123": { - "defaultLogLevel": "verbose", + "defaultLogLevel": "VERBOSE", "categoryLogLevel": { "API": "error", "AUTH": "debug" @@ -178,9 +176,8 @@ void main() { }); provider = BaseRemoteLoggingConstraintProvider.forTesting( config: const DefaultRemoteConfiguration( - refreshInterval: Duration(seconds: 1), + refreshIntervalInSeconds: 1, endpoint: 'https://example.com', - region: 'us-west-2', ), fileStorage: mockFileStorage, awsHttpClient: mockAWSHttpClient, @@ -211,9 +208,8 @@ void main() { }); provider = BaseRemoteLoggingConstraintProvider.forTesting( config: const DefaultRemoteConfiguration( - refreshInterval: Duration(seconds: 10), + refreshIntervalInSeconds: 10, endpoint: 'https://example.com', - region: 'us-west-2', ), fileStorage: mockFileStorage, awsHttpClient: mockAWSHttpClient,