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(Session Replay): Replay Options #3674

Merged
merged 39 commits into from
Feb 29, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
39 commits
Select commit Hold shift + click to select a range
663199a
Merge branch 'feat/session-replay' into feat(SR)/ReplayEvent
brustolin Feb 12, 2024
eae7f93
feat(Session Replay): ReplayEvent, ReplayRecording and Envelope handling
brustolin Feb 14, 2024
7f7be69
Merge branch 'main' into feat(SR)/ReplayEvent
brustolin Feb 14, 2024
37d92b3
Merge branch 'feat/session-replay' into feat(SR)/ReplayEvent
brustolin Feb 14, 2024
9e21c1e
refactoring
brustolin Feb 15, 2024
ad347c3
SessionReplayIntegration
brustolin Feb 16, 2024
723b074
MsgPack
brustolin Feb 19, 2024
d27ec15
Capture with scope
brustolin Feb 19, 2024
665bec4
MsgPack Tests
brustolin Feb 19, 2024
f42c9e7
Format code
getsentry-bot Feb 19, 2024
398e3d0
Replacing envelope item
brustolin Feb 19, 2024
ab57929
Merge branch 'feat(SR)/ReplayEvent' of github.com:getsentry/sentry-co…
brustolin Feb 19, 2024
33ead44
more test
brustolin Feb 19, 2024
6cd821e
Format code
getsentry-bot Feb 19, 2024
216c42e
Hub test
brustolin Feb 19, 2024
21efb9a
Update SentryHubTests.swift
brustolin Feb 19, 2024
b11fc9a
Merge branch 'feat(SR)/ReplayEvent' into feat(SR)/replay-integration
brustolin Feb 20, 2024
d6d8ce0
integration
brustolin Feb 20, 2024
522e972
More tests and log messages
brustolin Feb 20, 2024
522a5da
Format code
getsentry-bot Feb 20, 2024
4463fed
CategoryMapper tests
brustolin Feb 20, 2024
b14f253
Update SentryMsgPackSerializer.m
brustolin Feb 20, 2024
16b192d
Format code
getsentry-bot Feb 20, 2024
3d37160
Format code
getsentry-bot Feb 20, 2024
b725be7
Clean Up PR
brustolin Feb 20, 2024
5443cdc
Update SentryOptions.m
brustolin Feb 20, 2024
32227b1
Test
brustolin Feb 21, 2024
77066c7
fixing for tvos
brustolin Feb 21, 2024
e5e5b12
more fixes
brustolin Feb 21, 2024
939a6c1
Update Sentry.h
brustolin Feb 21, 2024
837c211
Update project.pbxproj
brustolin Feb 21, 2024
2cab983
Merge branch 'feat/session-replay' into feat(SR)/ReplayEvent
brustolin Feb 21, 2024
a3f7a62
Merge branch 'feat(SR)/ReplayEvent' into feat(SR)/replay-settings
brustolin Feb 21, 2024
823a528
Rename settings to options
brustolin Feb 22, 2024
6c40d23
Format code
getsentry-bot Feb 22, 2024
381beef
Merge branch 'feat/session-replay' into feat(SR)/replay-settings
brustolin Feb 29, 2024
d578eca
Merge branch 'feat/session-replay' into feat(SR)/replay-settings
brustolin Feb 29, 2024
cbfd13e
Merge branch 'feat(SR)/replay-settings' of github.com:getsentry/sentr…
brustolin Feb 29, 2024
55a6a5d
Update SentryOptionsTest.m
brustolin Feb 29, 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
10 changes: 10 additions & 0 deletions Sentry.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -768,6 +768,8 @@
D8292D7D2A39A027009872F7 /* UrlSanitizedTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D8292D7C2A39A027009872F7 /* UrlSanitizedTests.swift */; };
D8370B6A273DF1E900F66E2D /* SentryNSURLSessionTaskSearch.m in Sources */ = {isa = PBXBuildFile; fileRef = D8370B68273DF1E900F66E2D /* SentryNSURLSessionTaskSearch.m */; };
D8370B6C273DF20F00F66E2D /* SentryNSURLSessionTaskSearch.h in Headers */ = {isa = PBXBuildFile; fileRef = D8370B6B273DF20F00F66E2D /* SentryNSURLSessionTaskSearch.h */; };
D83D07812B7E5EFA00CC9674 /* SentryReplayOptions.h in Headers */ = {isa = PBXBuildFile; fileRef = D83D07802B7E5EFA00CC9674 /* SentryReplayOptions.h */; settings = {ATTRIBUTES = (Public, ); }; };
D83D07832B7E5F2100CC9674 /* SentryReplayOptions.m in Sources */ = {isa = PBXBuildFile; fileRef = D83D07822B7E5F2100CC9674 /* SentryReplayOptions.m */; };
D83D079B2B7F9D1C00CC9674 /* SentryMsgPackSerializer.h in Headers */ = {isa = PBXBuildFile; fileRef = D83D07992B7F9D1C00CC9674 /* SentryMsgPackSerializer.h */; };
D83D079C2B7F9D1C00CC9674 /* SentryMsgPackSerializer.m in Sources */ = {isa = PBXBuildFile; fileRef = D83D079A2B7F9D1C00CC9674 /* SentryMsgPackSerializer.m */; };
D84541182A2DC2CD00E2B11C /* SentryBinaryImageCacheTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D84541172A2DC2CD00E2B11C /* SentryBinaryImageCacheTests.swift */; };
Expand Down Expand Up @@ -1774,6 +1776,9 @@
D8292D7C2A39A027009872F7 /* UrlSanitizedTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UrlSanitizedTests.swift; sourceTree = "<group>"; };
D8370B68273DF1E900F66E2D /* SentryNSURLSessionTaskSearch.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SentryNSURLSessionTaskSearch.m; sourceTree = "<group>"; };
D8370B6B273DF20F00F66E2D /* SentryNSURLSessionTaskSearch.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SentryNSURLSessionTaskSearch.h; path = include/SentryNSURLSessionTaskSearch.h; sourceTree = "<group>"; };
D83D07802B7E5EFA00CC9674 /* SentryReplayOptions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SentryReplayOptions.h; path = Public/SentryReplayOptions.h; sourceTree = "<group>"; };
D83D07822B7E5F2100CC9674 /* SentryReplayOptions.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SentryReplayOptions.m; sourceTree = "<group>"; };
D83D07842B7E634F00CC9674 /* SentryReplayOptions+Private.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "SentryReplayOptions+Private.h"; path = "include/HybridPublic/SentryReplayOptions+Private.h"; sourceTree = "<group>"; };
D83D07992B7F9D1C00CC9674 /* SentryMsgPackSerializer.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = SentryMsgPackSerializer.h; path = include/SentryMsgPackSerializer.h; sourceTree = "<group>"; };
D83D079A2B7F9D1C00CC9674 /* SentryMsgPackSerializer.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SentryMsgPackSerializer.m; sourceTree = "<group>"; };
D84541172A2DC2CD00E2B11C /* SentryBinaryImageCacheTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SentryBinaryImageCacheTests.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -3428,6 +3433,9 @@
D80694CC2B7E0A3E00B820E6 /* SentryReplayType.m */,
D88D6C1B2B7B5A8800C8C633 /* SentryReplayRecording.h */,
D88D6C1C2B7B5A8800C8C633 /* SentryReplayRecording.m */,
D83D07802B7E5EFA00CC9674 /* SentryReplayOptions.h */,
D83D07842B7E634F00CC9674 /* SentryReplayOptions+Private.h */,
D83D07822B7E5F2100CC9674 /* SentryReplayOptions.m */,
);
name = SessionReplay;
sourceTree = "<group>";
Expand Down Expand Up @@ -3664,6 +3672,7 @@
03F84D2727DD414C008FE43F /* SentryMachLogging.hpp in Headers */,
63295AF51EF3C7DB002D4490 /* NSDictionary+SentrySanitize.h in Headers */,
8E4A037825F6F52100000D77 /* SentrySampleDecision.h in Headers */,
D83D07812B7E5EFA00CC9674 /* SentryReplayOptions.h in Headers */,
63FE717920DA4C1100CDBAE8 /* SentryCrashReportStore.h in Headers */,
0AAE202128ED9BCC00D0CD80 /* SentryReachability.h in Headers */,
D858FA662A29EAB3002A3503 /* SentryBinaryImageCache.h in Headers */,
Expand Down Expand Up @@ -4279,6 +4288,7 @@
63FE716720DA4C1100CDBAE8 /* SentryCrashCPU.c in Sources */,
63FE717320DA4C1100CDBAE8 /* SentryCrashC.c in Sources */,
63FE712120DA4C1000CDBAE8 /* SentryCrashSymbolicator.c in Sources */,
D83D07832B7E5F2100CC9674 /* SentryReplayOptions.m in Sources */,
63FE70D720DA4C1000CDBAE8 /* SentryCrashMonitor_MachException.c in Sources */,
7B96572226830D2400C66E25 /* SentryScopeSyncC.c in Sources */,
0A9BF4E228A114940068D266 /* SentryViewHierarchyIntegration.m in Sources */,
Expand Down
1 change: 1 addition & 0 deletions Sources/Sentry/Public/Sentry.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ FOUNDATION_EXPORT const unsigned char SentryVersionString[];
#import "SentryMessage.h"
#import "SentryNSError.h"
#import "SentryOptions.h"
#import "SentryReplayOptions.h"
#import "SentryRequest.h"
#import "SentrySDK.h"
#import "SentrySampleDecision.h"
Expand Down
12 changes: 11 additions & 1 deletion Sources/Sentry/Public/SentryOptions.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@

