Skip to content

Commit

Permalink
Add a filter setting to filter by a minimum log level (#8433)
Browse files Browse the repository at this point in the history
  • Loading branch information
kenzieschmoll authored Oct 15, 2024
1 parent f41c22f commit a0c2369
Show file tree
Hide file tree
Showing 5 changed files with 105 additions and 24 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,17 @@ class LoggingController extends DisposableController

@visibleForTesting
static final settingFilters = <SettingFilter<LogData, Object>>[
SettingFilter<LogData, Level>(
name: 'Hide logs below the minimum log level',
includeCallback: (LogData element, Level currentFilterValue) =>
element.level >= currentFilterValue.value,
enabledCallback: (Level filterValue) => filterValue >= Level.FINEST,
possibleValues: Level.LEVELS
// Omit Level.OFF and Level.ALL from the possible minimum levels.
.where((level) => level != Level.OFF && level != Level.ALL)
.toList(),
defaultValue: Level.INFO,
),
if (serviceConnection.serviceManager.connectedApp?.isFlutterAppNow ??
true) ...[
ToggleFilter<LogData>(
Expand Down
56 changes: 51 additions & 5 deletions packages/devtools_app/lib/src/shared/ui/filter.dart
Original file line number Diff line number Diff line change
Expand Up @@ -221,10 +221,9 @@ class _FilterDialogState<T> extends State<FilterDialog<T>>
],
for (final filter in widget.controller._settingFilters) ...[
if (filter is ToggleFilter<T>)
ToggleFilterElement(filter: filter)
_ToggleFilterElement(filter: filter)
else
// TODO(kenz): add a SettingFilterElement widget.
const SizedBox.shrink(),
_SettingFilterElement(filter: filter),
],
],
),
Expand Down Expand Up @@ -255,8 +254,8 @@ class _FilterDialogState<T> extends State<FilterDialog<T>>
}
}

