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

Support captureFeedback #2230

Merged
merged 42 commits into from
Oct 10, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
42 commits
Select commit Hold shift + click to select a range
249fad9
add captureFeedback methods
denrase Aug 13, 2024
76e733e
add should capture feedback as event test
denrase Aug 13, 2024
5595323
add sentry_feedback_test
denrase Aug 13, 2024
07815d8
update contexts test
denrase Aug 13, 2024
d3488c2
Merge branch 'main' into feat/capture-feedback
denrase Aug 13, 2024
684ef04
test before send feedback
denrase Aug 13, 2024
f3c8951
test hint and event processors
denrase Aug 13, 2024
95d8d9c
basic scope test
denrase Aug 13, 2024
ab350dc
test trace context and attachment behaviour
denrase Aug 13, 2024
26236e3
test sample rate for feedback and fix mock transport calls comparison
denrase Aug 13, 2024
bc22937
add hub tests
denrase Aug 13, 2024
58d83f9
add sentry tests
denrase Aug 13, 2024
74b5529
add changelog entry
denrase Aug 13, 2024
c86b10e
Merge branch 'main' into feat/capture-feedback
denrase Aug 19, 2024
9a7282c
cleanup + comments
denrase Aug 19, 2024
b238583
test envelope item for feedback
denrase Aug 19, 2024
8e12e8f
remove duplacte typedef
denrase Aug 19, 2024
ed773ef
fix test expectation
denrase Aug 19, 2024
ee71696
Deprecate captureUserFeedback
denrase Aug 19, 2024
4b403dd
update depraction info in cl
denrase Aug 19, 2024
b01cef2
format
denrase Aug 19, 2024
1733c9e
add missing option in test
denrase Aug 19, 2024
7b25235
run format
denrase Aug 19, 2024
d5c1f0d
organize imports
denrase Aug 19, 2024
4785da9
add missing method
denrase Aug 19, 2024
4ae6696
fix test epectation
denrase Aug 19, 2024
06a4a5f
ignore deprecations internally
denrase Aug 19, 2024
4bb3ceb
add to integration test, fix analyze errors
denrase Aug 19, 2024
34b2626
Merge branch 'main' into feat/capture-feedback
denrase Sep 5, 2024
5a18fdf
fix cl
denrase Sep 5, 2024
4f368c9
Merge branch 'main' into feat/capture-feedback
denrase Sep 23, 2024
995d288
disable fixture.options.automatedTestMode
denrase Sep 23, 2024
3114a70
update test
denrase Sep 23, 2024
55c6870
fix cl
denrase Sep 23, 2024
f1a8281
Add `SentryFeedbackWidget` (#2240)
denrase Sep 23, 2024
b52e3fc
Merge branch 'main' into feat/capture-feedback
denrase Oct 1, 2024
eb98dd2
fix cl
denrase Oct 1, 2024
67aec30
Merge branch 'main' into feat/capture-feedback
buenaflor Oct 10, 2024
02b7b75
Update CHANGELOG.md
buenaflor Oct 10, 2024
f187ee9
Update CHANGELOG.md
buenaflor Oct 10, 2024
b0b273c
Update CHANGELOG.md
buenaflor Oct 10, 2024
48bc130
Update CHANGELOG.md
buenaflor Oct 10, 2024
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
29 changes: 20 additions & 9 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,21 @@
- Emit `transaction.data` inside `contexts.trace.data` ([#2284](https://github.com/getsentry/sentry-dart/pull/2284))
- Blocking app starts if "appLaunchedInForeground" is false. (Android only) ([#2291](https://github.com/getsentry/sentry-dart/pull/2291))
- Windows native error & obfuscation support ([#2286](https://github.com/getsentry/sentry-dart/pull/2286))
- Support `captureFeedback` ([#2230](https://github.com/getsentry/sentry-dart/pull/2230))
- Deprecated `Sentry.captureUserFeedback`, use `captureFeedback` instead.
- Deprecated `Hub.captureUserFeedback`, use `captureFeedback` instead.
- Deprecated `SentryClient.captureUserFeedback`, use `captureFeedback` instead.
- Deprecated `SentryUserFeedback`, use `SentryFeedback` instead.
- Add `SentryFeedbackWidget` ([#2240](https://github.com/getsentry/sentry-dart/pull/2240))
```dart
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => SentryFeedbackWidget(associatedEventId: id),
fullscreenDialog: true,
),
);
```

### Enhancements

Expand Down Expand Up @@ -57,7 +72,6 @@
```

- Support allowUrls and denyUrls for Flutter Web ([#2227](https://github.com/getsentry/sentry-dart/pull/2227))

```dart
await SentryFlutter.init(
(options) {
Expand All @@ -68,7 +82,6 @@
appRunner: () => runApp(MyApp()),
);
```

- Collect touch breadcrumbs for all buttons, not just those with `key` specified. ([#2242](https://github.com/getsentry/sentry-dart/pull/2242))
- Add `enableDartSymbolication` option to Sentry.init() for **Flutter iOS, macOS and Android** ([#2256](https://github.com/getsentry/sentry-dart/pull/2256))
- This flag enables symbolication of Dart stack traces when native debug images are not available.
Expand All @@ -91,14 +104,12 @@

- Add `SentryFlutter.nativeCrash()` using MethodChannels for Android and iOS ([#2239](https://github.com/getsentry/sentry-dart/pull/2239))
- This can be used to test if native crash reporting works

- Add `ignoreRoutes` parameter to `SentryNavigatorObserver`. ([#2218](https://github.com/getsentry/sentry-dart/pull/2218))
- This will ignore the Routes and prevent the Route from being pushed to the Sentry server.
- Ignored routes will also create no TTID and TTFD spans.

```dart
SentryNavigatorObserver(ignoreRoutes: ["/ignoreThisRoute"]),
```
- This will ignore the Routes and prevent the Route from being pushed to the Sentry server.
- Ignored routes will also create no TTID and TTFD spans.
```dart
SentryNavigatorObserver(ignoreRoutes: ["/ignoreThisRoute"]),
```

### Improvements

Expand Down
2 changes: 2 additions & 0 deletions dart/lib/sentry.dart
Original file line number Diff line number Diff line change
Expand Up @@ -58,3 +58,5 @@ export 'src/utils.dart';
export 'src/spotlight.dart';
// proxy
export 'src/protocol/sentry_proxy.dart';
// feedback
export 'src/protocol/sentry_feedback.dart';
43 changes: 43 additions & 0 deletions dart/lib/src/hub.dart
Original file line number Diff line number Diff line change
Expand Up @@ -256,6 +256,8 @@
return sentryId;
}

@Deprecated(
'Will be removed in a future version. Use [captureFeedback] instead')
Future<void> captureUserFeedback(SentryUserFeedback userFeedback) async {
if (!_isEnabled) {
_options.logger(
Expand Down Expand Up @@ -288,6 +290,47 @@
}
}

/// Captures the feedback.
Future<SentryId> captureFeedback(
SentryFeedback feedback, {
Hint? hint,
ScopeCallback? withScope,
}) async {
var sentryId = SentryId.empty();

if (!_isEnabled) {
_options.logger(

Check warning on line 302 in dart/lib/src/hub.dart

View check run for this annotation

Codecov / codecov/patch

dart/lib/src/hub.dart#L302

Added line #L302 was not covered by tests
SentryLevel.warning,
"Instance is disabled and this 'captureFeedback' call is a no-op.",
);
} else {
final item = _peek();
late Scope scope;
final s = _cloneAndRunWithScope(item.scope, withScope);
if (s is Future<Scope>) {
scope = await s;
} else {
scope = s;
}

try {
sentryId = await item.client.captureFeedback(
feedback,
hint: hint,
scope: scope,
);
} catch (exception, stacktrace) {
_options.logger(

Check warning on line 323 in dart/lib/src/hub.dart

View check run for this annotation

Codecov / codecov/patch

dart/lib/src/hub.dart#L323

Added line #L323 was not covered by tests
SentryLevel.error,
'Error while capturing feedback',
exception: exception,
stackTrace: stacktrace,
);
}
}
return sentryId;
}

FutureOr<Scope> _cloneAndRunWithScope(
Scope scope, ScopeCallback? withScope) async {
if (withScope != null) {
Expand Down
19 changes: 17 additions & 2 deletions dart/lib/src/hub_adapter.dart
Original file line number Diff line number Diff line change
@@ -1,19 +1,20 @@
import 'dart:async';

import 'package:meta/meta.dart';
import 'hint.dart';

import 'hint.dart';
import 'hub.dart';
import 'metrics/metric.dart';
import 'metrics/metrics_aggregator.dart';
import 'metrics/metrics_api.dart';
import 'profiling.dart';
import 'protocol.dart';
import 'protocol/sentry_feedback.dart';
import 'scope.dart';
import 'sentry.dart';
import 'sentry_client.dart';
import 'sentry_user_feedback.dart';
import 'sentry_options.dart';
import 'sentry_user_feedback.dart';
import 'tracing.dart';

/// Hub adapter to make Integrations testable
Expand Down Expand Up @@ -118,7 +119,9 @@
ISentrySpan? getSpan() => Sentry.currentHub.getSpan();

@override
// ignore: deprecated_member_use_from_same_package
Future<void> captureUserFeedback(SentryUserFeedback userFeedback) =>
// ignore: deprecated_member_use_from_same_package
Sentry.captureUserFeedback(userFeedback);

@override
Expand Down Expand Up @@ -197,4 +200,16 @@
@override
MetricsAggregator? get metricsAggregator =>
Sentry.currentHub.metricsAggregator;

@override

Check warning on line 204 in dart/lib/src/hub_adapter.dart

View check run for this annotation

Codecov / codecov/patch

dart/lib/src/hub_adapter.dart#L204

Added line #L204 was not covered by tests
Future<SentryId> captureFeedback(
SentryFeedback feedback, {
Hint? hint,
ScopeCallback? withScope,
}) =>
Sentry.currentHub.captureFeedback(

Check warning on line 210 in dart/lib/src/hub_adapter.dart

View check run for this annotation

Codecov / codecov/patch

dart/lib/src/hub_adapter.dart#L210

Added line #L210 was not covered by tests
feedback,
hint: hint,
withScope: withScope,
);
}
10 changes: 10 additions & 0 deletions dart/lib/src/noop_hub.dart
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
import 'metrics/metrics_api.dart';
import 'profiling.dart';
import 'protocol.dart';
import 'protocol/sentry_feedback.dart';
import 'scope.dart';
import 'sentry_client.dart';
import 'sentry_options.dart';
Expand Down Expand Up @@ -96,8 +97,17 @@
SentryId.empty();

@override
// ignore: deprecated_member_use_from_same_package
Future<void> captureUserFeedback(SentryUserFeedback userFeedback) async {}

@override

Check warning on line 103 in dart/lib/src/noop_hub.dart

View check run for this annotation

Codecov / codecov/patch

dart/lib/src/noop_hub.dart#L103

Added line #L103 was not covered by tests
Future<SentryId> captureFeedback(
SentryFeedback feedback, {
Hint? hint,
ScopeCallback? withScope,
}) async =>
SentryId.empty();

Check warning on line 109 in dart/lib/src/noop_hub.dart

View check run for this annotation

Codecov / codecov/patch

dart/lib/src/noop_hub.dart#L109

Added line #L109 was not covered by tests

@override
ISentrySpan startTransaction(
String name,
Expand Down
7 changes: 7 additions & 0 deletions dart/lib/src/noop_sentry_client.dart
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import 'hint.dart';
import 'metrics/metric.dart';
import 'metrics/metrics_aggregator.dart';
import 'protocol.dart';
import 'protocol/sentry_feedback.dart';
import 'scope.dart';
import 'sentry_client.dart';
import 'sentry_envelope.dart';
Expand Down Expand Up @@ -55,6 +56,7 @@ class NoOpSentryClient implements SentryClient {
SentryId.empty();

@override
// ignore: deprecated_member_use_from_same_package
Future<void> captureUserFeedback(SentryUserFeedback userFeedback) async {}

@override
Expand All @@ -77,4 +79,9 @@ class NoOpSentryClient implements SentryClient {
@override
@internal
MetricsAggregator? get metricsAggregator => null;

@override
Future<SentryId> captureFeedback(SentryFeedback feedback,
{Scope? scope, Hint? hint}) async =>
SentryId.empty();
}
22 changes: 22 additions & 0 deletions dart/lib/src/protocol/contexts.dart
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import 'dart:collection';

import '../protocol.dart';
import 'sentry_feedback.dart';

/// The context interfaces provide additional context data.
///
Expand All @@ -19,6 +20,7 @@
SentryCulture? culture,
SentryTraceContext? trace,
SentryResponse? response,
SentryFeedback? feedback,
}) : super({
SentryDevice.type: device,
SentryOperatingSystem.type: operatingSystem,
Expand All @@ -29,6 +31,7 @@
SentryCulture.type: culture,
SentryTraceContext.type: trace,
SentryResponse.type: response,
SentryFeedback.type: feedback,
});

/// Deserializes [Contexts] from JSON [Map].
Expand Down Expand Up @@ -62,6 +65,9 @@
response: data[SentryResponse.type] != null
? SentryResponse.fromJson(Map.from(data[SentryResponse.type]))
: null,
feedback: data[SentryFeedback.type] != null
? SentryFeedback.fromJson(Map.from(data[SentryFeedback.type]))
: null,
);

data.keys
Expand Down Expand Up @@ -136,6 +142,11 @@

set response(SentryResponse? value) => this[SentryResponse.type] = value;

/// Feedback context for a feedback event.
SentryFeedback? get feedback => this[SentryFeedback.type];

set feedback(SentryFeedback? value) => this[SentryFeedback.type] = value;

Check warning on line 148 in dart/lib/src/protocol/contexts.dart

View check run for this annotation

Codecov / codecov/patch

dart/lib/src/protocol/contexts.dart#L148

Added line #L148 was not covered by tests

/// Produces a [Map] that can be serialized to JSON.
Map<String, dynamic> toJson() {
final json = <String, dynamic>{};
Expand Down Expand Up @@ -198,6 +209,13 @@
}
break;

case SentryFeedback.type:
final feedbackMap = feedback?.toJson();
if (feedbackMap?.isNotEmpty ?? false) {
json[SentryFeedback.type] = feedbackMap;
}
break;

case SentryRuntime.listType:
if (runtimes.length == 1) {
final runtime = runtimes[0];
Expand Down Expand Up @@ -249,6 +267,7 @@
trace: trace?.clone(),
response: response?.clone(),
runtimes: runtimes.map((runtime) => runtime.clone()).toList(),
feedback: feedback?.clone(),
)..addEntries(
entries.where((element) => !_defaultFields.contains(element.key)),
);
Expand All @@ -266,6 +285,7 @@
SentryGpu? gpu,
SentryTraceContext? trace,
SentryResponse? response,
SentryFeedback? feedback,
}) =>
Contexts(
device: device ?? this.device,
Expand All @@ -277,6 +297,7 @@
culture: culture ?? this.culture,
trace: trace ?? this.trace,
response: response ?? this.response,
feedback: feedback ?? this.feedback,
)..addEntries(
entries.where((element) => !_defaultFields.contains(element.key)),
);
Expand All @@ -292,5 +313,6 @@
SentryCulture.type,
SentryTraceContext.type,
SentryResponse.type,
SentryFeedback.type,
];
}
81 changes: 81 additions & 0 deletions dart/lib/src/protocol/sentry_feedback.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
import 'package:meta/meta.dart';

import 'access_aware_map.dart';
import 'sentry_id.dart';

@immutable
class SentryFeedback {
static const type = 'feedback';

SentryFeedback({
required this.message,
this.contactEmail,
this.name,
this.replayId,
this.url,
this.associatedEventId,
this.unknown,
});

final String message;
final String? contactEmail;
final String? name;
final String? replayId;
final String? url;
final SentryId? associatedEventId;

@internal
final Map<String, dynamic>? unknown;

/// Deserializes a [SentryFeedback] from JSON [Map].
factory SentryFeedback.fromJson(Map<String, dynamic> data) {
final json = AccessAwareMap(data);

String? associatedEventId = json['associated_event_id'];

return SentryFeedback(
message: json['message'],
contactEmail: json['contact_email'],
name: json['name'],
replayId: json['replay_id'],
url: json['url'],
associatedEventId:
associatedEventId != null ? SentryId.fromId(associatedEventId) : null,
unknown: json.notAccessed(),
);
}

Map<String, dynamic> toJson() {
return {
...?unknown,
'message': message,
if (contactEmail != null) 'contact_email': contactEmail,
if (name != null) 'name': name,
if (replayId != null) 'replay_id': replayId,
if (url != null) 'url': url,
if (associatedEventId != null)
'associated_event_id': associatedEventId.toString(),
};
}

SentryFeedback copyWith({
String? message,
String? contactEmail,
String? name,
String? replayId,
String? url,
SentryId? associatedEventId,
Map<String, dynamic>? unknown,
}) =>
SentryFeedback(
message: message ?? this.message,
contactEmail: contactEmail ?? this.contactEmail,
name: name ?? this.name,
replayId: replayId ?? this.replayId,
url: url ?? this.url,
associatedEventId: associatedEventId ?? this.associatedEventId,
unknown: unknown ?? this.unknown,
);

SentryFeedback clone() => copyWith();

Check warning on line 80 in dart/lib/src/protocol/sentry_feedback.dart

View check run for this annotation

Codecov / codecov/patch

dart/lib/src/protocol/sentry_feedback.dart#L80

Added line #L80 was not covered by tests
}
Loading
Loading