NS_ASSUME_NONNULL_BEGIN

@class SentryDsn, SentryMeasurementValue, SentryHttpStatusCodeRange, SentryScope;
@class SentryDsn, SentryMeasurementValue, SentryHttpStatusCodeRange, SentryScope,
SentryReplayOptions;

NS_SWIFT_NAME(Options)
@interface SentryOptions : NSObject
Expand Down Expand Up @@ -269,6 +270,15 @@ NS_SWIFT_NAME(Options)
* @note Default value is @c NO .
*/
@property (nonatomic, assign) BOOL enablePreWarmedAppStartTracing;

/**
* @warning This is an experimental feature and may still have bugs.
* Settings to configure the session replay.
* @node Default value is @c nil .
*/
@property (nonatomic, strong)
SentryReplayOptions *sessionReplayOptions API_AVAILABLE(ios(16.0), tvos(16.0));

#endif // SENTRY_UIKIT_AVAILABLE

/**
Expand Down
38 changes: 38 additions & 0 deletions Sources/Sentry/Public/SentryReplayOptions.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
#import <Foundation/Foundation.h>

NS_ASSUME_NONNULL_BEGIN

@interface SentryReplayOptions : NSObject

/**
* Indicates the percentage in which the replay for the session will be created.
* @discussion Specifying @c 0 means never, @c 1.0 means always.
* @note The value needs to be >= 0.0 and \<= 1.0. When setting a value out of range the SDK sets it
* to the default.
* @note The default is @c 0.
*/
@property (nonatomic) float replaysSessionSampleRate;

