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(user-feedback): capture envelopes #4535

Draft
wants to merge 6 commits into
base: armcknight/feat(user-feedback)/form
Choose a base branch
from
Draft
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
4 changes: 4 additions & 0 deletions Sentry.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -708,6 +708,7 @@
84CFA4CA2C9DF884008DA5F4 /* SentryUserFeedbackWidget.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84CFA4C92C9DF884008DA5F4 /* SentryUserFeedbackWidget.swift */; };
84CFA4CD2C9E0CA3008DA5F4 /* SentryUserFeedbackIntegration.m in Sources */ = {isa = PBXBuildFile; fileRef = 84CFA4CC2C9E0CA3008DA5F4 /* SentryUserFeedbackIntegration.m */; };
84CFA4CE2C9E0CA3008DA5F4 /* SentryUserFeedbackIntegration.h in Headers */ = {isa = PBXBuildFile; fileRef = 84CFA4CB2C9E0CA3008DA5F4 /* SentryUserFeedbackIntegration.h */; };
84DBC62C2CE82F12000C4904 /* SentryFeedback.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84DBC62B2CE82F0E000C4904 /* SentryFeedback.swift */; };
84DEE86B2B686BD400A7BC17 /* SentrySamplerDecision.h in Headers */ = {isa = PBXBuildFile; fileRef = 84DEE86A2B686BD400A7BC17 /* SentrySamplerDecision.h */; };
84DEE8762B69AD6400A7BC17 /* SentryLaunchProfiling.h in Headers */ = {isa = PBXBuildFile; fileRef = 84DEE8752B69AD6400A7BC17 /* SentryLaunchProfiling.h */; };
84E13B842CBF1D91003B52EC /* SentryUserFeedbackWidgetButtonMegaphoneIconView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84E13B832CBF1D91003B52EC /* SentryUserFeedbackWidgetButtonMegaphoneIconView.swift */; };
Expand Down Expand Up @@ -1777,6 +1778,7 @@
84CFA4C92C9DF884008DA5F4 /* SentryUserFeedbackWidget.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SentryUserFeedbackWidget.swift; sourceTree = "<group>"; };
84CFA4CB2C9E0CA3008DA5F4 /* SentryUserFeedbackIntegration.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = SentryUserFeedbackIntegration.h; path = ../../../Sentry/include/SentryUserFeedbackIntegration.h; sourceTree = "<group>"; };
84CFA4CC2C9E0CA3008DA5F4 /* SentryUserFeedbackIntegration.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; name = SentryUserFeedbackIntegration.m; path = ../../../Sentry/SentryUserFeedbackIntegration.m; sourceTree = "<group>"; };
84DBC62B2CE82F0E000C4904 /* SentryFeedback.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SentryFeedback.swift; sourceTree = "<group>"; };
84DEE86A2B686BD400A7BC17 /* SentrySamplerDecision.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SentrySamplerDecision.h; path = include/SentrySamplerDecision.h; sourceTree = "<group>"; };
84DEE8752B69AD6400A7BC17 /* SentryLaunchProfiling.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SentryLaunchProfiling.h; path = Sources/Sentry/include/SentryLaunchProfiling.h; sourceTree = SOURCE_ROOT; };
84E13B832CBF1D91003B52EC /* SentryUserFeedbackWidgetButtonMegaphoneIconView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SentryUserFeedbackWidgetButtonMegaphoneIconView.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -3524,6 +3526,7 @@
children = (
849B8F9E2C70091A00148E1F /* Configuration */,
849B8F962C6E906900148E1F /* SentryUserFeedbackIntegrationDriver.swift */,
84DBC62B2CE82F0E000C4904 /* SentryFeedback.swift */,
84CFA4CB2C9E0CA3008DA5F4 /* SentryUserFeedbackIntegration.h */,
84CFA4CC2C9E0CA3008DA5F4 /* SentryUserFeedbackIntegration.m */,
84CFA4C92C9DF884008DA5F4 /* SentryUserFeedbackWidget.swift */,
Expand Down Expand Up @@ -4566,6 +4569,7 @@
7B6438AB26A70F24000D0F65 /* UIViewController+Sentry.m in Sources */,
84302A812B5767A50027A629 /* SentryLaunchProfiling.m in Sources */,
63AA76A31EB9CBAA00D153DE /* SentryDsn.m in Sources */,
84DBC62C2CE82F12000C4904 /* SentryFeedback.swift in Sources */,
63B818FA1EC34639002FDF4C /* SentryDebugMeta.m in Sources */,
7B98D7D325FB65AE00C5A389 /* SentryWatchdogTerminationTracker.m in Sources */,
8E564AE8267AF22600FE117D /* SentryNetworkTrackingIntegration.m in Sources */,
Expand Down
34 changes: 22 additions & 12 deletions Sources/Sentry/Public/SentrySDK.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,18 @@

