Skip to content

Commit

Permalink
feat: implement _isLoggable method (#3894)
Browse files Browse the repository at this point in the history
* feat: implement _isLoggable and corrected categoryLogLevel in UserLogLevel class

* chore: added _userId private variable instead of using method variable

* chore: add aft workflows

* chore: added helper method make sure category keys match

* chore: removed unnecessary new listener

* Update packages/logging_cloudwatch/aws_logging_cloudwatch/lib/src/cloudwatch_logger_plugin.dart

Co-authored-by: NikaHsn <[email protected]>

* chore: removed white spaces

* chore: added tests, tests methods, and fixed a typ

* Update packages/logging_cloudwatch/aws_logging_cloudwatch/lib/src/cloudwatch_logger_plugin.dart

Co-authored-by: NikaHsn <[email protected]>

* chore: removed testing methods and adjusted tests

* chore: WIP - changed tests for handleLogEntry

* chore: added future<void>.delay(0) to tests

* chore: updated remote_constraint_provider_test

* updated the tests

* chore: flattened if statement

---------

Co-authored-by: NikaHsn <[email protected]>
Co-authored-by: Nika Hassani <[email protected]>
  • Loading branch information
3 people committed Nov 27, 2023
1 parent 68152aa commit b1c938b
Show file tree
Hide file tree
Showing 6 changed files with 237 additions and 19 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -161,7 +161,7 @@ class UserLogLevel
_$UserLogLevelFromJson(json);

final LogLevel defaultLogLevel;
final Map<String, String> categoryLogLevel;
final Map<String, LogLevel> categoryLogLevel;

@override
List<Object?> get props => [defaultLogLevel, categoryLogLevel];
Expand Down

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
Expand Up @@ -98,8 +98,12 @@ class CloudWatchLoggerPlugin extends AWSLoggerPlugin
if (event.type == AuthHubEventType.signedOut ||
event.type == AuthHubEventType.userDeleted ||
event.type == AuthHubEventType.sessionExpired) {
_userId = null;
await _clearLogs();
}
if (event.type == AuthHubEventType.signedIn) {
_userId = event.payload?.userId;
}
});
}

Expand All @@ -122,11 +126,15 @@ class CloudWatchLoggerPlugin extends AWSLoggerPlugin
if (event.type == AuthHubEventType.signedOut ||
event.type == AuthHubEventType.userDeleted ||
event.type == AuthHubEventType.sessionExpired) {
_userId = null;
await _clearLogs();
}
if (event.type == AuthHubEventType.signedIn) {
_userId = event.payload?.userId;
}
});
}

String? _userId;
final CloudWatchPluginConfig _pluginConfig;
final CloudWatchLogsClient _client;
final CloudWatchLogStreamProvider _logStreamProvider;
Expand Down Expand Up @@ -301,11 +309,35 @@ class CloudWatchLoggerPlugin extends AWSLoggerPlugin

/// Whether a [logEntry] should be logged by this plugin.
bool _isLoggable(LogEntry logEntry) {
if (!_enabled) {
return false;
}
if (!_enabled) return false;

final loggingConstraint = _getLoggingConstraint();
return logEntry.level >= loggingConstraint.defaultLogLevel;
final hasUserLogLevel = loggingConstraint.userLogLevel.containsKey(_userId);
LogLevel? logLevel;

if (hasUserLogLevel) {
final userLogLevel = loggingConstraint.userLogLevel[_userId]!;
logLevel =
_getCategoryLogLevel(userLogLevel.categoryLogLevel, logEntry) ??
userLogLevel.defaultLogLevel;
} else {
logLevel =
_getCategoryLogLevel(loggingConstraint.categoryLogLevel, logEntry);
}

return logEntry.level >= (logLevel ?? loggingConstraint.defaultLogLevel);
}

