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

Add flag to disable reporting of view hierarchy identifiers #2158

Merged
merged 7 commits into from
Jul 15, 2024
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
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@

### Features

- Add flag to disable reporting of view hierarchy identifiers ([#2158](https://github.com/getsentry/sentry-dart/pull/2158))
- Use `reportViewHierarchyIdentifiers` to enable or disable the option
- Record dropped spans in client reports ([#2154](https://github.com/getsentry/sentry-dart/pull/2154))
- Add memory usage to contexts ([#2133](https://github.com/getsentry/sentry-dart/pull/2133))
- Only for Linux/Windows applications, as iOS/Android/macOS use native SDKs
Expand Down
8 changes: 8 additions & 0 deletions flutter/lib/src/sentry_flutter_options.dart
Original file line number Diff line number Diff line change
Expand Up @@ -213,6 +213,14 @@ class SentryFlutterOptions extends SentryOptions {
@experimental
bool attachViewHierarchy = false;

/// Enables collection of view hierarchy element identifiers.
///
/// Identifiers are extracted from widget keys.
/// Disable this flag if your widget keys contain sensitive data.
///
/// Default: `true`
bool reportViewHierarchyIdentifiers = true;

/// When enabled, the SDK tracks when the application stops responding for a
/// specific amount of time, See [appHangTimeoutInterval].
/// Only available on iOS and macOS.
Expand Down
15 changes: 11 additions & 4 deletions flutter/lib/src/view_hierarchy/sentry_tree_walker.dart
Original file line number Diff line number Diff line change
Expand Up @@ -209,9 +209,10 @@ import '../widget_utils.dart';
class _TreeWalker {
static const _privateDelimiter = '_';

_TreeWalker(this.rootElement);
_TreeWalker(this.rootElement, this.options);

final Element rootElement;
final SentryFlutterOptions options;

ValueChanged<Element> _visitor(
SentryViewHierarchyElement parentSentryElement) {
Expand Down Expand Up @@ -278,10 +279,15 @@ class _TreeWalker {
alpha = widget.opacity;
}

String? identifier;
if (options.reportViewHierarchyIdentifiers) {
identifier = WidgetUtils.toStringValue(widget.key);
}

return SentryViewHierarchyElement(
element.widget.runtimeType.toString(),
depth: element.depth,
identifier: WidgetUtils.toStringValue(element.widget.key),
identifier: identifier,
width: width,
height: height,
x: x,
Expand All @@ -292,15 +298,16 @@ class _TreeWalker {
}
}

SentryViewHierarchy? walkWidgetTree(WidgetsBinding instance) {
SentryViewHierarchy? walkWidgetTree(
WidgetsBinding instance, SentryFlutterOptions options) {
// to keep compatibility with older versions
// ignore: deprecated_member_use
final rootElement = instance.renderViewElement;
if (rootElement == null) {
return null;
}

final walker = _TreeWalker(rootElement);
final walker = _TreeWalker(rootElement, options);

return walker.toSentryViewHierarchy();
}
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ class SentryViewHierarchyEventProcessor implements EventProcessor {
if (instance == null) {
return event;
}
final sentryViewHierarchy = walkWidgetTree(instance);
final sentryViewHierarchy = walkWidgetTree(instance, _options);

if (sentryViewHierarchy == null) {
return event;
Expand Down
8 changes: 5 additions & 3 deletions flutter/test/view_hierarchy/sentry_tree_walker_test.dart
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:sentry/sentry.dart';
import 'package:sentry_flutter/sentry_flutter.dart';
import 'package:sentry_flutter/src/view_hierarchy/sentry_tree_walker.dart';

void main() {
Expand All @@ -16,7 +16,8 @@ void main() {
await tester.runAsync(() async {
await tester.pumpWidget(MyApp());

final sentryViewHierarchy = walkWidgetTree(instance);
final sentryViewHierarchy =
walkWidgetTree(instance, SentryFlutterOptions());

expect(sentryViewHierarchy!.renderingSystem, 'flutter');
});
Expand Down Expand Up @@ -147,7 +148,8 @@ void main() {

SentryViewHierarchyElement _getFirstSentryViewHierarchy(
WidgetsBinding instance) {
final sentryViewHierarchy = walkWidgetTree(instance);
final options = SentryFlutterOptions();
final sentryViewHierarchy = walkWidgetTree(instance, options);

return sentryViewHierarchy!.windows.first;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import 'dart:convert';

import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:sentry/sentry.dart';
Expand Down Expand Up @@ -79,6 +81,27 @@ void main() {
expect(hint.viewHierarchy, isNull);
});
});

testWidgets('does not add view hierarchy identifiers if opt out in options',
(tester) async {
await tester.runAsync(() async {
final sut =
fixture.getSut(instance, reportViewHierarchyIdentifiers: false);

await tester.pumpWidget(MyApp());

final event = SentryEvent(
exceptions: [SentryException(type: 'type', value: 'value')]);
final hint = Hint();

sut.apply(event, hint);

expect(hint.viewHierarchy, isNotNull);
final bytes = await hint.viewHierarchy!.bytes;
final jsonString = utf8.decode(bytes);
expect(jsonString, isNot(contains('identifier')));
});
});
});
}

Expand All @@ -99,9 +122,11 @@ class TestBindingWrapper implements BindingWrapper {
}

class Fixture {
SentryViewHierarchyEventProcessor getSut(WidgetsBinding instance) {
SentryViewHierarchyEventProcessor getSut(WidgetsBinding instance,
{bool reportViewHierarchyIdentifiers = true}) {
final options = SentryFlutterOptions()
..bindingUtils = TestBindingWrapper(instance);
..bindingUtils = TestBindingWrapper(instance)
..reportViewHierarchyIdentifiers = reportViewHierarchyIdentifiers;
return SentryViewHierarchyEventProcessor(options);
}
}
Expand Down
Loading