Skip to content

Commit

Permalink
feat: Add sampling configuration for profiling (#2004)
Browse files Browse the repository at this point in the history
Adds two new configuration options, profilesSampleRate and profilesSampler to mirror tracesSampleRate and tracesSampler, except for profiling data.

There are no breaking changes -- enableProfiling is now deprecated, but will continue to work for existing clients that use it (this is equivalent to setting profilesSampleRate to 1.0)
  • Loading branch information
indragiek committed Jul 27, 2022
1 parent e6c1fb8 commit 643eab8
Show file tree
Hide file tree
Showing 22 changed files with 546 additions and 55 deletions.
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

0 comments on commit 643eab8

Please sign in to comment.