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: Add sampling configuration for profiling #2004

Merged
merged 25 commits into from
Jul 27, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
ee182cc
Add new public API and documentation
indragiek Jul 19, 2022
3778216
Implement profilesSampleRate and profilesSampler
indragiek Jul 19, 2022
1f715c9
Profiles sampling logic
indragiek Jul 22, 2022
79fa056
Update docs
indragiek Jul 22, 2022
4957475
Make tracesSamplerDecision a parameter of sample:
indragiek Jul 23, 2022
1d9bbde
sampler -> tracesSampler
indragiek Jul 23, 2022
87dc145
Remove unused SentryTracer initializer
indragiek Jul 23, 2022
a665cc0
Pass through the ProfilesSamplerDecision
indragiek Jul 23, 2022
7c87766
Put the init method back
indragiek Jul 25, 2022
4670155
Fix test build
indragiek Jul 25, 2022
2f1988c
Only create SentryProfilesSampler if profiling is enabled
indragiek Jul 25, 2022
a23d406
Fix broken test
indragiek Jul 25, 2022
6b9dbf6
New tests to validate profile sampling
indragiek Jul 25, 2022
78cd14c
Make sure enableProfiling still works
indragiek Jul 25, 2022
c0f2f1b
Avoid unnecessary indirection
indragiek Jul 25, 2022
fa6431c
Add tests for enableProfiling
indragiek Jul 25, 2022
d74deed
Merge branch 'master' into indragiek/profiles-sample-rate
indragiek Jul 25, 2022
6f38459
Format code
getsentry-bot Jul 25, 2022
436ed07
Update CHANGELOG.md
indragiek Jul 25, 2022
135e6c1
Merge branch 'indragiek/profiles-sample-rate' of github.com:getsentry…
indragiek Jul 25, 2022
9f262f2
Fix compilation on non-iOS platforms
indragiek Jul 26, 2022
2fe7b01
Fix build
indragiek Jul 26, 2022
ba0d698
Format code
getsentry-bot Jul 26, 2022
38850f4
Fix test
indragiek Jul 26, 2022
0ddcebd
Merge branch 'indragiek/profiles-sample-rate' of github.com:getsentry…
indragiek Jul 26, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
# Changelog

## Unreleased

### Features

- Add sampling configuration for profiling (#2004)

## 7.22.0

### Features
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ extension Tracer {
options.tracesSampleRate = 1.0
options.enableFileIOTracking = true
options.enableCoreDataTracking = true
options.enableProfiling = true
options.profilesSampleRate = 1.0
options.attachScreenshot = true
options.enableUserInteractionTracing = true
}
Expand Down
2 changes: 1 addition & 1 deletion Samples/iOS-Swift/iOS-Swift/AppDelegate.swift
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
options.sessionTrackingIntervalMillis = 5_000
options.enableFileIOTracking = true
options.enableCoreDataTracking = true
options.enableProfiling = true
options.profilesSampleRate = 1.0
options.attachScreenshot = true

if !ProcessInfo.processInfo.arguments.contains("--io.sentry.test.benchmarking") {
Expand Down
2 changes: 1 addition & 1 deletion Samples/iOS-SwiftUI/iOS-SwiftUI/SwiftUIApp.swift
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ struct SwiftUIApp: App {
// Sampling 100% - In Production you probably want to adjust this
options.tracesSampleRate = 1.0
options.enableFileIOTracking = true
options.enableProfiling = true
options.profilesSampleRate = 1.0
options.enableUserInteractionTracing = true
}
}
Expand Down
2 changes: 1 addition & 1 deletion Samples/iOS15-SwiftUI/iOS15-SwiftUI/App.swift
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ struct SwiftUIApp: App {
// Sampling 100% - In Production you probably want to adjust this
options.tracesSampleRate = 1.0
options.enableFileIOTracking = true
options.enableProfiling = true
options.profilesSampleRate = 1.0
options.enableUserInteractionTracing = true
}
}
Expand Down
8 changes: 8 additions & 0 deletions Sentry.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@
objects = {

/* Begin PBXBuildFile section */
0356A570288B4612008BF593 /* SentryProfilesSampler.h in Headers */ = {isa = PBXBuildFile; fileRef = 0356A56E288B4612008BF593 /* SentryProfilesSampler.h */; };
0356A571288B4612008BF593 /* SentryProfilesSampler.m in Sources */ = {isa = PBXBuildFile; fileRef = 0356A56F288B4612008BF593 /* SentryProfilesSampler.m */; };
035E73C827D56757005EEB11 /* SentryBacktraceTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = 035E73C727D56757005EEB11 /* SentryBacktraceTests.mm */; };
035E73CA27D57398005EEB11 /* SentryThreadHandleTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = 035E73C927D57398005EEB11 /* SentryThreadHandleTests.mm */; };
035E73CC27D575B3005EEB11 /* SentrySamplingProfilerTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = 035E73CB27D575B3005EEB11 /* SentrySamplingProfilerTests.mm */; };
Expand Down Expand Up @@ -680,6 +682,8 @@
/* End PBXContainerItemProxy section */

