Skip to content

Commit

Permalink
ref: Set sample rate to default if out of range
Browse files Browse the repository at this point in the history
Set sampleRate, tracesSampleRate and tracesSampler to default value when
a provided value is out of range.

Fixes GH-986
  • Loading branch information
philipphofmann committed Apr 22, 2021
1 parent 12d5b82 commit 79d9b45
Show file tree
Hide file tree
Showing 6 changed files with 153 additions and 71 deletions.
3 changes: 2 additions & 1 deletion Sources/Sentry/Public/SentryDefines.h
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,8 @@ typedef BOOL (^SentryShouldQueueEvent)(
*
* @param samplingContext context of the sampling.
*
* @return A sample rate between 0.0 and 1.0.
* @return A sample rate that is >= 0.0 and <= 1.0 or NIL if no sampling decision has been taken..
* When returning a value out of range the SDK uses the default of 0.
*/
typedef NSNumber *_Nullable (^SentryTracesSamplerCallback)(
SentrySamplingContext *_Nonnull samplingContext);
Expand Down
19 changes: 11 additions & 8 deletions Sources/Sentry/Public/SentryOptions.h
Original file line number Diff line number Diff line change
Expand Up @@ -103,8 +103,10 @@ NS_SWIFT_NAME(Options)
+ (NSArray<NSString *> *)defaultIntegrations;

/**
* Defines the sample rate of SentryClient, should be a float between 0.0
* and 1.0. valid settings are 0.0 - 1.0 and nil
* Indicates the percentage of events being sent to Sentry. Setting this to 0 or NIL discards all
* events, 1.0 sends all events, 0.01 collects 1% of all events. The default is 1. 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 1.0.
*/
@property (nullable, nonatomic, copy) NSNumber *sampleRate;

Expand Down Expand Up @@ -156,16 +158,17 @@ NS_SWIFT_NAME(Options)
@property (nonatomic, assign) BOOL sendDefaultPii;

/**
* Indicates the percentage of the tracing data that is collected.
* Setting this to 0 or NIL discards all trace data, 1.0 collects all trace data,
* 0.01 collects 1% of all trace data.
* Indicates the percentage of the tracing data that is collected. Setting this to 0 or NIL discards
* all trace data, 1.0 collects all trace data, 0.01 collects 1% of all trace data. 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.
*/
@property (nullable, nonatomic, strong) NSNumber *tracesSampleRate;

/**
* A callback to a user defined traces sampler function.
* Returning 0 or NIL discards all trace data, 1.0 collects all trace data,
* 0.01 collects 1% of all trace data.
* A callback to a user defined traces sampler function. Returning 0 or NIL discards all trace
* data, 1.0 collects all trace data, 0.01 collects 1% of all trace data. The sample rate needs to
* be >= 0.0 and <= 1.0 or NIL. When returning a value out of range the SDK uses the default of 0.
*/
@property (nullable, nonatomic) SentryTracesSamplerCallback tracesSampler;

Expand Down
41 changes: 36 additions & 5 deletions Sources/Sentry/SentryOptions.m
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,14 @@
#import "SentrySDK.h"
#import "SentrySdkInfo.h"

@interface
SentryOptions ()

@property (readonly, nonatomic, copy) NSNumber *defaultSampleRate;
@property (readonly, nonatomic, copy) NSNumber *defaultTracesSampleRate;

@end

@implementation SentryOptions

+ (NSArray<NSString *> *)defaultIntegrations
Expand All @@ -25,14 +33,16 @@ - (instancetype)init
self.maxBreadcrumbs = defaultMaxBreadcrumbs;
self.maxCacheItems = 30;
self.integrations = SentryOptions.defaultIntegrations;
self.sampleRate = @1;
_defaultSampleRate = @1;
self.sampleRate = _defaultSampleRate;
self.enableAutoSessionTracking = YES;
self.enableOutOfMemoryTracking = YES;
self.sessionTrackingIntervalMillis = [@30000 unsignedIntValue];
self.attachStacktrace = YES;
self.maxAttachmentSize = 20 * 1024 * 1024;
self.sendDefaultPii = NO;
self.tracesSampleRate = @0;
_defaultTracesSampleRate = @0;
self.tracesSampleRate = self.defaultTracesSampleRate;

// Use the name of the bundle’s executable file as inAppInclude, so SentryFrameInAppLogic
// marks frames coming from there as inApp. With this approach, the SDK marks public
Expand Down Expand Up @@ -163,7 +173,7 @@ - (void)validateOptions:(NSDictionary<NSString *, id> *)options
}

NSNumber *sampleRate = options[@"sampleRate"];
if (nil != sampleRate && [sampleRate floatValue] >= 0 && [sampleRate floatValue] <= 1.0) {
if (nil != sampleRate) {
self.sampleRate = sampleRate;
}

Expand Down Expand Up @@ -193,8 +203,7 @@ - (void)validateOptions:(NSDictionary<NSString *, id> *)options
}