/**
* Indicates the percentage in which a 30 seconds replay will be send with error events.
* @discussion Specifying @c 0 means never, @c 1.0 means always.
* @note The value needs to be >= 0.0 and \<= 1.0. When setting a value out of range the SDK sets it
* to the default.
* @note The default is @c 0.
*/
@property (nonatomic) float replaysOnErrorSampleRate;
brustolin marked this conversation as resolved.
Show resolved Hide resolved

/**
* Inittialize the settings of session replay
*
* @param sessionSampleRate Indicates the percentage in which the replay for the session will be
* created.
* @param errorSampleRate Indicates the percentage in which a 30 seconds replay will be send with
* error events.
*/
- (instancetype)initWithReplaySessionSampleRate:(float)sessionSampleRate
replaysOnErrorSampleRate:(float)errorSampleRate;

@end

NS_ASSUME_NONNULL_END
14 changes: 14 additions & 0 deletions Sources/Sentry/SentryBaseIntegration.m
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#import "SentryBaseIntegration.h"
#import "SentryCrashWrapper.h"
#import "SentryLog.h"
#import "SentryReplayOptions.h"
#import <Foundation/Foundation.h>
#import <SentryDependencyContainer.h>
#import <SentryOptions+Private.h>
Expand Down Expand Up @@ -140,6 +141,19 @@
[self logWithOptionName:@"attachViewHierarchy"];
return NO;
}