/* Begin PBXFileReference section */
0356A56E288B4612008BF593 /* SentryProfilesSampler.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = SentryProfilesSampler.h; path = Sources/Sentry/SentryProfilesSampler.h; sourceTree = SOURCE_ROOT; };
0356A56F288B4612008BF593 /* SentryProfilesSampler.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; name = SentryProfilesSampler.m; path = Sources/Sentry/SentryProfilesSampler.m; sourceTree = SOURCE_ROOT; };
035E73C727D56757005EEB11 /* SentryBacktraceTests.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = SentryBacktraceTests.mm; sourceTree = "<group>"; };
035E73C927D57398005EEB11 /* SentryThreadHandleTests.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = SentryThreadHandleTests.mm; sourceTree = "<group>"; };
035E73CB27D575B3005EEB11 /* SentrySamplingProfilerTests.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = SentrySamplingProfilerTests.mm; sourceTree = "<group>"; };
Expand Down Expand Up @@ -2592,6 +2596,8 @@
03F84D1927DD414C008FE43F /* SentryThreadState.hpp */,
03BCC38927E1BF49003232C7 /* SentryTime.h */,
03BCC38B27E1C01A003232C7 /* SentryTime.mm */,
0356A56E288B4612008BF593 /* SentryProfilesSampler.h */,
0356A56F288B4612008BF593 /* SentryProfilesSampler.m */,
);
path = Profiling;
sourceTree = "<group>";
Expand Down Expand Up @@ -2812,6 +2818,7 @@
7BE3C77B2446111500A38442 /* SentryRateLimitParser.h in Headers */,
7D0637032382B34300B30749 /* SentryScope.h in Headers */,
03F84D2727DD414C008FE43F /* SentryMachLogging.hpp in Headers */,
0356A570288B4612008BF593 /* SentryProfilesSampler.h in Headers */,
63295AF51EF3C7DB002D4490 /* NSDictionary+SentrySanitize.h in Headers */,
8E4A037825F6F52100000D77 /* SentrySampleDecision.h in Headers */,
63FE717920DA4C1100CDBAE8 /* SentryCrashReportStore.h in Headers */,
Expand Down Expand Up @@ -3290,6 +3297,7 @@
D85852BA27EDDC5900C6D8AE /* SentryUIApplication.m in Sources */,
7B4E375F258231FC00059C93 /* SentryAttachment.m in Sources */,
636085141ED47BE600E8599E /* SentryFileManager.m in Sources */,
0356A571288B4612008BF593 /* SentryProfilesSampler.m in Sources */,
63FE710B20DA4C1000CDBAE8 /* SentryCrashMach.c in Sources */,
63FE707720DA4C1000CDBAE8 /* Container+SentryDeepSearch.m in Sources */,
63FE71A020DA4C1100CDBAE8 /* SentryCrashInstallation.m in Sources */,
Expand Down
36 changes: 35 additions & 1 deletion Sources/Sentry/Public/SentryOptions.h
Original file line number Diff line number Diff line change
Expand Up @@ -308,11 +308,45 @@ NS_SWIFT_NAME(Options)

#if SENTRY_TARGET_PROFILING_SUPPORTED
/**
* This feature is experimental. Profiling is not supported on watchOS or tvOS.
*
* Indicates the percentage profiles being sampled out of the sampled transactions.
*
* The default is 0. The value needs to be >= 0.0 and <= 1.0. When setting a value out of range
* the SDK sets it to the default of 0.
*
* This property is dependent on `tracesSampleRate` -- if `tracesSampleRate` is 0 (default),
* no profiles will be collected no matter what this property is set to. This property is
* used to undersample profiles *relative to* `tracesSampleRate`.
*/
@property (nullable, nonatomic, strong) NSNumber *profilesSampleRate;

/**
* This feature is experimental. Profiling is not supported on watchOS or tvOS.
*
* A callback to a user defined profiles sampler function. This is similar to setting
* `profilesSampleRate`, but instead of a static value, the callback function will be called to
* determine the sample rate.
*/
@property (nullable, nonatomic) SentryTracesSamplerCallback profilesSampler;

/**
* If profiling should be enabled or not. Returns YES if either a profilesSampleRate > 0 and
* <=1 or a profilesSampler is set otherwise NO.
*/
@property (nonatomic, assign, readonly) BOOL isProfilingEnabled;