NSNumber *tracesSampleRate = options[@"tracesSampleRate"];
if (nil != tracesSampleRate && [tracesSampleRate floatValue] >= 0 &&
[tracesSampleRate floatValue] <= 1.0) {
if (nil != tracesSampleRate) {
self.tracesSampleRate = tracesSampleRate;
}

Expand Down Expand Up @@ -230,4 +239,26 @@ - (void)addInAppExclude:(NSString *)inAppExclude
_inAppExcludes = [self.inAppExcludes arrayByAddingObject:inAppExclude];
}

- (void)setSampleRate:(NSNumber *)sampleRate
{
if (sampleRate == nil) {
_sampleRate = nil;
} else if ([sampleRate doubleValue] >= 0 && [sampleRate doubleValue] <= 1.0) {
_sampleRate = sampleRate;
} else {
_sampleRate = _defaultSampleRate;
}
}

- (void)setTracesSampleRate:(NSNumber *)tracesSampleRate
{
if (tracesSampleRate == nil) {
_tracesSampleRate = nil;
} else if ([tracesSampleRate doubleValue] >= 0 && [tracesSampleRate doubleValue] <= 1.0) {
_tracesSampleRate = tracesSampleRate;
} else {
_tracesSampleRate = _defaultTracesSampleRate;
}
}

@end
8 changes: 6 additions & 2 deletions Sources/Sentry/TracesSampler.m
Original file line number Diff line number Diff line change
Expand Up @@ -23,13 +23,17 @@ - (instancetype)initWithOptions:(SentryOptions *)options