if (integrationOptions & kIntegrationOptionEnableReplay) {
if (@available(iOS 16.0, tvOS 16.0, *)) {
if (options.sessionReplayOptions.replaysOnErrorSampleRate == 0
&& options.sessionReplayOptions.replaysSessionSampleRate == 0) {
[self logWithOptionName:@"sessionReplaySettings"];
return NO;

Check warning on line 150 in Sources/Sentry/SentryBaseIntegration.m

View check run for this annotation

Codecov / codecov/patch

Sources/Sentry/SentryBaseIntegration.m#L149-L150

Added lines #L149 - L150 were not covered by tests
}
} else {
[self logWithReason:@"Session replay requires iOS 16 or above"];
return NO;

Check warning on line 154 in Sources/Sentry/SentryBaseIntegration.m

View check run for this annotation

Codecov / codecov/patch

Sources/Sentry/SentryBaseIntegration.m#L153-L154

Added lines #L153 - L154 were not covered by tests
}
}
#endif

if ((integrationOptions & kIntegrationOptionEnableCrashHandler)
Expand Down
14 changes: 10 additions & 4 deletions Sources/Sentry/SentryOptions.m
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,8 @@
# import "SentryAppStartTrackingIntegration.h"
# import "SentryFramesTrackingIntegration.h"
# import "SentryPerformanceTrackingIntegration.h"
# if SENTRY_HAS_UIKIT
# import "SentryScreenshotIntegration.h"
# endif // SENTRY_HAS_UIKIT
# import "SentryReplayOptions+Private.h"
# import "SentryScreenshotIntegration.h"
# import "SentryUIEventTrackingIntegration.h"
# import "SentryViewHierarchyIntegration.h"
# import "SentryWatchdogTerminationTrackingIntegration.h"
Expand Down Expand Up @@ -382,7 +381,6 @@ - (BOOL)validateOptions:(NSDictionary<NSString *, id> *)options
if ([self isBlock:options[@"initialScope"]]) {
self.initialScope = options[@"initialScope"];
}

#if SENTRY_HAS_UIKIT
[self setBool:options[@"enableUIViewControllerTracing"]
block:^(BOOL value) { self->_enableUIViewControllerTracing = value; }];
Expand All @@ -402,6 +400,14 @@ - (BOOL)validateOptions:(NSDictionary<NSString *, id> *)options

[self setBool:options[@"enablePreWarmedAppStartTracing"]
block:^(BOOL value) { self->_enablePreWarmedAppStartTracing = value; }];

if (@available(iOS 16.0, tvOS 16.0, *)) {
if ([options[@"sessionReplayOptions"] isKindOfClass:NSDictionary.class]) {
self.sessionReplayOptions =
[[SentryReplayOptions alloc] initWithDictionary:options[@"sessionReplayOptions"]];
}
}

#endif // SENTRY_HAS_UIKIT

[self setBool:options[@"enableAppHangTracking"]
Expand Down
51 changes: 51 additions & 0 deletions Sources/Sentry/SentryReplayOptions.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
#import "SentryReplayOptions.h"

NS_ASSUME_NONNULL_BEGIN

@interface
SentryReplayOptions ()

@property (nonatomic) NSInteger replayBitRate;

@end

@implementation SentryReplayOptions

- (instancetype)init
{
if (self = [super init]) {
self.replaysSessionSampleRate = 0;
self.replaysOnErrorSampleRate = 0;
self.replayBitRate = 20000;
}
return self;
}

- (instancetype)initWithReplaySessionSampleRate:(float)sessionSampleRate
replaysOnErrorSampleRate:(float)errorSampleRate
{
if (self = [self init]) {
self.replaysSessionSampleRate = sessionSampleRate;
self.replaysOnErrorSampleRate = errorSampleRate;

Check warning on line 29 in Sources/Sentry/SentryReplayOptions.m

View check run for this annotation

Codecov / codecov/patch

Sources/Sentry/SentryReplayOptions.m#L28-L29

Added lines #L28 - L29 were not covered by tests
}

return self;
}

Check warning on line 33 in Sources/Sentry/SentryReplayOptions.m

View check run for this annotation

Codecov / codecov/patch

Sources/Sentry/SentryReplayOptions.m#L32-L33

Added lines #L32 - L33 were not covered by tests

- (instancetype)initWithDictionary:(NSDictionary *)dictionary
{
if (self = [self init]) {
if ([dictionary[@"replaysSessionSampleRate"] isKindOfClass:NSNumber.class]) {
self.replaysSessionSampleRate = [dictionary[@"replaysSessionSampleRate"] floatValue];
}

if ([dictionary[@"replaysOnErrorSampleRate"] isKindOfClass:NSNumber.class]) {
self.replaysOnErrorSampleRate = [dictionary[@"replaysOnErrorSampleRate"] floatValue];
}
}
return self;
}

@end

NS_ASSUME_NONNULL_END
20 changes: 20 additions & 0 deletions Sources/Sentry/include/HybridPublic/SentryReplayOptions+Private.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
#import "SentryReplayOptions.h"
#import <Foundation/Foundation.h>

NS_ASSUME_NONNULL_BEGIN

@interface
SentryReplayOptions (Private)

/**
* Defines the quality of the session replay.
* Higher bit rates better quality, but also bigger files to transfer.
* @note The default value is @c 20000;
*/
@property (nonatomic) NSInteger replayBitRate;

- (instancetype)initWithDictionary:(NSDictionary *)dictionary;

@end

NS_ASSUME_NONNULL_END
1 change: 1 addition & 0 deletions Sources/Sentry/include/SentryBaseIntegration.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ typedef NS_OPTIONS(NSUInteger, SentryIntegrationOption) {
kIntegrationOptionAttachViewHierarchy = 1 << 15,
kIntegrationOptionEnableCrashHandler = 1 << 16,
kIntegrationOptionEnableMetricKit = 1 << 17,
kIntegrationOptionEnableReplay = 1 << 18,
};

@interface SentryBaseIntegration : NSObject
Expand Down
25 changes: 25 additions & 0 deletions Tests/SentryTests/SentryOptionsTest.m
Original file line number Diff line number Diff line change
Expand Up @@ -544,6 +544,7 @@ - (void)testNSNull_SetsDefaultValue
#if SENTRY_HAS_UIKIT
@"enableUIViewControllerTracing" : [NSNull null],
@"attachScreenshot" : [NSNull null],
@"sessionReplayOptions" : [NSNull null],
#endif
@"enableAppHangTracking" : [NSNull null],
@"appHangTimeoutInterval" : [NSNull null],
Expand Down Expand Up @@ -603,6 +604,9 @@ - (void)assertDefaultValues:(SentryOptions *)options
XCTAssertEqual(options.enableUserInteractionTracing, YES);
XCTAssertEqual(options.enablePreWarmedAppStartTracing, NO);
XCTAssertEqual(options.attachViewHierarchy, NO);
if (@available(iOS 16.0, tvOS 16.0, *)) {
XCTAssertNil(options.sessionReplayOptions);
}
#endif
XCTAssertFalse(options.enableTracing);
XCTAssertTrue(options.enableAppHangTracking);
Expand Down Expand Up @@ -778,6 +782,27 @@ - (void)testEnablePreWarmedAppStartTracking
[self testBooleanField:@"enablePreWarmedAppStartTracing" defaultValue:NO];
}

- (void)testSessionReplaySettingsInit
{
if (@available(iOS 16.0, tvOS 16.0, *)) {
SentryOptions *options = [self getValidOptions:@{
@"sessionReplayOptions" :
@ { @"replaysSessionSampleRate" : @2, @"replaysOnErrorSampleRate" : @4 }
}];
XCTAssertEqual(options.sessionReplayOptions.replaysSessionSampleRate, 2);
XCTAssertEqual(options.sessionReplayOptions.replaysOnErrorSampleRate, 4);
}
}

- (void)testSessionReplaySettingsDefaults
{
if (@available(iOS 16.0, tvOS 16.0, *)) {
SentryOptions *options = [self getValidOptions:@{ @"sessionReplayOptions" : @ {} }];
XCTAssertEqual(options.sessionReplayOptions.replaysSessionSampleRate, 0);
XCTAssertEqual(options.sessionReplayOptions.replaysOnErrorSampleRate, 0);
}
}

#endif

#if SENTRY_HAS_METRIC_KIT
Expand Down
1 change: 1 addition & 0 deletions Tests/SentryTests/SentryTests-Bridging-Header.h
Original file line number Diff line number Diff line change
Expand Up @@ -220,6 +220,7 @@
#import "SentryPerformanceTracker+Testing.h"
#import "SentryPropagationContext.h"
#import "SentryReplayEvent.h"
#import "SentryReplayOptions.h"
#import "SentryReplayRecording.h"
#import "SentrySampleDecision+Private.h"
#import "SentrySpanOperations.h"
Expand Down
Loading