@protocol SentrySpan;

@class SentryOptions, SentryEvent, SentryBreadcrumb, SentryScope, SentryUser, SentryId,
SentryUserFeedback, SentryTransactionContext;
@class SentryBreadcrumb;
@class SentryEvent;
@class SentryFeedback;
@class SentryId;
@class SentryMetricsAPI;
@class UIView;
@class SentryOptions;
@class SentryReplayApi;
@class SentryScope;
@class SentryTransactionContext;
@class SentryUser;
@class SentryUserFeedback;
@class UIView;

NS_ASSUME_NONNULL_BEGIN

Expand Down Expand Up @@ -246,25 +253,28 @@ SENTRY_NO_INIT
/**
* Captures user feedback that was manually gathered and sends it to Sentry.
* @param userFeedback The user feedback to send to Sentry.
* @note This method will be deprecated in a future release; use `captureFeedback` instead.
*/
+ (void)captureUserFeedback:(SentryUserFeedback *)userFeedback
NS_SWIFT_NAME(capture(userFeedback:));

/**
* Captures user feedback that was manually gathered and sends it to Sentry.
* @param feedback The feedback to send to Sentry.
* @note If you'd prefer not to have to build the UI required to gather the feedback from the user,
* consider using `showUserFeedbackForm`, which delivers a prepackaged user feedback experience. See
* @c SentryOptions.configureUserFeedback to customize a fully managed integration. See
* https://docs.sentry.io/platforms/apple/user-feedback/#user-feedback-api and (TODO: add link to
* new docs) for more information on each approach.
* https://docs.sentry.io/platforms/apple/user-feedback/ for more information.
*/
+ (void)captureUserFeedback:(SentryUserFeedback *)userFeedback
NS_SWIFT_NAME(capture(userFeedback:));
+ (void)captureFeedback:(SentryFeedback *)feedback NS_SWIFT_NAME(capture(feedback:));

/**
* Display a form to gather information from an end user in the app to send to Sentry as a user
* feedback event.
* @see @c SentryOptions.enableUserFeedbackIntegration and @c SentryOptions.configureUserFeedback to
* enable the functionality and customize the experience.
* @note If @c SentryOptions.enableUserFeedbackIntegration is @c NO, this method is a no-op.
* @see @c SentryOptions.configureUserFeedback to customize the experience.
* @note This is a fully managed user feedback flow; there will be no need to call
* @c SentrySDK.captureUserFeedback . See
* https://docs.sentry.io/platforms/apple/user-feedback/#user-feedback-api and (TODO: add link to
* new docs) for more information on each approach.
* https://docs.sentry.io/platforms/apple/user-feedback/ for more information.
*/
+ (void)showUserFeedbackForm;

Expand Down
12 changes: 11 additions & 1 deletion Sources/Sentry/Public/SentryUserFeedback.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,14 +15,24 @@ NS_ASSUME_NONNULL_BEGIN
*/
NS_SWIFT_NAME(UserFeedback)
@interface SentryUserFeedback : NSObject <SentrySerializable>
SENTRY_NO_INIT

/**
* Initializes SentryUserFeedback and sets the required eventId.
* @param eventId The eventId of the event to which the user feedback is associated.
* @note Uses the old envelope format descried at
* https://develop.sentry.dev/sdk/data-model/envelope-items/#user-feedback and will be deprecated in
* the future.
*/
- (instancetype)initWithEventId:(SentryId *)eventId;

/**
* Initializes a new `SentryUserFeedback` as its own event, instead of one attached to a transaction
* or error event.
* @note Uses the new envelope format described at
* https://develop.sentry.dev/application/feedback-architecture/#feedback-events.
*/
- (instancetype)init;

/**
* The eventId of the event to which the user feedback is associated.
*/
Expand Down
10 changes: 10 additions & 0 deletions Sources/Sentry/SentryClient.m
Original file line number Diff line number Diff line change
Expand Up @@ -569,6 +569,16 @@ - (void)captureUserFeedback:(SentryUserFeedback *)userFeedback
[self.transportAdapter sendUserFeedback:userFeedback];
}

- (void)captureFeedback:(SentryFeedback *)feedback
{
if ([self isDisabled]) {
[self logDisabledMessage];
return;
}

[self.transportAdapter sendFeedback:feedback];
}

- (void)storeEnvelope:(SentryEnvelope *)envelope
{
[self.fileManager storeEnvelope:envelope];
Expand Down
18 changes: 18 additions & 0 deletions Sources/Sentry/SentryEnvelope.m
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,24 @@ - (instancetype)initWithUserFeedback:(SentryUserFeedback *)userFeedback
data:json];
}

