Skip to content

Commit 9147013

Browse files
committed
add tracessampler option; not yet tested
1 parent a0c7221 commit 9147013

File tree

8 files changed

+96
-24
lines changed

8 files changed

+96
-24
lines changed

packages/angular/README.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -76,9 +76,9 @@ components initializations.
7676

7777
#### Install
7878

79-
Registering a Trace Service is a 3 steps process.
79+
Registering a Trace Service is a 3 step process.
8080

81-
1. Register and configure `@sentry/tracing` `BrowserTracing` integration, including custom Angular routing
81+
1. Register and configure the `BrowserTracing` integration from `@sentry/tracing`, including custom Angular routing
8282
instrumentation:
8383

8484
```javascript
@@ -117,7 +117,7 @@ import { TraceService } from '@sentry/angular';
117117
export class AppModule {}
118118
```
119119

120-
3. Either require the `TraceService` from inside `AppModule` or use `APP_INITIALIZER` to force instantiate Tracing.
120+
3. Either require the `TraceService` from inside `AppModule` or use `APP_INITIALIZER` to force-instantiate Tracing.
121121

122122
```javascript
123123
@NgModule({

packages/gatsby/README.md

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ Register the package as a plugin in `gastby-config.js`:
2424
}
2525
```
2626

27-
Options will be passed directly to `Sentry.init`. See all available options in [our docs](https://docs.sentry.io/error-reporting/configuration/?platform=javascript). The `environment` value defaults to `NODE_ENV` (or `development` if not set).
27+
Options will be passed directly to `Sentry.init`. See all available options in [our docs](https://docs.sentry.io/error-reporting/configuration/?platform=javascript). The `environment` value defaults to `NODE_ENV` (or `'development'` if `NODE_ENV` is not set).
2828

2929
## GitHub Actions
3030

@@ -40,7 +40,7 @@ To automatically capture the `release` value on Vercel you will need to register
4040

4141
## Sentry Performance
4242

43-
To enable Tracing support, supply the `tracesSampleRate` to the options and make sure you have installed the `@sentry/tracing` package.
43+
To enable Tracing support, supply either `tracesSampleRate` or `tracesSampler` to the options and make sure you have installed the `@sentry/tracing` package.
4444

4545
```javascript
4646
{
@@ -50,7 +50,10 @@ To enable Tracing support, supply the `tracesSampleRate` to the options and make
5050
resolve: "@sentry/gatsby",
5151
options: {
5252
dsn: process.env.SENTRY_DSN, // this is the default
53-
tracesSampleRate: 1, // this is just to test, you should lower this in production
53+
54+
// A rate of 1 means all traces will be sent, so it's good for testing.
55+
// In production, you'll likely want to either choose a lower rate or use `tracesSampler` instead.
56+
tracesSampleRate: 1,
5457
}
5558
},
5659
// ...

packages/gatsby/gatsby-browser.js

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
exports.onClientEntry = function(_, pluginParams) {
22
require.ensure(['@sentry/react'], function(require) {
33
const Sentry = require('@sentry/react');
4+
const hasTracingEnabled = require('@sentry/utils').hasTracingEnabled;
45

56
let TracingIntegration = undefined;
67
let BrowserTracingIntegration = undefined;
@@ -16,10 +17,9 @@ exports.onClientEntry = function(_, pluginParams) {
1617
/* no-empty */
1718
}
1819

19-
const tracesSampleRate = pluginParams.tracesSampleRate !== undefined ? pluginParams.tracesSampleRate : 0;
2020
const integrations = [...(pluginParams.integrations || [])];
2121

22-
if (tracesSampleRate) {
22+
if (hasTracingEnabled()) {
2323
if (BrowserTracingIntegration) {
2424
integrations.push(new BrowserTracingIntegration());
2525
} else if (TracingIntegration) {
@@ -34,7 +34,8 @@ exports.onClientEntry = function(_, pluginParams) {
3434
// eslint-disable-next-line no-undef
3535
dsn: __SENTRY_DSN__,
3636
...pluginParams,
37-
tracesSampleRate,
37+
tracesSampleRate: pluginParams.tracesSampleRate,
38+
tracesSampler: pluginParams.tracesSampler,
3839
integrations,
3940
});
4041

packages/tracing/src/hubextensions.ts

Lines changed: 56 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
import { getMainCarrier, Hub } from '@sentry/hub';
2-
import { TransactionContext } from '@sentry/types';
2+
import { SampleContext, TransactionContext } from '@sentry/types';
33

44
import { IdleTransaction } from './idletransaction';
55
import { Transaction } from './transaction';
6+
import { hasTracingEnabled, logger } from '@sentry/utils';
67

78
/** Returns all trace headers that are currently on the top scope. */
89
function traceHeaders(this: Hub): { [key: string]: string } {
@@ -19,25 +20,68 @@ function traceHeaders(this: Hub): { [key: string]: string } {
1920
}
2021

2122
/**
22-
* Use RNG to generate sampling decision, which all child spans inherit.
23+
* Use sample rate (given in options as either a constant or ) along with a random number generator to make a sampling
24+
* decision, which all child spans and child transactions inherit.
25+
*
26+
* Sample rate is set in SDK config, either as a constant (`tracesSampleRate`) or a function to compute the rate
27+
* (`tracesSampler`).
28+
*
29+
* Called every time a transaction is created. Only transactions which emerge with sampled === true will be sent to
30+
* Sentry.
31+
*
32+
* Mutates the given Transaction object and then returns the mutated object.
2333
*/
2434
function sample<T extends Transaction>(hub: Hub, transaction: T): T {
35+
// nothing to do if tracing is disabled
36+
if (!hasTracingEnabled(hub)) {
37+
transaction.sampled = false;
38+
return transaction;
39+
}
40+
41+
logger.log('Tracing enabled');
42+
2543
const client = hub.getClient();
44+
const options = (client && client.getOptions()) || {};
45+
46+
// we have to test for a pre-existsing sampling decision, in case this transaction is a child transaction and has
47+
// inherited its parent's decision
2648
if (transaction.sampled === undefined) {
27-
const sampleRate = (client && client.getOptions().tracesSampleRate) || 0;
28-
// if true = we want to have the transaction
29-
// if false = we don't want to have it
30-
// Math.random (inclusive of 0, but not 1)
49+
let sampleRate;
50+
51+
// prefer the hook
52+
if (options.tracesSampler) {
53+
// TODO (kmclb) build context object
54+
const sampleContext: SampleContext = {};
55+
sampleRate = options.tracesSampler(sampleContext);
56+
}
57+
// we would have bailed at the beginning if neither `tracesSampler` nor `tracesSampleRate` were defined, so if the
58+
// former isn't, the latter must be
59+
else {
60+
sampleRate = options.tracesSampleRate;
61+
}
62+
63+
// if the function returned either 0 or null, it's a sign the transaction should be dropped
64+
if (!sampleRate) {
65+
logger.log('Discarding trace because tracesSampler returned 0 or null');
66+
transaction.sampled = false;
67+
return transaction;
68+
}
69+
70+
// now we roll the dice (Math.random is inclusive of 0, but not of 1)
3171
transaction.sampled = Math.random() < sampleRate;
32-
}
3372

34-
// We only want to create a span list if we sampled the transaction
35-
// If sampled == false, we will discard the span anyway, so we can save memory by not storing child spans
36-
if (transaction.sampled) {
37-
const experimentsOptions = (client && client.getOptions()._experiments) || {};
38-
transaction.initSpanRecorder(experimentsOptions.maxSpans as number);
73+
// if we're not going to keep it, we're done
74+
if (!transaction.sampled) {
75+
logger.log(`Discarding trace because it's not included in the random sample (sampling rate = ${sampleRate})`);
76+
return transaction;
77+
}
3978
}
4079

