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: add OTEL_SAMPLING_PROBABILITY env var #1069

Merged
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.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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) {
dyladan marked this conversation as resolved.
Show resolved Hide resolved
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();
});
}
});