- (instancetype)initWithFeedback:(SentryFeedback *)feedback
{
NSError *error = nil;
NSData *json = [NSJSONSerialization dataWithJSONObject:[feedback serialize]
options:0
error:&error];

if (nil != error) {
SENTRY_LOG_ERROR(@"Couldn't serialize feedback.");
json = [NSData new];
}

return [self
initWithHeader:[[SentryEnvelopeItemHeader alloc] initWithType:SentryEnvelopeItemTypeFeedback
length:json.length]
data:json];
}

- (instancetype)initWithClientReport:(SentryClientReport *)clientReport
{
NSError *error = nil;
Expand Down
8 changes: 8 additions & 0 deletions Sources/Sentry/SentryHub.m
Original file line number Diff line number Diff line change
Expand Up @@ -489,6 +489,14 @@ - (void)captureUserFeedback:(SentryUserFeedback *)userFeedback
}
}

- (void)captureFeedback:(SentryFeedback *)feedback
{
SentryClient *client = _client;
if (client != nil) {
[client captureFeedback:feedback];
}
}

- (void)addBreadcrumb:(SentryBreadcrumb *)crumb
{
SentryOptions *options = [[self client] options];
Expand Down
5 changes: 5 additions & 0 deletions Sources/Sentry/SentrySDK.m
Original file line number Diff line number Diff line change
Expand Up @@ -406,6 +406,11 @@ + (void)captureUserFeedback:(SentryUserFeedback *)userFeedback
[SentrySDK.currentHub captureUserFeedback:userFeedback];
}

+ (void)captureFeedback:(SentryFeedback *)feedback
{
[SentrySDK.currentHub captureFeedback:feedback];
}

+ (void)showUserFeedbackForm
{
// TODO: implement
Expand Down
11 changes: 11 additions & 0 deletions Sources/Sentry/SentryTransportAdapter.m
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
#import "SentryEnvelope.h"
#import "SentryEvent.h"
#import "SentryOptions.h"
#import "SentrySwift.h"
#import "SentryUserFeedback.h"
#import <Foundation/Foundation.h>

Expand Down Expand Up @@ -87,6 +88,16 @@ - (void)sendUserFeedback:(SentryUserFeedback *)userFeedback
[self sendEnvelope:envelope];
}

- (void)sendFeedback:(SentryFeedback *)feedback
{
SentryEnvelopeItem *item = [[SentryEnvelopeItem alloc] initWithFeedback:feedback];
SentryEnvelopeHeader *envelopeHeader =
[[SentryEnvelopeHeader alloc] initWithId:feedback.eventId];
SentryEnvelope *envelope = [[SentryEnvelope alloc] initWithHeader:envelopeHeader
singleItem:item];
[self sendEnvelope:envelope];
}