LogLevel? _getCategoryLogLevel(
Map<String, LogLevel> categoryLogLevel,
LogEntry logEntry,
) {
for (final entry in categoryLogLevel.entries) {
if (logEntry.loggerName.toLowerCase().contains(entry.key.toLowerCase())) {
return entry.value;
}
}
return null;
}

@override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,29 @@ void main() {
late CloudWatchLoggerPlugin plugin;
late MockSmithyOperation<PutLogEventsResponse> mockPutLogEventsOperation;

const loggingConstraint = LoggingConstraints();
const loggingConstraint = LoggingConstraints(
defaultLogLevel: LogLevel.error,
categoryLogLevel: {
'Auth': LogLevel.warn,
'DataStore': LogLevel.debug,
},
userLogLevel: {
'mockUserId': UserLogLevel(
defaultLogLevel: LogLevel.warn,
categoryLogLevel: {
'Auth': LogLevel.debug,
'DataStore': LogLevel.info,
},
),
'userId': UserLogLevel(
defaultLogLevel: LogLevel.error,
categoryLogLevel: {
'Auth': LogLevel.info,
'DataStore': LogLevel.warn,
},
),
},
);
const pluginConfig = CloudWatchPluginConfig(
logGroupName: 'logGroupName',
region: 'region',
Expand All @@ -38,6 +60,48 @@ void main() {
loggerName: 'loggerName',
);

final infoLog = LogEntry(
level: LogLevel.info,
message: 'info message',
loggerName: 'loggerName',
);

final datastoreDebugLog = LogEntry(
level: LogLevel.debug,
message: 'debug message',
loggerName: 'DataStore',
);

final datastoreInfoLog = LogEntry(
level: LogLevel.info,
message: 'debug message',
loggerName: 'DataStore',
);

final authWarnLog = LogEntry(
level: LogLevel.warn,
message: 'debug message',
loggerName: 'Auth',
);

final authDebugLog = LogEntry(
level: LogLevel.debug,
message: 'debug message',
loggerName: 'Auth',
);

final authInfoLog = LogEntry(
level: LogLevel.info,
message: 'info message',
loggerName: 'Auth',
);

final authVerboseLog = LogEntry(
level: LogLevel.verbose,
message: 'verbose message',
loggerName: 'Auth',
);

final queuedItems = <QueuedItem>[
QueuedItem(
id: 1,
Expand All @@ -62,6 +126,9 @@ void main() {
];

group('enable/disable: ', () {
final hubEventController = StreamController<AuthHubEvent>.broadcast();
Amplify.Hub.addChannel(HubChannel.Auth, hubEventController.stream);

setUp(() {
mockCloudWatchLogsClient = MockCloudWatchLogsClient();
mockQueuedItemStore = MockQueuedItemStore();
Expand All @@ -74,7 +141,11 @@ void main() {
);
});

test('when enabled, logs are added to the item store', () async {
tearDownAll(hubEventController.close);

test(
'when enabled, logs are added to the item store '
'if loggable at default log level', () async {
when(
() => mockQueuedItemStore.addItem(
any(),
Expand All @@ -87,11 +158,15 @@ void main() {
.thenReturn(false);

plugin.enable();

await expectLater(
plugin.handleLogEntry(errorLog),
completes,
);
// should not log this because it is below default log level.
await expectLater(
plugin.handleLogEntry(warnLog),
completes,
);

verify(
() => mockQueuedItemStore.addItem(
Expand All @@ -100,20 +175,123 @@ void main() {
enableQueueRotation: false,
),
).called(1);

verify(
() => mockQueuedItemStore.isFull(pluginConfig.localStoreMaxSizeInMB),
).called(1);
});

test('when enabled,logs are not added to the log store if not loggable',
() async {
test(
'when enabled, logs are added to the item store '
'if loggable at category log level', () async {
when(
() => mockQueuedItemStore.addItem(
any(),
any(),
enableQueueRotation: false,
),
).thenAnswer((_) async => {});

when(() => mockQueuedItemStore.isFull(pluginConfig.localStoreMaxSizeInMB))
.thenReturn(false);

plugin.enable();
await expectLater(
plugin.handleLogEntry(authWarnLog),
completes,
);
await expectLater(
plugin.handleLogEntry(datastoreDebugLog),
completes,
);
// should not log this because it is below auth category log level.
await expectLater(
plugin.handleLogEntry(authInfoLog),
completes,
);

verify(
() => mockQueuedItemStore.addItem(
any(),
any(),
enableQueueRotation: false,
),
).called(2);
verify(
() => mockQueuedItemStore.isFull(pluginConfig.localStoreMaxSizeInMB),
).called(2);
});

test(
'when enabled, logs are added to the log store if'
' loggable at user log level', () async {
when(
() => mockQueuedItemStore.addItem(
any(),
any(),
enableQueueRotation: false,
),
).thenAnswer((_) async => {});

when(() => mockQueuedItemStore.isFull(pluginConfig.localStoreMaxSizeInMB))
.thenReturn(false);

plugin.enable();
hubEventController.add(AuthHubEvent.signedIn(MockAuthUser()));
await Future<void>.delayed(Duration.zero);

await expectLater(
plugin.handleLogEntry(authWarnLog),
completes,
);
await expectLater(
plugin.handleLogEntry(datastoreInfoLog),
completes,
);
await expectLater(
plugin.handleLogEntry(warnLog),
completes,
);
verifyZeroInteractions(mockQueuedItemStore);

// should not log these because they are below user log level.
await expectLater(
plugin.handleLogEntry(authVerboseLog),
completes,
);
await expectLater(
plugin.handleLogEntry(infoLog),
completes,
);

verify(
() => mockQueuedItemStore.addItem(
any(),
any(),
enableQueueRotation: false,
),
).called(3);
verify(
() => mockQueuedItemStore.isFull(pluginConfig.localStoreMaxSizeInMB),
).called(3);

hubEventController.add(AuthHubEvent.signedOut());
await Future<void>.delayed(Duration.zero);

// should not log this because it is below auth category log level.
await expectLater(
plugin.handleLogEntry(authDebugLog),
completes,
);

verifyNever(
() => mockQueuedItemStore.addItem(
any(),
any(),
enableQueueRotation: false,
),
);
verifyNever(
() => mockQueuedItemStore.isFull(pluginConfig.localStoreMaxSizeInMB),
);
});

test(
Expand Down Expand Up @@ -732,6 +910,7 @@ void main() {
AuthHubEvent.signedOut,
AuthHubEvent.userDeleted,
];

Amplify.Hub.addChannel(HubChannel.Auth, hubEventController.stream);
setUp(() {
mockCloudWatchLogsClient = MockCloudWatchLogsClient();
Expand Down Expand Up @@ -798,7 +977,7 @@ void main() {
plugin.handleLogEntry(errorLog),
completes,
);
hubEventController.add(AuthHubEvent.signedIn(MockAuhtUser()));
hubEventController.add(AuthHubEvent.signedIn(MockAuthUser()));
await Future<void>.delayed(Duration.zero);

verify(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,4 +18,10 @@ class MockCloudWatchLogStreamProvider extends Mock
class MockRemoteLoggingConstraintProvider extends Mock
implements RemoteLoggingConstraintProvider {}

class MockAuhtUser extends Mock implements AuthUser {}
class MockAuthUser extends Mock implements AuthUser {
@override
final String userId = 'mockUserId';

@override
final String username = 'mockUser';
}
Original file line number Diff line number Diff line change
Expand Up @@ -140,8 +140,8 @@ void main() {
"cognito-sub-xyz-123": {
"defaultLogLevel": "VERBOSE",
"categoryLogLevel": {
"API": "error",
"AUTH": "debug"
"API": "ERROR",
"AUTH": "DEBUG"
}
}
}
Expand Down

0 comments on commit b1c938b

Please sign in to comment.