Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: implement _isLoggable method #3894

Merged
merged 16 commits into from
Oct 9, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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();
}
khatruong2009 marked this conversation as resolved.
Show resolved Hide resolved
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);
khatruong2009 marked this conversation as resolved.
Show resolved Hide resolved
}

LogLevel? _getCategoryLogLevel(
khatruong2009 marked this conversation as resolved.
Show resolved Hide resolved
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.
khatruong2009 marked this conversation as resolved.
Show resolved Hide resolved
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
Loading