80+
// at this point we know we're keeping the transaction, whether because of an inherited decision or because it got
81+
// lucky with the dice roll
82+
const experimentsOptions = (client && client.getOptions()._experiments) || {};
83+
transaction.initSpanRecorder(experimentsOptions.maxSpans as number);
84+
4185
return transaction;
4286
}
4387

packages/types/src/index.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ export { Span, SpanContext } from './span';
2222
export { StackFrame } from './stackframe';
2323
export { Stacktrace } from './stacktrace';
2424
export { Status } from './status';
25-
export { Transaction, TransactionContext } from './transaction';
25+
export { SampleContext, Transaction, TransactionContext } from './transaction';
2626
export { Thread } from './thread';
2727
export { Transport, TransportOptions, TransportClass } from './transport';
2828
export { User } from './user';

packages/types/src/options.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import { Event, EventHint } from './event';
33
import { Integration } from './integration';
44
import { LogLevel } from './loglevel';
55
import { Transport, TransportClass, TransportOptions } from './transport';
6+
import { SampleContext } from './transaction';
67

78
/** Base configuration options for every SDK. */
89
export interface Options {
@@ -88,6 +89,9 @@ export interface Options {
8889
*/
8990
tracesSampleRate?: number;
9091

92+
/** Function to compute tracing sample rate dynamically and filter unwanted traces */
93+
tracesSampler?(traceContext: SampleContext): number | null;
94+
9195
/** Attaches stacktraces to pure capture message / log integrations */
9296
attachStacktrace?: boolean;
9397

packages/types/src/transaction.ts

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { Span, SpanContext } from './span';
22

33
/**
4-
* Interface holding Transaction specific properties
4+
* Interface holding Transaction-specific properties
55
*/
66
export interface TransactionContext extends SpanContext {
77
name: string;
@@ -48,3 +48,11 @@ export interface Transaction extends TransactionContext, Span {
4848
*/
4949
setName(name: string): void;
5050
}
51+
52+
/**
53+
* The data passed to the `tracesSampler` function, which forms the basis for whatever decisions it might make.
54+
*/
55+
export interface SampleContext {
56+
[key: string]: string;
57+
// TODO (kmclb) fill this out
58+
}

packages/utils/src/misc.ts

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/* eslint-disable @typescript-eslint/no-explicit-any */
2-
import { Event, Integration, StackFrame, WrappedFunction } from '@sentry/types';
2+
import { Event, Hub, Integration, StackFrame, WrappedFunction } from '@sentry/types';
33

44
import { isString } from './is';
55
import { snipLine } from './string';
@@ -510,3 +510,15 @@ export function addContextToFrame(lines: string[], frame: StackFrame, linesOfCon
510510
.slice(Math.min(sourceLine + 1, maxLines), sourceLine + 1 + linesOfContext)
511511
.map((line: string) => snipLine(line, 0));
512512
}
513+
514+
/**
515+
* Determines if tracing is currently enabled.
516+
*
517+
* Tracing is enabled when at least one of `tracesSampleRate` and `tracesSampler` is defined in the SDK config.
518+
*/
519+
export function hasTracingEnabled(hub: Hub): boolean {
520+
const client = hub.getClient();
521+
const options = (client && client.getOptions()) || {};
522+
523+
return !!options.tracesSampleRate || !!options.tracesSampler;
524+
}

0 commit comments

Comments
 (0)