- (SentrySampleDecision)sample:(SentrySamplingContext *)context
{
if (context.transactionContext.sampled != kSentrySampleDecisionUndecided)
if (context.transactionContext.sampled != kSentrySampleDecisionUndecided) {
return context.transactionContext.sampled;
}

if (_options.tracesSampler != nil) {
NSNumber *callbackDecision = _options.tracesSampler(context);
if (callbackDecision != nil)
return [self calcSample:callbackDecision.doubleValue];
if ([callbackDecision doubleValue] < 0 || [callbackDecision doubleValue] > 1.0) {
callbackDecision = @0;
}
return [self calcSample:callbackDecision.doubleValue];
}

if (context.transactionContext.parentSampled != kSentrySampleDecisionUndecided)
Expand Down
78 changes: 40 additions & 38 deletions Tests/SentryTests/SentryHubTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -242,55 +242,46 @@ class SentryHubTests: XCTestCase {
}

func testStartTransactionNotSamplingUsingSampleRate() {
let options = fixture.options
options.tracesSampleRate = 0.49

let hub = fixture.getSut(options)
Dynamic(hub).sampler.random = fixture.random

let span = hub.startTransaction(name: fixture.transactionName, operation: fixture.transactionOperation)

XCTAssertEqual(span.context.sampled, .no)
testSampler(expected: .no) { options in
options.tracesSampler = { _ in return 0.49 }
}
}

func testStartTransactionSamplingUsingSampleRate() {
let options = fixture.options
options.tracesSampleRate = 0.5

let hub = fixture.getSut()
Dynamic(hub).sampler.random = fixture.random

let span = hub.startTransaction(name: fixture.transactionName, operation: fixture.transactionOperation)

XCTAssertEqual(span.context.sampled, .yes)
testSampler(expected: .yes) { options in
options.tracesSampler = { _ in return 0.5 }
}
}

func testStartTransactionNotSamplingUsingTracesSampler() {
let options = fixture.options
options.tracesSampler = {(_: SamplingContext) -> NSNumber in
return 0.4
testSampler(expected: .no) { options in
options.tracesSampler = { _ in return 0.4 }
}

let hub = fixture.getSut()
Dynamic(hub).sampler.random = fixture.random

let span = hub.startTransaction(name: fixture.transactionName, operation: fixture.transactionOperation)

XCTAssertEqual(span.context.sampled, .no)
}

func testStartTransactionSamplingUsingTracesSampler() {
let options = fixture.options
options.tracesSampler = {(_: SamplingContext) -> NSNumber in
return 0.6
testSampler(expected: .yes) { options in
options.tracesSampler = { _ in return 0.6 }
}
}

func testStartTransaction_WhenSampleRateAndSamplerNil() {
testSampler(expected: SentrySampleDecision.no) { options in
options.tracesSampleRate = nil
options.tracesSampler = { _ in return nil }
}
}

func testStartTransaction_WhenTracesSamplerOutOfRange_TooBig() {
testSampler(expected: .no) { options in
options.tracesSampler = { _ in return 1.01 }
}
}

func testStartTransaction_WhenTracesSamplersOutOfRange_TooSmall() {
testSampler(expected: .no) { options in
options.tracesSampler = { _ in return -0.01 }
}

let hub = fixture.getSut()
Dynamic(hub).sampler.random = fixture.random

let span = hub.startTransaction(name: fixture.transactionName, operation: fixture.transactionOperation)

XCTAssertEqual(span.context.sampled, .yes)
}

func testCaptureMessageWithScope() {
Expand Down Expand Up @@ -692,4 +683,15 @@ class SentryHubTests: XCTestCase {
private func assertNoEnvelopesCaptured() {
XCTAssertEqual(0, fixture.client.capturedEnvelopes.count)
}

private func testSampler(expected: SentrySampleDecision, options: (Options) -> Void) {
options(fixture.options)

let hub = fixture.getSut()
Dynamic(hub).sampler.random = fixture.random

let span = hub.startTransaction(name: fixture.transactionName, operation: fixture.transactionOperation)

XCTAssertEqual(expected, span.context.sampled)
}
}
75 changes: 58 additions & 17 deletions Tests/SentryTests/SentryOptionsTest.m
Original file line number Diff line number Diff line change
Expand Up @@ -279,25 +279,49 @@ - (void)testDefaultIntegrations
@"Default integrations are not set correctly");
}

- (void)testSampleRateWithDict
{
NSNumber *sampleRate = @0.1;
SentryOptions *options = [self getValidOptions:@{ @"sampleRate" : sampleRate }];
XCTAssertEqual(sampleRate, options.sampleRate);
}

- (void)testSampleRate_SetToNil
{
SentryOptions *options = [[SentryOptions alloc] init];
options.sampleRate = nil;
XCTAssertNil(options.sampleRate);
}

- (void)testSampleRateLowerBound
{
SentryOptions *options = [[SentryOptions alloc] init];
options.sampleRate = @0.5;

NSNumber *sampleRateLowerBound = @0;
SentryOptions *options = [self getValidOptions:@{ @"sampleRate" : sampleRateLowerBound }];
options.sampleRate = sampleRateLowerBound;
XCTAssertEqual(sampleRateLowerBound, options.sampleRate);

options.sampleRate = @0.5;

NSNumber *sampleRateTooLow = @-0.01;
options = [self getValidOptions:@{ @"sampleRate" : sampleRateTooLow }];
options.sampleRate = sampleRateTooLow;
XCTAssertEqual(@1, options.sampleRate);
}

- (void)testSampleRateUpperBound
{
NSNumber *sampleRateUpperBound = @1;
SentryOptions *options = [self getValidOptions:@{ @"sampleRate" : sampleRateUpperBound }];
XCTAssertEqual(sampleRateUpperBound, options.sampleRate);
SentryOptions *options = [[SentryOptions alloc] init];
options.sampleRate = @0.5;

NSNumber *upperBound = @1;
options.sampleRate = upperBound;
XCTAssertEqual(upperBound, options.sampleRate);

options.sampleRate = @0.5;

NSNumber *sampleRateTooHigh = @1.01;
options = [self getValidOptions:@{ @"sampleRate" : sampleRateTooHigh }];
NSNumber *tooHigh = @1.01;
options.sampleRate = tooHigh;
XCTAssertEqual(@1, options.sampleRate);
}

Expand Down Expand Up @@ -490,25 +514,42 @@ - (void)testDefaultTracesSampleRate
XCTAssertEqual(options.tracesSampleRate.doubleValue, 0);
}

- (void)testTracesSampleRate_SetToNil
{
SentryOptions *options = [[SentryOptions alloc] init];
options.tracesSampleRate = nil;
XCTAssertNil(options.tracesSampleRate);
}

- (void)testTracesSampleRateLowerBound
{
NSNumber *sampleRateLowerBound = @0;
SentryOptions *options = [self getValidOptions:@{ @"tracesSampleRate" : sampleRateLowerBound }];
XCTAssertEqual(sampleRateLowerBound, options.tracesSampleRate);
SentryOptions *options = [[SentryOptions alloc] init];
options.tracesSampleRate = @0.5;

NSNumber *sampleRateTooLow = @-0.01;
options = [self getValidOptions:@{ @"tracesSampleRate" : sampleRateTooLow }];
NSNumber *lowerBound = @0;
options.tracesSampleRate = lowerBound;
XCTAssertEqual(lowerBound, options.tracesSampleRate);

options.tracesSampleRate = @0.5;

NSNumber *tooLow = @-0.01;
options.tracesSampleRate = tooLow;
XCTAssertEqual(@0, options.tracesSampleRate);
}

- (void)testTracesSampleRateUpperBound
{
NSNumber *sampleRateUpperBound = @1;
SentryOptions *options = [self getValidOptions:@{ @"tracesSampleRate" : sampleRateUpperBound }];
XCTAssertEqual(sampleRateUpperBound, options.tracesSampleRate);
SentryOptions *options = [[SentryOptions alloc] init];
options.tracesSampleRate = @0.5;

NSNumber *lowerBound = @1;
options.tracesSampleRate = lowerBound;
XCTAssertEqual(lowerBound, options.tracesSampleRate);

options.tracesSampleRate = @0.5;

NSNumber *sampleRateTooHigh = @1.01;
options = [self getValidOptions:@{ @"tracesSampleRate" : sampleRateTooHigh }];
NSNumber *tooLow = @1.01;
options.tracesSampleRate = tooLow;
XCTAssertEqual(@0, options.tracesSampleRate);
}

Expand Down

0 comments on commit 79d9b45

Please sign in to comment.