Skip to content

Commit

Permalink
enh: propagate sample seed in baggage (#2629)
Browse files Browse the repository at this point in the history
* initial seed propagation impl

* update

* improve naming

* update CHANGELOG
  • Loading branch information
buenaflor authored Feb 5, 2025
1 parent 8c9f280 commit 8f62960
Show file tree
Hide file tree
Showing 10 changed files with 67 additions and 18 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@

### Enhancements

- Propagate sample seed in baggage header ([#2629](https://github.com/getsentry/sentry-dart/pull/2629))
- Read more about the specs [here](https://develop.sentry.dev/sdk/telemetry/traces/#propagated-random-value)
- Finish and start new transaction when tapping same element again ([#2623](https://github.com/getsentry/sentry-dart/pull/2623))

### Fixes
Expand Down
18 changes: 16 additions & 2 deletions dart/lib/src/sentry_baggage.dart
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
import 'package:meta/meta.dart';
import 'scope.dart';
import 'protocol.dart';

import 'scope.dart';
import 'sentry_options.dart';

class SentryBaggage {
static const String _sampleRateKeyName = 'sentry-sample_rate';
static const String _sampleRandKeyName = 'sentry-sample_rand';

static const int _maxChars = 8192;
static const int _maxListMember = 64;

Expand Down Expand Up @@ -194,6 +195,10 @@ class SentryBaggage {
set(_sampleRateKeyName, value);
}

void setSampleRand(String value) {
set(_sampleRandKeyName, value);
}

void setSampled(String value) {
set('sentry-sampled', value);
}
Expand All @@ -207,6 +212,15 @@ class SentryBaggage {
return double.tryParse(sampleRate);
}

double? getSampleRand() {
final sampleRand = get(_sampleRandKeyName);
if (sampleRand == null) {
return null;
}

return double.tryParse(sampleRand);
}

void setReplayId(String value) => set('sentry-replay_id', value);

SentryId? getReplayId() {
Expand Down
8 changes: 7 additions & 1 deletion dart/lib/src/sentry_trace_context_header.dart
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import 'package:meta/meta.dart';

import 'protocol/sentry_id.dart';
import 'protocol/access_aware_map.dart';
import 'protocol/sentry_id.dart';
import 'sentry_baggage.dart';
import 'sentry_options.dart';

Expand All @@ -15,6 +15,7 @@ class SentryTraceContextHeader {
this.userSegment,
this.transaction,
this.sampleRate,
this.sampleRand,
this.sampled,
this.unknown,
this.replayId,
Expand All @@ -30,6 +31,7 @@ class SentryTraceContextHeader {
final String? userSegment;
final String? transaction;
final String? sampleRate;
final String? sampleRand;
final String? sampled;

@internal
Expand Down Expand Up @@ -102,6 +104,9 @@ class SentryTraceContextHeader {
if (sampleRate != null) {
baggage.setSampleRate(sampleRate!);
}
if (sampleRand != null) {
baggage.setSampleRand(sampleRand!);
}
if (sampled != null) {
baggage.setSampled(sampled!);
}
Expand All @@ -113,6 +118,7 @@ class SentryTraceContextHeader {

factory SentryTraceContextHeader.fromBaggage(SentryBaggage baggage) {
return SentryTraceContextHeader(
// TODO: implement and use proper get methods here
SentryId.fromId(baggage.get('sentry-trace_id').toString()),
baggage.get('sentry-public_key').toString(),
release: baggage.get('sentry-release'),
Expand Down
8 changes: 8 additions & 0 deletions dart/lib/src/sentry_tracer.dart
Original file line number Diff line number Diff line change
Expand Up @@ -385,6 +385,7 @@ class SentryTracer extends ISentrySpan {
transaction:
_isHighQualityTransactionName(transactionNameSource) ? name : null,
sampleRate: _sampleRateToString(_rootSpan.samplingDecision?.sampleRate),
sampleRand: _sampleRandToString(_rootSpan.samplingDecision?.sampleRand),
sampled: _rootSpan.samplingDecision?.sampled.toString(),
);

Expand All @@ -398,6 +399,13 @@ class SentryTracer extends ISentrySpan {
return sampleRate != null ? SampleRateFormat().format(sampleRate) : null;
}

String? _sampleRandToString(double? sampleRand) {
if (!isValidSampleRand(sampleRand)) {
return null;
}
return sampleRand != null ? SampleRateFormat().format(sampleRand) : null;
}

bool _isHighQualityTransactionName(SentryTransactionNameSource source) {
return source != SentryTransactionNameSource.url;
}
Expand Down
28 changes: 16 additions & 12 deletions dart/lib/src/sentry_traces_sampler.dart
Original file line number Diff line number Diff line change
Expand Up @@ -31,12 +31,9 @@ class SentryTracesSampler {
final tracesSampler = _options.tracesSampler;
if (tracesSampler != null) {
try {
final result = tracesSampler(samplingContext);
if (result != null) {
return SentryTracesSamplingDecision(
_sample(result),
sampleRate: result,
);
final sampleRate = tracesSampler(samplingContext);
if (sampleRate != null) {
return _makeSampleDecision(sampleRate);
}
} catch (exception, stackTrace) {
_options.logger(
Expand Down Expand Up @@ -64,10 +61,7 @@ class SentryTracesSampler {
double? optionsOrDefaultRate = optionsRate ?? defaultRate;

if (optionsOrDefaultRate != null) {
return SentryTracesSamplingDecision(
_sample(optionsOrDefaultRate),
sampleRate: optionsOrDefaultRate,
);
return _makeSampleDecision(optionsOrDefaultRate);
}

return SentryTracesSamplingDecision(false);
Expand All @@ -78,8 +72,18 @@ class SentryTracesSampler {
if (optionsRate == null || !tracesSamplingDecision.sampled) {
return false;
}
return _sample(optionsRate);
return _isSampled(optionsRate);
}

bool _sample(double result) => !(result < _random.nextDouble());
SentryTracesSamplingDecision _makeSampleDecision(double sampleRate) {
final sampleRand = _random.nextDouble();
final sampled = _isSampled(sampleRate, sampleRand: sampleRand);
return SentryTracesSamplingDecision(sampled,
sampleRate: sampleRate, sampleRand: sampleRand);
}

bool _isSampled(double sampleRate, {double? sampleRand}) {
final rand = sampleRand ?? _random.nextDouble();
return rand <= sampleRate;
}
}
2 changes: 2 additions & 0 deletions dart/lib/src/sentry_traces_sampling_decision.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,10 @@ class SentryTracesSamplingDecision {
SentryTracesSamplingDecision(
this.sampled, {
this.sampleRate,
this.sampleRand,
});

final bool sampled;
final double? sampleRate;
final double? sampleRand;
}
8 changes: 5 additions & 3 deletions dart/lib/src/sentry_transaction_context.dart
Original file line number Diff line number Diff line change
@@ -1,27 +1,27 @@
import 'package:meta/meta.dart';
import 'sentry_trace_origins.dart';

import 'protocol.dart';
import 'sentry_baggage.dart';
import 'sentry_trace_origins.dart';
import 'tracing.dart';

@immutable
class SentryTransactionContext extends SentrySpanContext {
final String name;
final SentryTracesSamplingDecision? parentSamplingDecision;
final SentryTransactionNameSource? transactionNameSource;
final SentryTracesSamplingDecision? samplingDecision;
final SentryTracesSamplingDecision? parentSamplingDecision;

SentryTransactionContext(
this.name,
String operation, {
super.description,
this.parentSamplingDecision,
super.traceId,
super.spanId,
super.parentSpanId,
this.transactionNameSource,
this.samplingDecision,
this.parentSamplingDecision,
super.origin,
}) : super(
operation: operation,
Expand All @@ -35,6 +35,7 @@ class SentryTransactionContext extends SentrySpanContext {
SentryBaggage? baggage,
}) {
final sampleRate = baggage?.getSampleRate();
final sampleRand = baggage?.getSampleRand();
return SentryTransactionContext(
name,
operation,
Expand All @@ -44,6 +45,7 @@ class SentryTransactionContext extends SentrySpanContext {
? SentryTracesSamplingDecision(
traceHeader.sampled!,
sampleRate: sampleRate,
sampleRand: sampleRand,
)
: null,
transactionNameSource:
Expand Down
7 changes: 7 additions & 0 deletions dart/lib/src/utils/tracing_utils.dart
Original file line number Diff line number Diff line change
Expand Up @@ -80,3 +80,10 @@ bool isValidSampleRate(double? sampleRate) {
}
return !sampleRate.isNaN && sampleRate >= 0.0 && sampleRate <= 1.0;
}

bool isValidSampleRand(double? sampleRand) {
if (sampleRand == null) {
return false;
}
return !sampleRand.isNaN && sampleRand >= 0.0 && sampleRand < 1.0;
}
2 changes: 2 additions & 0 deletions dart/test/protocol/sentry_baggage_header_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ void main() {
baggage.setUserSegment('userSegment');
baggage.setTransaction('transaction');
baggage.setSampleRate('1.0');
baggage.setSampleRand('0.4');
baggage.setSampled('false');
final replayId = SentryId.newId().toString();
baggage.setReplayId(replayId);
Expand All @@ -37,6 +38,7 @@ void main() {
'sentry-user_segment=userSegment,'
'sentry-transaction=transaction,'
'sentry-sample_rate=1.0,'
'sentry-sample_rand=0.4,'
'sentry-sampled=false,'
'sentry-replay_id=$replayId');
});
Expand Down
2 changes: 2 additions & 0 deletions dart/test/sentry_tracer_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -487,6 +487,7 @@ void main() {
SentryTracesSamplingDecision(
true,
sampleRate: 1.0,
sampleRand: 0.8,
);
final _context = SentryTransactionContext(
'name',
Expand All @@ -512,6 +513,7 @@ void main() {
expect(newBaggage.get('sentry-user_segment'), 'segment');
expect(newBaggage.get('sentry-transaction'), 'name');
expect(newBaggage.get('sentry-sample_rate'), '1');
expect(newBaggage.getSampleRand(), 0.8);
expect(newBaggage.get('sentry-sampled'), 'true');
});

Expand Down

0 comments on commit 8f62960

Please sign in to comment.