Skip to content

Commit

Permalink
feat: add OTEL_SAMPLING_PROBABILITY env var (#1069)
Browse files Browse the repository at this point in the history
Allows user to configure tracer's sampling probability via an env var.

Uses parentOrElse sampler with a probability sampler delegate when setting OTEL_SAMPLING_PROBABILITY

Defaults to AlwaysOnSampler when unset or set to 1.

Signed-off-by: Naseem <naseem@transit.app>
  • Loading branch information
Naseem committed Jul 24, 2020
1 parent 827cca3 commit 0f0c08a
Show file tree
Hide file tree
Showing 3 changed files with 107 additions and 2 deletions.
7 changes: 7 additions & 0 deletions packages/opentelemetry-tracing/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,13 @@ span.setAttribute('key', 'value');
span.end();
```

## Config

Tracing configuration is a merge of user supplied configuration with both the default
configuration as specified in [config.ts](./src/config.ts) and an
environmentally configurable (via `OTEL_SAMPLING_PROBABILITY`) probability
sampler delegate of a [ParentOrElse](https://github.com/open-telemetry/opentelemetry-specification/blob/master/specification/trace/sdk.md#parentorelse) sampler.

## Example

See [examples/basic-tracer-node](https://github.com/open-telemetry/opentelemetry-js/tree/master/examples/basic-tracer-node) for an end-to-end example, including exporting created spans.
Expand Down
20 changes: 19 additions & 1 deletion packages/opentelemetry-tracing/src/utility.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,14 +21,32 @@ import {
DEFAULT_MAX_LINKS_PER_SPAN,
} from './config';
import { TracerConfig } from './types';
import {
ParentOrElseSampler,
ProbabilitySampler,
getEnv,
} from '@opentelemetry/core';

/**
* Function to merge Default configuration (as specified in './config') with
* user provided configurations.
*/
export function mergeConfig(userConfig: TracerConfig) {
const traceParams = userConfig.traceParams;
const target = Object.assign({}, DEFAULT_CONFIG, userConfig);
const otelSamplingProbability = getEnv().OTEL_SAMPLING_PROBABILITY;

const target = Object.assign(
DEFAULT_CONFIG,
// use default AlwaysOnSampler if otelSamplingProbability is 1
otelSamplingProbability !== undefined && otelSamplingProbability < 1
? {
sampler: new ParentOrElseSampler(
new ProbabilitySampler(otelSamplingProbability)
),
}
: {},
userConfig
);

// the user-provided value will be used to extend the default value.
if (traceParams) {
Expand Down
82 changes: 81 additions & 1 deletion packages/opentelemetry-tracing/test/Tracer.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,12 @@
*/

import * as assert from 'assert';
import { NoopSpan, Sampler, SamplingDecision } from '@opentelemetry/api';
import {
NoopSpan,
Sampler,
SamplingDecision,
TraceFlags,
} from '@opentelemetry/api';
import { BasicTracerProvider, Tracer, Span } from '../src';
import {
InstrumentationLibrary,
Expand All @@ -40,6 +45,12 @@ describe('Tracer', () => {
}
}

afterEach(() => {
if (typeof process !== 'undefined' && process.release.name === 'node') {
delete process.env.OTEL_SAMPLING_PROBABILITY;
}
});

it('should create a Tracer instance', () => {
const tracer = new Tracer(
{ name: 'default', version: '0.0.1' },
Expand All @@ -49,6 +60,15 @@ describe('Tracer', () => {
assert.ok(tracer instanceof Tracer);
});

it('should use an AlwaysOnSampler by default', () => {
const tracer = new Tracer(
{ name: 'default', version: '0.0.1' },
{},
tracerProvider
);
assert.strictEqual(tracer['_sampler'].toString(), 'AlwaysOnSampler');
});

it('should respect NO_RECORD sampling result', () => {
const tracer = new Tracer(
{ name: 'default', version: '0.0.1' },
Expand Down Expand Up @@ -94,4 +114,64 @@ describe('Tracer', () => {
assert.strictEqual(lib.name, 'default');
assert.strictEqual(lib.version, '0.0.1');
});

if (typeof process !== 'undefined' && process.release.name === 'node') {
it('should sample a trace when OTEL_SAMPLING_PROBABILITY is invalid', () => {
process.env.OTEL_SAMPLING_PROBABILITY = 'invalid value';
const tracer = new Tracer(
{ name: 'default', version: '0.0.1' },
{},
tracerProvider
);
const span = tracer.startSpan('my-span');
const context = span.context();
assert.strictEqual(context.traceFlags, TraceFlags.SAMPLED);
span.end();
});
}

if (typeof process !== 'undefined' && process.release.name === 'node') {
it('should sample a trace when OTEL_SAMPLING_PROBABILITY is greater than 1', () => {
process.env.OTEL_SAMPLING_PROBABILITY = '2';
const tracer = new Tracer(
{ name: 'default', version: '0.0.1' },
{},
tracerProvider
);
const span = tracer.startSpan('my-span');
const context = span.context();
assert.strictEqual(context.traceFlags, TraceFlags.SAMPLED);
span.end();
});
}

if (typeof process !== 'undefined' && process.release.name === 'node') {
it('should not sample a trace when OTEL_SAMPLING_PROBABILITY is 0', () => {
process.env.OTEL_SAMPLING_PROBABILITY = '0';
const tracer = new Tracer(
{ name: 'default', version: '0.0.1' },
{},
tracerProvider
);
const span = tracer.startSpan('my-span');
const context = span.context();
assert.strictEqual(context.traceFlags, TraceFlags.NONE);
span.end();
});
}

if (typeof process !== 'undefined' && process.release.name === 'node') {
it('should not sample a trace when OTEL_SAMPLING_PROBABILITY is less than 0', () => {
process.env.OTEL_SAMPLING_PROBABILITY = '-1';
const tracer = new Tracer(
{ name: 'default', version: '0.0.1' },
{},
tracerProvider
);
const span = tracer.startSpan('my-span');
const context = span.context();
assert.strictEqual(context.traceFlags, TraceFlags.NONE);
span.end();
});
}
});

0 comments on commit 0f0c08a

Please sign in to comment.