/**
* DEPRECATED: Use `profilesSampleRate` instead. Setting `enableProfiling` to YES is the equivalent
* of setting `profilesSampleRate` to `1.0`. If `profilesSampleRate` is set, it will take precedence
* over this setting.
*
* Whether to enable the sampling profiler. Default is NO.
* @note This is a beta feature that is currently not available to all Sentry customers. This
* feature is not supported on watchOS or tvOS.
*/
@property (nonatomic, assign) BOOL enableProfiling;
@property (nonatomic, assign) BOOL enableProfiling DEPRECATED_MSG_ATTRIBUTE(
"This property will be removed in a future version of the SDK");
#endif

/**
Expand Down
23 changes: 19 additions & 4 deletions Sources/Sentry/SentryHub.m
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
#import "SentryFileManager.h"
#import "SentryId.h"
#import "SentryLog.h"
#import "SentryProfilesSampler.h"
#import "SentrySDK+Private.h"
#import "SentrySamplingContext.h"
#import "SentryScope.h"
Expand All @@ -27,7 +28,8 @@
@property (nullable, nonatomic, strong) SentryClient *client;
@property (nullable, nonatomic, strong) SentryScope *scope;
@property (nonatomic, strong) SentryCrashWrapper *crashWrapper;
@property (nonatomic, strong) SentryTracesSampler *sampler;
@property (nonatomic, strong) SentryTracesSampler *tracesSampler;
@property (nonatomic, strong) SentryProfilesSampler *profilesSampler;
@property (nonatomic, strong) id<SentryCurrentDateProvider> currentDateProvider;

@end
Expand All @@ -45,7 +47,12 @@ - (instancetype)initWithClient:(nullable SentryClient *)client
_sessionLock = [[NSObject alloc] init];
_installedIntegrations = [[NSMutableArray alloc] init];
_crashWrapper = [SentryCrashWrapper sharedInstance];
_sampler = [[SentryTracesSampler alloc] initWithOptions:client.options];
_tracesSampler = [[SentryTracesSampler alloc] initWithOptions:client.options];
#if SENTRY_TARGET_PROFILING_SUPPORTED
if (client.options.isProfilingEnabled) {
_profilesSampler = [[SentryProfilesSampler alloc] initWithOptions:client.options];
}
#endif
_currentDateProvider = [SentryDefaultCurrentDateProvider sharedInstance];
}
return self;
Expand Down Expand Up @@ -341,12 +348,16 @@ - (SentryId *)captureEvent:(SentryEvent *)event
[[SentrySamplingContext alloc] initWithTransactionContext:transactionContext
customSamplingContext:customSamplingContext];

SentryTracesSamplerDecision *samplerDecision = [_sampler sample:samplingContext];
SentryTracesSamplerDecision *samplerDecision = [_tracesSampler sample:samplingContext];
transactionContext.sampled = samplerDecision.decision;
transactionContext.sampleRate = samplerDecision.sampleRate;

SentryProfilesSamplerDecision *profilesSamplerDecision =
[_profilesSampler sample:samplingContext tracesSamplerDecision:samplerDecision];

id<SentrySpan> tracer = [[SentryTracer alloc] initWithTransactionContext:transactionContext
hub:self
profilesSamplerDecision:profilesSamplerDecision
waitForChildren:waitForChildren];

if (bindToScope)
Expand All @@ -365,12 +376,16 @@ - (SentryTracer *)startTransactionWithContext:(SentryTransactionContext *)transa
[[SentrySamplingContext alloc] initWithTransactionContext:transactionContext
customSamplingContext:customSamplingContext];

SentryTracesSamplerDecision *samplerDecision = [_sampler sample:samplingContext];
SentryTracesSamplerDecision *samplerDecision = [_tracesSampler sample:samplingContext];
transactionContext.sampled = samplerDecision.decision;
transactionContext.sampleRate = samplerDecision.sampleRate;

SentryProfilesSamplerDecision *profilesSamplerDecision =
[_profilesSampler sample:samplingContext tracesSamplerDecision:samplerDecision];

SentryTracer *tracer = [[SentryTracer alloc] initWithTransactionContext:transactionContext
hub:self
profilesSamplerDecision:profilesSamplerDecision
idleTimeout:idleTimeout
dispatchQueueWrapper:dispatchQueueWrapper];
if (bindToScope)
Expand Down
58 changes: 54 additions & 4 deletions Sources/Sentry/SentryOptions.m
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,10 @@
@property (nullable, nonatomic, copy, readonly) NSNumber *defaultSampleRate;
@property (nullable, nonatomic, copy, readonly) NSNumber *defaultTracesSampleRate;
@property (nonatomic, strong) NSMutableSet<NSString *> *disabledIntegrations;

#if SENTRY_TARGET_PROFILING_SUPPORTED
@property (nullable, nonatomic, copy, readonly) NSNumber *defaultProfilesSampleRate;
@property (nonatomic, assign) BOOL enableProfiling_DEPRECATED_TEST_ONLY;
#endif
@end

@implementation SentryOptions
Expand Down Expand Up @@ -68,11 +71,13 @@ - (instancetype)init
self.enableNetworkBreadcrumbs = YES;
_defaultTracesSampleRate = nil;
self.tracesSampleRate = _defaultTracesSampleRate;
self.enableCoreDataTracking = NO;
_enableSwizzling = YES;
#if SENTRY_TARGET_PROFILING_SUPPORTED
self.enableProfiling = NO;
_enableProfiling = NO;
_defaultProfilesSampleRate = nil;
self.profilesSampleRate = _defaultProfilesSampleRate;
#endif
self.enableCoreDataTracking = NO;
_enableSwizzling = YES;
self.sendClientReports = YES;

// Use the name of the bundle’s executable file as inAppInclude, so SentryInAppLogic
Expand Down Expand Up @@ -289,6 +294,14 @@ - (BOOL)validateOptions:(NSDictionary<NSString *, id> *)options
block:^(BOOL value) { self->_enableCoreDataTracking = value; }];

#if SENTRY_TARGET_PROFILING_SUPPORTED
if ([options[@"profilesSampleRate"] isKindOfClass:[NSNumber class]]) {
self.profilesSampleRate = options[@"profilesSampleRate"];
}

if ([self isBlock:options[@"profilesSampler"]]) {
self.profilesSampler = options[@"profilesSampler"];
}

[self setBool:options[@"enableProfiling"]
block:^(BOOL value) { self->_enableProfiling = value; }];
#endif
Expand Down Expand Up @@ -380,6 +393,43 @@ - (BOOL)isTracingEnabled
|| _tracesSampler != nil;
}

#if SENTRY_TARGET_PROFILING_SUPPORTED
- (BOOL)isValidProfilesSampleRate:(NSNumber *)profilesSampleRate
{
return [self isValidTracesSampleRate:profilesSampleRate];
}

- (void)setProfilesSampleRate:(NSNumber *)profilesSampleRate
{
if (profilesSampleRate == nil) {
_profilesSampleRate = nil;
} else if ([self isValidProfilesSampleRate:profilesSampleRate]) {
_profilesSampleRate = profilesSampleRate;
} else {
_profilesSampleRate = _defaultProfilesSampleRate;
}
}

- (BOOL)isProfilingEnabled
{
return (_profilesSampleRate != nil && [_profilesSampleRate doubleValue] > 0)
|| _profilesSampler != nil || _enableProfiling;
}

# pragma clang diagnostic push
# pragma clang diagnostic ignored "-Wdeprecated-declarations"
- (void)setEnableProfiling_DEPRECATED_TEST_ONLY:(BOOL)enableProfiling_DEPRECATED_TEST_ONLY
{
self.enableProfiling = enableProfiling_DEPRECATED_TEST_ONLY;
}

- (BOOL)enableProfiling_DEPRECATED_TEST_ONLY
{
return self.enableProfiling;
}
# pragma clang diagnostic pop
#endif

/**
* Checks if the passed in block is actually of type block. We can't check if the block matches a
* specific block without some complex objc runtime method calls and therefore we only check if its
Expand Down
49 changes: 49 additions & 0 deletions Sources/Sentry/SentryProfilesSampler.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
#import "SentryRandom.h"
#import "SentrySampleDecision.h"
#import <Foundation/Foundation.h>

NS_ASSUME_NONNULL_BEGIN

@class SentryOptions, SentrySamplingContext, SentryTracesSamplerDecision;

@interface SentryProfilesSamplerDecision : NSObject

@property (nonatomic, readonly) SentrySampleDecision decision;

@property (nullable, nonatomic, strong, readonly) NSNumber *sampleRate;

- (instancetype)initWithDecision:(SentrySampleDecision)decision
forSampleRate:(nullable NSNumber *)sampleRate;

@end

@interface SentryProfilesSampler : NSObject

/**
* A random number generator
*/
@property (nonatomic, strong) id<SentryRandom> random;

/**
* Init a ProfilesSampler with given options and random generator.
* @param options Sentry options with sampling configuration
* @param random A random number generator
*/
- (instancetype)initWithOptions:(SentryOptions *)options random:(id<SentryRandom>)random;

/**
* Init a ProfilesSampler with given options and a default Random generator.
* @param options Sentry options with sampling configuration
*/
- (instancetype)initWithOptions:(SentryOptions *)options;

/**
* Determines whether a profile should be sampled based on the context, options, and
* whether the trace corresponding to the profile was sampled.
*/
- (SentryProfilesSamplerDecision *)sample:(SentrySamplingContext *)context
tracesSamplerDecision:(SentryTracesSamplerDecision *)tracesSamplerDecision;

@end

NS_ASSUME_NONNULL_END