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(v8/core): Remove deprecated span.sampled #11274

Merged
merged 2 commits into from
Mar 26, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
54 changes: 17 additions & 37 deletions packages/core/src/tracing/sampling.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,8 @@
import type { Options, SamplingContext } from '@sentry/types';
import type { Options, SamplingContext, TransactionContext } from '@sentry/types';
import { isNaN, logger } from '@sentry/utils';

import { DEBUG_BUILD } from '../debug-build';
import { SEMANTIC_ATTRIBUTE_SENTRY_SAMPLE_RATE } from '../semanticAttributes';
import { hasTracingEnabled } from '../utils/hasTracingEnabled';
import { spanToJSON } from '../utils/spanUtils';
import type { Transaction } from './transaction';

/**
* Makes a sampling decision for the given transaction and stores it on the transaction.
Expand All @@ -16,50 +13,42 @@ import type { Transaction } from './transaction';
* This method muttes the given `transaction` and will set the `sampled` value on it.
* It returns the same transaction, for convenience.
*/
export function sampleTransaction<T extends Transaction>(
transaction: T,
export function sampleTransaction(
transactionContext: TransactionContext,
options: Pick<Options, 'tracesSampleRate' | 'tracesSampler' | 'enableTracing'>,
samplingContext: SamplingContext,
): T {
): [sampled: boolean, sampleRate?: number] {
// nothing to do if tracing is not enabled
if (!hasTracingEnabled(options)) {
// eslint-disable-next-line deprecation/deprecation
transaction.sampled = false;
return transaction;
return [false];
}

// if the user has forced a sampling decision by passing a `sampled` value in their transaction context, go with that
// eslint-disable-next-line deprecation/deprecation
if (transaction.sampled !== undefined) {
// eslint-disable-next-line deprecation/deprecation
transaction.setAttribute(SEMANTIC_ATTRIBUTE_SENTRY_SAMPLE_RATE, Number(transaction.sampled));
return transaction;
const transactionContextSampled = transactionContext.sampled;
// if the user has forced a sampling decision by passing a `sampled` value in
// their transaction context, go with that.
if (transactionContextSampled !== undefined) {
return [transactionContextSampled, Number(transactionContextSampled)];
}

// we would have bailed already if neither `tracesSampler` nor `tracesSampleRate` nor `enableTracing` were defined, so one of these should
// work; prefer the hook if so
let sampleRate;
if (typeof options.tracesSampler === 'function') {
sampleRate = options.tracesSampler(samplingContext);
transaction.setAttribute(SEMANTIC_ATTRIBUTE_SENTRY_SAMPLE_RATE, Number(sampleRate));
} else if (samplingContext.parentSampled !== undefined) {
sampleRate = samplingContext.parentSampled;
} else if (typeof options.tracesSampleRate !== 'undefined') {
sampleRate = options.tracesSampleRate;
transaction.setAttribute(SEMANTIC_ATTRIBUTE_SENTRY_SAMPLE_RATE, Number(sampleRate));
} else {
// When `enableTracing === true`, we use a sample rate of 100%
sampleRate = 1;
transaction.setAttribute(SEMANTIC_ATTRIBUTE_SENTRY_SAMPLE_RATE, sampleRate);
}

// Since this is coming from the user (or from a function provided by the user), who knows what we might get. (The
// only valid values are booleans or numbers between 0 and 1.)
if (!isValidSampleRate(sampleRate)) {
DEBUG_BUILD && logger.warn('[Tracing] Discarding transaction because of invalid sample rate.');
// eslint-disable-next-line deprecation/deprecation
transaction.sampled = false;
return transaction;
return [false];
}

// if the function returned 0 (or false), or if `tracesSampleRate` is 0, it's a sign the transaction should be dropped
Expand All @@ -72,40 +61,31 @@ export function sampleTransaction<T extends Transaction>(
: 'a negative sampling decision was inherited or tracesSampleRate is set to 0'
}`,
);
// eslint-disable-next-line deprecation/deprecation
transaction.sampled = false;
return transaction;
return [false, Number(sampleRate)];
}

// Now we roll the dice. Math.random is inclusive of 0, but not of 1, so strict < is safe here. In case sampleRate is
// a boolean, the < comparison will cause it to be automatically cast to 1 if it's true and 0 if it's false.
// eslint-disable-next-line deprecation/deprecation
transaction.sampled = Math.random() < (sampleRate as number | boolean);
const shouldSample = Math.random() < sampleRate;

// if we're not going to keep it, we're done
// eslint-disable-next-line deprecation/deprecation
if (!transaction.sampled) {
if (!shouldSample) {
DEBUG_BUILD &&
logger.log(
`[Tracing] Discarding transaction because it's not included in the random sample (sampling rate = ${Number(
sampleRate,
)})`,
);
return transaction;
return [false, Number(sampleRate)];
}

if (DEBUG_BUILD) {
const { op, description } = spanToJSON(transaction);
logger.log(`[Tracing] starting ${op} transaction - ${description}`);
}

return transaction;
return [true, Number(sampleRate)];
}

/**
* Checks the given sample rate to make sure it is valid type and value (a boolean, or a number between 0 and 1).
*/
function isValidSampleRate(rate: unknown): boolean {
function isValidSampleRate(rate: unknown): rate is number | boolean {
// we need to check NaN explicitly because it's of type 'number' and therefore wouldn't get caught by this typecheck
if (isNaN(rate) || !(typeof rate === 'number' || typeof rate === 'boolean')) {
DEBUG_BUILD &&
Expand Down
16 changes: 0 additions & 16 deletions packages/core/src/tracing/sentrySpan.ts
Original file line number Diff line number Diff line change
Expand Up @@ -97,22 +97,6 @@ export class SentrySpan implements Span {
// This rule conflicts with another eslint rule :(
/* eslint-disable @typescript-eslint/member-ordering */

/**
* Was this span chosen to be sent as part of the sample?
* @deprecated Use `isRecording()` instead.
*/
public get sampled(): boolean | undefined {
return this._sampled;
}

/**
* Was this span chosen to be sent as part of the sample?
* @deprecated You cannot update the sampling decision of a span after span creation.
*/
public set sampled(sampled: boolean | undefined) {
this._sampled = sampled;
}

/**
* Attributes for the span.
* @deprecated Use `spanToJSON(span).atttributes` instead.
Expand Down
13 changes: 10 additions & 3 deletions packages/core/src/tracing/trace.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import { getMainCarrier } from '../asyncContext';
import { getClient, getCurrentScope, getIsolationScope, withScope } from '../currentScopes';

import { getAsyncContextStrategy, getCurrentHub } from '../hub';
import { SEMANTIC_ATTRIBUTE_SENTRY_SAMPLE_RATE } from '../semanticAttributes';
import { handleCallbackErrors } from '../utils/handleCallbackErrors';
import { hasTracingEnabled } from '../utils/hasTracingEnabled';
import {
Expand Down Expand Up @@ -325,9 +326,7 @@ function _startTransaction(transactionContext: TransactionContext): Transaction
const client = getClient();
const options: Partial<ClientOptions> = (client && client.getOptions()) || {};

// eslint-disable-next-line deprecation/deprecation
let transaction = new Transaction(transactionContext, getCurrentHub());
transaction = sampleTransaction(transaction, options, {
const [sampled, sampleRate] = sampleTransaction(transactionContext, options, {
name: transactionContext.name,
parentSampled: transactionContext.parentSampled,
transactionContext,
Expand All @@ -337,8 +336,16 @@ function _startTransaction(transactionContext: TransactionContext): Transaction
...transactionContext.attributes,
},
});

// eslint-disable-next-line deprecation/deprecation
const transaction = new Transaction({ ...transactionContext, sampled }, getCurrentHub());
if (sampleRate !== undefined) {
transaction.setAttribute(SEMANTIC_ATTRIBUTE_SENTRY_SAMPLE_RATE, sampleRate);
}

if (client) {
client.emit('spanStart', transaction);
}

return transaction;
}
3 changes: 3 additions & 0 deletions packages/core/test/lib/tracing/trace.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -354,6 +354,7 @@ describe('startSpan', () => {
trace: {
data: {
'sentry.source': 'custom',
'sentry.sample_rate': 1,
'sentry.origin': 'manual',
},
parent_span_id: innerParentSpanId,
Expand Down Expand Up @@ -679,6 +680,7 @@ describe('startSpanManual', () => {
trace: {
data: {
'sentry.source': 'custom',
'sentry.sample_rate': 1,
'sentry.origin': 'manual',
},
parent_span_id: innerParentSpanId,
Expand Down Expand Up @@ -932,6 +934,7 @@ describe('startInactiveSpan', () => {
trace: {
data: {
'sentry.source': 'custom',
'sentry.sample_rate': 1,
'sentry.origin': 'manual',
},
parent_span_id: innerParentSpanId,
Expand Down
6 changes: 0 additions & 6 deletions packages/types/src/transaction.ts
Original file line number Diff line number Diff line change
Expand Up @@ -58,12 +58,6 @@ export interface TraceparentData {
* Transaction "Class", inherits Span only has `setName`
*/
export interface Transaction extends Omit<TransactionContext, 'name' | 'op' | 'spanId' | 'traceId'>, Span {
/**
* Was this transaction chosen to be sent as part of the sample?
* @deprecated Use `spanIsSampled(transaction)` instead.
*/
sampled?: boolean | undefined;

/**
* @inheritDoc
*/
Expand Down