class ToggleFilterElement extends StatelessWidget {
const ToggleFilterElement({super.key, required this.filter});
class _ToggleFilterElement extends StatelessWidget {
const _ToggleFilterElement({required this.filter});

final ToggleFilter filter;

Expand All @@ -281,6 +280,53 @@ class ToggleFilterElement extends StatelessWidget {
}
}

class _SettingFilterElement extends StatelessWidget {
const _SettingFilterElement({required this.filter});

final SettingFilter filter;

static const _leadingInset = 6.0;

@override
Widget build(BuildContext context) {
Widget content = Padding(
// This padding is required to left-align [_SettingFilterElement]s with
// [_ToggleFilterElement] checkboxes in the dialog.
padding: const EdgeInsets.only(left: _leadingInset),
child: Row(
children: [
Text(filter.name),
const BulletSpacer(),
ValueListenableBuilder(
valueListenable: filter.setting,
builder: (context, value, _) {
return RoundedDropDownButton(
value: value,
items: filter.possibleValues
.map(
(value) => DropdownMenuItem(
value: value,
child: Text('$value'),
),
)
.toList(),
onChanged: (value) => filter.setting.value = value!,
);
},
),
],
),
);
if (filter.tooltip != null) {
content = DevToolsTooltip(
message: filter.tooltip,
child: content,
);
}
return content;
}
}

class Filter<T> {
Filter({required this.queryFilter, required this.settingFilters});

Expand Down
3 changes: 3 additions & 0 deletions packages/devtools_app/release_notes/NEXT_RELEASE_NOTES.md
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,9 @@ severity. [#8419](https://github.com/flutter/devtools/pull/8419)
[#8427](https://github.com/flutter/devtools/pull/8427)
![Logging filter](images/log_filter.png "Logging filter")

* Added support for filtering by log severity / levels. - []()
![Log level filter](images/log_level_filter.png "Log level filter")

* Fix a bug where logs would get out of order after midnight. -
[#8420](https://github.com/flutter/devtools/pull/8420)

Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
59 changes: 40 additions & 19 deletions packages/devtools_app/test/logging/logging_controller_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import 'package:devtools_app_shared/utils.dart';
import 'package:devtools_test/devtools_test.dart';
import 'package:devtools_test/helpers.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:logging/logging.dart';

void main() {
group('LoggingController', () {
Expand All @@ -27,6 +28,7 @@ void main() {
jsonEncode({'kind': 'stdout', 'message': message}),
0,
summary: message,
level: Level.INFO.value,
),
);
}
Expand All @@ -38,12 +40,21 @@ void main() {
jsonEncode({'kind': 'gc', 'message': message}),
0,
summary: message,
level: Level.INFO.value,
),
);
}

void addLogWithKind(String kind) {
controller.log(LogData(kind, jsonEncode({'foo': 'test_data'}), 0));
void addLog({required String kind, Level? level, bool isError = false}) {
controller.log(
LogData(
kind,
jsonEncode({'foo': 'test_data'}),
0,
level: level?.value,
isError: isError,
),
);
}

setUp(() {
Expand Down Expand Up @@ -88,8 +99,8 @@ void main() {
addStdoutData('abc');
addStdoutData('def');
addStdoutData('abc ghi');
addLogWithKind('Flutter.Navigation');
addLogWithKind('Flutter.Error');
addLog(kind: 'Flutter.Navigation');
addLog(kind: 'Flutter.Error', isError: true);
addGcData('gc1');
addGcData('gc2');

Expand All @@ -112,8 +123,8 @@ void main() {
addStdoutData('abc');
addStdoutData('def');
addStdoutData('abc ghi');
addLogWithKind('Flutter.Navigation');
addLogWithKind('Flutter.Error');
addLog(kind: 'Flutter.Navigation');
addLog(kind: 'Flutter.Error', isError: true);
addGcData('gc1');
addGcData('gc2');

Expand All @@ -133,24 +144,27 @@ void main() {
addStdoutData('abc');
addStdoutData('def');
addStdoutData('abc ghi');
addLogWithKind('Flutter.Navigation');
addLogWithKind('Flutter.Error');
addLog(kind: 'Flutter.Navigation');
addLog(kind: 'Flutter.Error', isError: true);

// The following logs should all be filtered by default.
addGcData('gc1');
addGcData('gc2');
addLogWithKind('Flutter.FirstFrame');
addLogWithKind('Flutter.FrameworkInitialization');
addLogWithKind('Flutter.Frame');
addLogWithKind('Flutter.ImageSizesForFrame');
addLogWithKind('Flutter.ServiceExtensionStateChanged');
addLog(kind: 'Flutter.FirstFrame');
addLog(kind: 'Flutter.FrameworkInitialization');
addLog(kind: 'Flutter.Frame');
addLog(kind: 'Flutter.ImageSizesForFrame');
addLog(kind: 'Flutter.ServiceExtensionStateChanged');

// At this point data is filtered by the default toggle filter values.
expect(controller.data, hasLength(12));
expect(controller.filteredData.value, hasLength(5));

// Test query filters assuming default toggle filters are all enabled.
for (final filter in controller.activeFilter.value.settingFilters) {
// Test query filters assuming default setting filters are all enabled.
controller.activeFilter.value.settingFilters.first.setting.value =
Level.INFO;
for (final filter
in controller.activeFilter.value.settingFilters.sublist(1)) {
filter.setting.value = true;
}

Expand Down Expand Up @@ -186,12 +200,14 @@ void main() {
expect(controller.data, hasLength(12));
expect(controller.filteredData.value, hasLength(5));

// Test toggle filters.
final verboseFlutterFrameworkFilter =
// Test setting filters.
final minimumLogLevelFilter =
controller.activeFilter.value.settingFilters[0];
final verboseFlutterServiceFilter =
final verboseFlutterFrameworkFilter =
controller.activeFilter.value.settingFilters[1];
final gcFilter = controller.activeFilter.value.settingFilters[2];
final verboseFlutterServiceFilter =
controller.activeFilter.value.settingFilters[2];
final gcFilter = controller.activeFilter.value.settingFilters[3];

verboseFlutterFrameworkFilter.setting.value = false;
controller.setActiveFilter();
Expand All @@ -207,6 +223,11 @@ void main() {
controller.setActiveFilter();
expect(controller.data, hasLength(12));
expect(controller.filteredData.value, hasLength(12));

minimumLogLevelFilter.setting.value = Level.SEVERE;
controller.setActiveFilter();
expect(controller.data, hasLength(12));
expect(controller.filteredData.value, hasLength(1));
});
});

Expand Down

0 comments on commit a0c2369

Please sign in to comment.