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 28 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
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,11 @@
```dart
SentryNavigatorObserver(ignoreRoutes: ["/ignoreThisRoute"]),
```
- 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.

### 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 @@ -245,6 +245,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 @@ -274,6 +276,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 288 in dart/lib/src/hub.dart

View check run for this annotation

Codecov / codecov/patch

dart/lib/src/hub.dart#L288

Added line #L288 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 309 in dart/lib/src/hub.dart

View check run for this annotation

Codecov / codecov/patch

dart/lib/src/hub.dart#L309

Added line #L309 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 @@ -117,7 +118,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 @@ -196,4 +199,16 @@
@override
MetricsAggregator? get metricsAggregator =>
Sentry.currentHub.metricsAggregator;

@override

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

View check run for this annotation

Codecov / codecov/patch

dart/lib/src/hub_adapter.dart#L203

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

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

View check run for this annotation

Codecov / codecov/patch

dart/lib/src/hub_adapter.dart#L209

Added line #L209 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
}
14 changes: 14 additions & 0 deletions dart/lib/src/sentry.dart
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

import 'dart_exception_type_identifier.dart';
import 'metrics/metrics_api.dart';
import 'protocol/sentry_feedback.dart';
import 'run_zoned_guarded_integration.dart';
import 'event_processor/enricher/enricher_event_processor.dart';
import 'environment/environment_variables.dart';
Expand All @@ -21,6 +22,7 @@
import 'sentry_options.dart';
import 'sentry_user_feedback.dart';
import 'tracing.dart';
import 'sentry_attachment/sentry_attachment.dart';

/// Configuration options callback
typedef OptionsConfiguration = FutureOr<void> Function(SentryOptions);
Expand Down Expand Up @@ -216,9 +218,21 @@
/// Reports a [userFeedback] to Sentry.io.
///
/// First capture an event and use the [SentryId] to create a [SentryUserFeedback]
@Deprecated(

Check warning on line 221 in dart/lib/src/sentry.dart

View check run for this annotation

Codecov / codecov/patch

dart/lib/src/sentry.dart#L221

Added line #L221 was not covered by tests
'Will be removed in a future version. Use [captureFeedback] instead')
static Future<void> captureUserFeedback(SentryUserFeedback userFeedback) =>
_hub.captureUserFeedback(userFeedback);

/// Reports [SentryFeedback] to Sentry.io.
///
/// Use [withScope] to add [SentryAttachment] to the feedback.
static Future<SentryId> captureFeedback(
SentryFeedback feedback, {
Hint? hint,
ScopeCallback? withScope,
}) =>
_hub.captureFeedback(feedback, hint: hint, withScope: withScope);

/// Close the client SDK
static Future<void> close() async {
final hub = _hub;
Expand Down
Loading
Loading