Skip to content

Commit

Permalink
add tracessampler option; not yet tested
Browse files Browse the repository at this point in the history
  • Loading branch information
lobsterkatie committed Aug 14, 2020
1 parent a0c7221 commit 9147013
Show file tree
Hide file tree
Showing 8 changed files with 96 additions and 24 deletions.
6 changes: 3 additions & 3 deletions packages/angular/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -76,9 +76,9 @@ components initializations.

#### Install

Registering a Trace Service is a 3 steps process.
Registering a Trace Service is a 3 step process.

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

```javascript
Expand Down Expand Up @@ -117,7 +117,7 @@ import { TraceService } from '@sentry/angular';
export class AppModule {}
```

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

```javascript
@NgModule({
Expand Down
9 changes: 6 additions & 3 deletions packages/gatsby/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ Register the package as a plugin in `gastby-config.js`:
}
```

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).
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).

## GitHub Actions

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

## Sentry Performance

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

```javascript
{
Expand All @@ -50,7 +50,10 @@ To enable Tracing support, supply the `tracesSampleRate` to the options and make
resolve: "@sentry/gatsby",
options: {
dsn: process.env.SENTRY_DSN, // this is the default
tracesSampleRate: 1, // this is just to test, you should lower this in production

// A rate of 1 means all traces will be sent, so it's good for testing.
// In production, you'll likely want to either choose a lower rate or use `tracesSampler` instead.
tracesSampleRate: 1,
}
},
// ...
Expand Down
7 changes: 4 additions & 3 deletions packages/gatsby/gatsby-browser.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
exports.onClientEntry = function(_, pluginParams) {
require.ensure(['@sentry/react'], function(require) {
const Sentry = require('@sentry/react');
const hasTracingEnabled = require('@sentry/utils').hasTracingEnabled;

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

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

if (tracesSampleRate) {
if (hasTracingEnabled()) {
if (BrowserTracingIntegration) {
integrations.push(new BrowserTracingIntegration());
} else if (TracingIntegration) {
Expand All @@ -34,7 +34,8 @@ exports.onClientEntry = function(_, pluginParams) {
// eslint-disable-next-line no-undef
dsn: __SENTRY_DSN__,
...pluginParams,
tracesSampleRate,
tracesSampleRate: pluginParams.tracesSampleRate,
tracesSampler: pluginParams.tracesSampler,
integrations,
});

Expand Down
68 changes: 56 additions & 12 deletions packages/tracing/src/hubextensions.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import { getMainCarrier, Hub } from '@sentry/hub';
import { TransactionContext } from '@sentry/types';
import { SampleContext, TransactionContext } from '@sentry/types';

import { IdleTransaction } from './idletransaction';
import { Transaction } from './transaction';
import { hasTracingEnabled, logger } from '@sentry/utils';

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

/**
* Use RNG to generate sampling decision, which all child spans inherit.
* Use sample rate (given in options as either a constant or ) along with a random number generator to make a sampling
* decision, which all child spans and child transactions inherit.
*
* Sample rate is set in SDK config, either as a constant (`tracesSampleRate`) or a function to compute the rate
* (`tracesSampler`).
*
* Called every time a transaction is created. Only transactions which emerge with sampled === true will be sent to
* Sentry.
*
* Mutates the given Transaction object and then returns the mutated object.
*/
function sample<T extends Transaction>(hub: Hub, transaction: T): T {
// nothing to do if tracing is disabled
if (!hasTracingEnabled(hub)) {
transaction.sampled = false;
return transaction;
}

logger.log('Tracing enabled');

const client = hub.getClient();
const options = (client && client.getOptions()) || {};

// we have to test for a pre-existsing sampling decision, in case this transaction is a child transaction and has
// inherited its parent's decision
if (transaction.sampled === undefined) {
const sampleRate = (client && client.getOptions().tracesSampleRate) || 0;
// if true = we want to have the transaction
// if false = we don't want to have it
// Math.random (inclusive of 0, but not 1)
let sampleRate;

// prefer the hook
if (options.tracesSampler) {
// TODO (kmclb) build context object
const sampleContext: SampleContext = {};
sampleRate = options.tracesSampler(sampleContext);
}
// we would have bailed at the beginning if neither `tracesSampler` nor `tracesSampleRate` were defined, so if the
// former isn't, the latter must be
else {
sampleRate = options.tracesSampleRate;
}

// if the function returned either 0 or null, it's a sign the transaction should be dropped
if (!sampleRate) {
logger.log('Discarding trace because tracesSampler returned 0 or null');
transaction.sampled = false;
return transaction;
}

// now we roll the dice (Math.random is inclusive of 0, but not of 1)
transaction.sampled = Math.random() < sampleRate;
}

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

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

return transaction;
}

Expand Down
2 changes: 1 addition & 1 deletion packages/types/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ export { Span, SpanContext } from './span';
export { StackFrame } from './stackframe';
export { Stacktrace } from './stacktrace';
export { Status } from './status';
export { Transaction, TransactionContext } from './transaction';
export { SampleContext, Transaction, TransactionContext } from './transaction';
export { Thread } from './thread';
export { Transport, TransportOptions, TransportClass } from './transport';
export { User } from './user';
Expand Down
4 changes: 4 additions & 0 deletions packages/types/src/options.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { Event, EventHint } from './event';
import { Integration } from './integration';
import { LogLevel } from './loglevel';
import { Transport, TransportClass, TransportOptions } from './transport';
import { SampleContext } from './transaction';

/** Base configuration options for every SDK. */
export interface Options {
Expand Down Expand Up @@ -88,6 +89,9 @@ export interface Options {
*/
tracesSampleRate?: number;

/** Function to compute tracing sample rate dynamically and filter unwanted traces */
tracesSampler?(traceContext: SampleContext): number | null;

/** Attaches stacktraces to pure capture message / log integrations */
attachStacktrace?: boolean;

Expand Down
10 changes: 9 additions & 1 deletion packages/types/src/transaction.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { Span, SpanContext } from './span';

/**
* Interface holding Transaction specific properties
* Interface holding Transaction-specific properties
*/
export interface TransactionContext extends SpanContext {
name: string;
Expand Down Expand Up @@ -48,3 +48,11 @@ export interface Transaction extends TransactionContext, Span {
*/
setName(name: string): void;
}

/**
* The data passed to the `tracesSampler` function, which forms the basis for whatever decisions it might make.
*/
export interface SampleContext {
[key: string]: string;
// TODO (kmclb) fill this out
}
14 changes: 13 additions & 1 deletion packages/utils/src/misc.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/* eslint-disable @typescript-eslint/no-explicit-any */
import { Event, Integration, StackFrame, WrappedFunction } from '@sentry/types';
import { Event, Hub, Integration, StackFrame, WrappedFunction } from '@sentry/types';

import { isString } from './is';
import { snipLine } from './string';
Expand Down Expand Up @@ -510,3 +510,15 @@ export function addContextToFrame(lines: string[], frame: StackFrame, linesOfCon
.slice(Math.min(sourceLine + 1, maxLines), sourceLine + 1 + linesOfContext)
.map((line: string) => snipLine(line, 0));
}

/**
* Determines if tracing is currently enabled.
*
* Tracing is enabled when at least one of `tracesSampleRate` and `tracesSampler` is defined in the SDK config.
*/
export function hasTracingEnabled(hub: Hub): boolean {
const client = hub.getClient();
const options = (client && client.getOptions()) || {};

return !!options.tracesSampleRate || !!options.tracesSampler;
}

0 comments on commit 9147013

Please sign in to comment.