- (void)sendEnvelope:(SentryEnvelope *)envelope
{
for (id<SentryTransport> transport in self.transports) {
Expand Down
41 changes: 34 additions & 7 deletions Sources/Sentry/SentryUserFeedback.m
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,26 @@
#import "SentrySwift.h"
#import <Foundation/Foundation.h>

@implementation SentryUserFeedback
typedef enum : NSUInteger {
/** A user feedback attached to a transaction or error event. */
kSentryUserFeedbackTypeAttached,

/** A user feedback sent as its own event independent of any other event. */
kSentryUserFeedbackTypeStandalone,
} SentryUserFeedbackType;

@implementation SentryUserFeedback {
SentryUserFeedbackType _type;
}

- (instancetype)init
{
if (self = [super init]) {
_type = kSentryUserFeedbackTypeStandalone;
_eventId = [[SentryId alloc] init];
}
return self;
}

- (instancetype)initWithEventId:(SentryId *)eventId
{
Expand All @@ -11,18 +30,26 @@ - (instancetype)initWithEventId:(SentryId *)eventId
_email = @"";
_name = @"";
_comments = @"";
_type = kSentryUserFeedbackTypeAttached;
}
return self;
}

- (NSDictionary<NSString *, id> *)serialize
{
return @{
@"event_id" : self.eventId.sentryIdString,
@"email" : self.email,
@"name" : self.name,
@"comments" : self.comments
};
switch (_type) {
case kSentryUserFeedbackTypeAttached:
return @{
@"event_id" : self.eventId.sentryIdString,
@"email" : self.email,
@"name" : self.name,
@"comments" : self.comments
};
case kSentryUserFeedbackTypeStandalone:
return @{

};
}
}

@end
10 changes: 6 additions & 4 deletions Sources/Sentry/include/HybridPublic/SentryEnvelope.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,14 @@

#endif

@class SentryEvent;
@class SentrySession;
@class SentryId;
@class SentryUserFeedback;
@class SentryAttachment;
@class SentryEnvelopeItemHeader;
@class SentryEvent;
@class SentryFeedback;
@class SentryId;
@class SentrySession;
@class SentryTraceContext;
@class SentryUserFeedback;

NS_ASSUME_NONNULL_BEGIN

Expand Down Expand Up @@ -82,6 +83,7 @@ SENTRY_NO_INIT
- (instancetype)initWithEvent:(SentryEvent *)event;
- (instancetype)initWithSession:(SentrySession *)session;
- (instancetype)initWithUserFeedback:(SentryUserFeedback *)userFeedback;
- (instancetype)initWithFeedback:(SentryFeedback *)feedback;
- (_Nullable instancetype)initWithAttachment:(SentryAttachment *)attachment
maxAttachmentSize:(NSUInteger)maxAttachmentSize;
- (instancetype)initWithHeader:(SentryEnvelopeItemHeader *)header
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
static NSString *const SentryEnvelopeItemTypeEvent = @"event";
static NSString *const SentryEnvelopeItemTypeSession = @"session";
static NSString *const SentryEnvelopeItemTypeUserFeedback = @"user_report";
static NSString *const SentryEnvelopeItemTypeFeedback = @"feedback";
static NSString *const SentryEnvelopeItemTypeTransaction = @"transaction";
static NSString *const SentryEnvelopeItemTypeAttachment = @"attachment";
static NSString *const SentryEnvelopeItemTypeClientReport = @"client_report";
Expand Down
17 changes: 15 additions & 2 deletions Sources/Sentry/include/SentryClient+Private.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,15 @@
#import "SentryDataCategory.h"
#import "SentryDiscardReason.h"

@class SentrySession, SentryEnvelopeItem, SentryId, SentryAttachment, SentryThreadInspector,
SentryReplayEvent, SentryReplayRecording, SentryEnvelope;
@class SentryAttachment;
@class SentryEnvelope;
@class SentryEnvelopeItem;
@class SentryFeedback;
@class SentryId;
@class SentryReplayEvent;
@class SentryReplayRecording;
@class SentrySession;
@class SentryThreadInspector;

NS_ASSUME_NONNULL_BEGIN

Expand Down Expand Up @@ -63,6 +70,12 @@ NS_ASSUME_NONNULL_BEGIN
- (void)addAttachmentProcessor:(id<SentryClientAttachmentProcessor>)attachmentProcessor;
- (void)removeAttachmentProcessor:(id<SentryClientAttachmentProcessor>)attachmentProcessor;

/**
* Captures a new-style user feedback and sends it to Sentry.
* @param feedback The user feedback to send to Sentry.
*/
- (void)captureFeedback:(SentryFeedback *)feedback NS_SWIFT_NAME(capture(feedback:));

@end

NS_ASSUME_NONNULL_END
2 changes: 2 additions & 0 deletions Sources/Sentry/include/SentryHub+Private.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
@class SentryTransaction;
@class SentryDispatchQueueWrapper;
@class SentryEnvelope;
@class SentryFeedback;
@class SentryNSTimerFactory;
@class SentrySession;
@class SentryTracer;
Expand Down Expand Up @@ -62,6 +63,7 @@ NS_ASSUME_NONNULL_BEGIN

- (void)storeEnvelope:(SentryEnvelope *)envelope;
- (void)captureEnvelope:(SentryEnvelope *)envelope;
- (void)captureFeedback:(SentryFeedback *)feedback;

- (void)registerSessionListener:(id<SentrySessionListener>)listener;
- (void)unregisterSessionListener:(id<SentrySessionListener>)listener;
Expand Down
1 change: 1 addition & 0 deletions Sources/Sentry/include/SentryPrivate.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
#import "SentryDispatchQueueWrapper.h"
#import "SentryNSDataUtils.h"
#import "SentryRandom.h"
#import "SentrySDK+Private.h"
#import "SentryTime.h"

// Headers that also import SentryDefines should be at the end of this list
Expand Down
8 changes: 7 additions & 1 deletion Sources/Sentry/include/SentrySDK+Private.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,11 @@
# import "SentrySDK.h"
#endif

@class SentryHub, SentryId, SentryAppStartMeasurement, SentryEnvelope;
@class SentryAppStartMeasurement;
@class SentryEnvelope;
@class SentryFeedback;
@class SentryHub;
@class SentryId;

NS_ASSUME_NONNULL_BEGIN

Expand Down Expand Up @@ -51,6 +55,8 @@ NS_ASSUME_NONNULL_BEGIN
*/
+ (void)captureEnvelope:(SentryEnvelope *)envelope;

+ (void)captureFeedback:(SentryFeedback *)feedback;

@end

NS_ASSUME_NONNULL_END
Loading