Skip to content

Commit

Permalink
feat: add ParentOrElseSampler
Browse files Browse the repository at this point in the history
Also renamed ALWAYS_SAMPLER and NEVER_SAMPLER to AlwaysOnSampler and
AlwaysOffSampler respectively.
  • Loading branch information
legendecas committed Jul 6, 2020
1 parent a557b04 commit 95272d4
Show file tree
Hide file tree
Showing 14 changed files with 320 additions and 46 deletions.
3 changes: 3 additions & 0 deletions packages/opentelemetry-core/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,9 @@ export * from './correlation-context/correlation-context';
export * from './correlation-context/propagation/HttpCorrelationContext';
export * from './platform';
export * from './trace/NoRecordingSpan';
export * from './trace/sampler/AlwaysOffSampler';
export * from './trace/sampler/AlwaysOnSampler';
export * from './trace/sampler/ParentOrElseSampler';
export * from './trace/sampler/ProbabilitySampler';
export * from './trace/spancontext-utils';
export * from './trace/TraceState';
Expand Down
30 changes: 30 additions & 0 deletions packages/opentelemetry-core/src/trace/sampler/AlwaysOffSampler.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
/*
* Copyright The OpenTelemetry Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

import { Sampler, SamplingDecision } from '@opentelemetry/api';

/** Sampler that samples no traces. */
export class AlwaysOffSampler implements Sampler {
shouldSample() {
return {
decision: SamplingDecision.NOT_RECORD,
};
}

toString(): string {
return `AlwaysOffSampler`;
}
}
30 changes: 30 additions & 0 deletions packages/opentelemetry-core/src/trace/sampler/AlwaysOnSampler.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
/*
* Copyright The OpenTelemetry Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

import { Sampler, SamplingDecision } from '@opentelemetry/api';

/** Sampler that samples all traces. */
export class AlwaysOnSampler implements Sampler {
shouldSample() {
return {
decision: SamplingDecision.RECORD_AND_SAMPLED,
};
}

toString(): string {
return `AlwaysOnSampler`;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
/*
* Copyright The OpenTelemetry Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

import {
Sampler,
SpanContext,
TraceFlags,
SamplingDecision,
SpanKind,
Attributes,
Link,
} from '@opentelemetry/api';

/** Sampler that samples a given fraction of traces. */
export class ParentOrElseSampler implements Sampler {
constructor(private _delegateSampler: Sampler) {}

shouldSample(
parentContext: SpanContext | undefined,
traceId: string,
spanName: string,
spanKind: SpanKind,
attributes: Attributes,
links: Link[]
) {
// Respect the parent sampling decision if there is one
if (parentContext && typeof parentContext.traceFlags !== 'undefined') {
return {
decision:
(TraceFlags.SAMPLED & parentContext.traceFlags) === TraceFlags.SAMPLED
? SamplingDecision.RECORD_AND_SAMPLED
: SamplingDecision.NOT_RECORD,
};
}
return this._delegateSampler.shouldSample(
parentContext,
traceId,
spanName,
spanKind,
attributes,
links
);
}

toString(): string {
return `ParentOrElse{${this._delegateSampler.toString()}}`;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,9 @@ export class ProbabilitySampler implements Sampler {
}

shouldSample(parentContext?: SpanContext) {
// Respect the parent sampling decision if there is one
// Respect the parent sampling decision if there is one.
// TODO(legendecas): add an option to ignore parent regarding to spec:
// https://github.com/open-telemetry/opentelemetry-specification/blob/master/specification/trace/sdk.md#probability
if (parentContext && typeof parentContext.traceFlags !== 'undefined') {
return {
decision:
Expand Down Expand Up @@ -56,6 +58,3 @@ export class ProbabilitySampler implements Sampler {
return probability >= 1 ? 1 : probability <= 0 ? 0 : probability;
}
}

export const ALWAYS_SAMPLER = new ProbabilitySampler(1);
export const NEVER_SAMPLER = new ProbabilitySampler(0);
28 changes: 28 additions & 0 deletions packages/opentelemetry-core/test/trace/AlwaysOffSampler.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
/*
* Copyright The OpenTelemetry Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import * as assert from 'assert';
import * as api from '@opentelemetry/api';
import { AlwaysOffSampler } from '../../src/trace/sampler/AlwaysOffSampler';

describe('AlwaysOffSampler', () => {
it('should return decision: api.SamplingDecision.NOT_RECORD for AlwaysOffSampler', () => {
const sampler = new AlwaysOffSampler();
assert.deepStrictEqual(sampler.shouldSample(), {
decision: api.SamplingDecision.NOT_RECORD,
});
assert.strictEqual(sampler.toString(), 'AlwaysOffSampler');
});
});
28 changes: 28 additions & 0 deletions packages/opentelemetry-core/test/trace/AlwaysOnSampler.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
/*
* Copyright The OpenTelemetry Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import * as assert from 'assert';
import * as api from '@opentelemetry/api';
import { AlwaysOnSampler } from '../../src/trace/sampler/AlwaysOnSampler';

describe('AlwaysOnSampler', () => {
it('should return api.SamplingDecision.RECORD_AND_SAMPLED for AlwaysOnSampler', () => {
const sampler = new AlwaysOnSampler();
assert.deepStrictEqual(sampler.shouldSample(), {
decision: api.SamplingDecision.RECORD_AND_SAMPLED,
});
assert.strictEqual(sampler.toString(), 'AlwaysOnSampler');
});
});
113 changes: 113 additions & 0 deletions packages/opentelemetry-core/test/trace/ParentOrElseSampler.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
/*
* Copyright The OpenTelemetry Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import * as assert from 'assert';
import * as api from '@opentelemetry/api';
import { AlwaysOnSampler } from '../../src/trace/sampler/AlwaysOnSampler';
import { ParentOrElseSampler } from '../../src/trace/sampler/ParentOrElseSampler';
import { TraceFlags, SpanKind } from '@opentelemetry/api';
import { AlwaysOffSampler } from '../../src/trace/sampler/AlwaysOffSampler';

const traceId = 'd4cda95b652f4a1592b449d5929fda1b';
const spanId = '6e0c63257de34c92';
const spanName = 'foobar';

describe('ParentOrElseSampler', () => {
it('should return api.SamplingDecision.NOT_RECORD for not sampled parent while composited with AlwaysOnSampler', () => {
const sampler = new ParentOrElseSampler(new AlwaysOnSampler());
assert.strictEqual(sampler.toString(), 'ParentOrElse{AlwaysOnSampler}');

const spanContext = {
traceId,
spanId,
traceFlags: TraceFlags.NONE,
};
assert.deepStrictEqual(
sampler.shouldSample(
spanContext,
traceId,
spanName,
SpanKind.CLIENT,
{},
[]
),
{
decision: api.SamplingDecision.NOT_RECORD,
}
);
});

it('should return api.SamplingDecision.RECORD_AND_SAMPLED while composited with AlwaysOnSampler', () => {
const sampler = new ParentOrElseSampler(new AlwaysOnSampler());
assert.strictEqual(sampler.toString(), 'ParentOrElse{AlwaysOnSampler}');

assert.deepStrictEqual(
sampler.shouldSample(
undefined,
traceId,
spanName,
SpanKind.CLIENT,
{},
[]
),
{
decision: api.SamplingDecision.RECORD_AND_SAMPLED,
}
);
});

it('should return api.SamplingDecision.RECORD_AND_SAMPLED for sampled parent while composited with AlwaysOffSampler', () => {
const sampler = new ParentOrElseSampler(new AlwaysOffSampler());
assert.strictEqual(sampler.toString(), 'ParentOrElse{AlwaysOffSampler}');

const spanContext = {
traceId,
spanId,
traceFlags: TraceFlags.NONE,
};
assert.deepStrictEqual(
sampler.shouldSample(
spanContext,
traceId,
spanName,
SpanKind.CLIENT,
{},
[]
),
{
decision: api.SamplingDecision.RECORD_AND_SAMPLED,
}
);
});

it('should return api.SamplingDecision.RECORD_AND_SAMPLED while composited with AlwaysOffSampler', () => {
const sampler = new ParentOrElseSampler(new AlwaysOffSampler());
assert.strictEqual(sampler.toString(), 'ParentOrElse{AlwaysOffSampler}');

assert.deepStrictEqual(
sampler.shouldSample(
undefined,
traceId,
spanName,
SpanKind.CLIENT,
{},
[]
),
{
decision: api.SamplingDecision.NOT_RECORD,
}
);
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,7 @@

import * as assert from 'assert';
import * as api from '@opentelemetry/api';
import {
ProbabilitySampler,
ALWAYS_SAMPLER,
NEVER_SAMPLER,
} from '../../src/trace/sampler/ProbabilitySampler';
import { ProbabilitySampler } from '../../src/trace/sampler/ProbabilitySampler';

describe('ProbabilitySampler', () => {
it('should return a always sampler for 1', () => {
Expand Down Expand Up @@ -66,20 +62,6 @@ describe('ProbabilitySampler', () => {
});
});

it('should return api.SamplingDecision.RECORD_AND_SAMPLED for ALWAYS_SAMPLER', () => {
assert.deepStrictEqual(ALWAYS_SAMPLER.shouldSample(), {
decision: api.SamplingDecision.RECORD_AND_SAMPLED,
});
assert.strictEqual(ALWAYS_SAMPLER.toString(), 'ProbabilitySampler{1}');
});

it('should return decision: api.SamplingDecision.NOT_RECORD for NEVER_SAMPLER', () => {
assert.deepStrictEqual(NEVER_SAMPLER.shouldSample(), {
decision: api.SamplingDecision.NOT_RECORD,
});
assert.strictEqual(NEVER_SAMPLER.toString(), 'ProbabilitySampler{0}');
});

it('should handle NaN', () => {
const sampler = new ProbabilitySampler(NaN);
assert.deepStrictEqual(sampler.shouldSample(), {
Expand Down
Loading

0 comments on commit 95272d4

Please sign in to comment.