From 5245015a334caccdb42c1a63ce585f38a68f66b6 Mon Sep 17 00:00:00 2001 From: Mayur Kale Date: Wed, 3 Jul 2019 11:05:58 -0700 Subject: [PATCH] =?UTF-8?q?=E2=9C=A8=20Add=20Sampler=20API=20(#48)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Add Sampler API * Keep Optional SpanContext only to make sampling decision * Add ProbabilitySampler * Add ProbabilitySampler * Make probability private and implement probability sampler * Add test - should sample based on the probability * Minor fix --- .../src/trace/sampler/ProbabilitySampler.ts | 33 +++++++++ .../test/trace/ProbabilitySampler.test.ts | 67 +++++++++++++++++++ packages/opentelemetry-types/src/index.ts | 1 + .../opentelemetry-types/src/trace/Sampler.ts | 39 +++++++++++ 4 files changed, 140 insertions(+) create mode 100644 packages/opentelemetry-core/src/trace/sampler/ProbabilitySampler.ts create mode 100644 packages/opentelemetry-core/test/trace/ProbabilitySampler.test.ts create mode 100644 packages/opentelemetry-types/src/trace/Sampler.ts diff --git a/packages/opentelemetry-core/src/trace/sampler/ProbabilitySampler.ts b/packages/opentelemetry-core/src/trace/sampler/ProbabilitySampler.ts new file mode 100644 index 00000000000..c23ac47756c --- /dev/null +++ b/packages/opentelemetry-core/src/trace/sampler/ProbabilitySampler.ts @@ -0,0 +1,33 @@ +/** + * Copyright 2019, 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 } from '@opentelemetry/types'; + +/** Sampler that samples a given fraction of traces. */ +export class ProbabilitySampler implements Sampler { + readonly description = 'ProbabilitySampler'; + + constructor(private readonly _probability: number = 1) {} + + shouldSample(parentContext?: SpanContext) { + if (this._probability >= 1.0) return true; + else if (this._probability <= 0) return false; + return Math.random() < this._probability; + } +} + +export const ALWAYS_SAMPLER = new ProbabilitySampler(1); +export const NEVER_SAMPLER = new ProbabilitySampler(0); diff --git a/packages/opentelemetry-core/test/trace/ProbabilitySampler.test.ts b/packages/opentelemetry-core/test/trace/ProbabilitySampler.test.ts new file mode 100644 index 00000000000..88bac0b22fb --- /dev/null +++ b/packages/opentelemetry-core/test/trace/ProbabilitySampler.test.ts @@ -0,0 +1,67 @@ +/** + * Copyright 2019, 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 { + ProbabilitySampler, + ALWAYS_SAMPLER, + NEVER_SAMPLER, +} from '../../src/trace/sampler/ProbabilitySampler'; + +describe('ProbabilitySampler', () => { + it('should return a always sampler for 1', () => { + const sampler = new ProbabilitySampler(); + assert.strictEqual( + sampler.shouldSample({ + traceId: 'd4cda95b652f4a1592b449d5929fda1b', + spanId: '6e0c63257de34c92', + }), + true + ); + }); + + it('should return a always sampler for >1', () => { + const sampler = new ProbabilitySampler(100); + assert.strictEqual(sampler.shouldSample(), true); + }); + + it('should return a never sampler for 0', () => { + const sampler = new ProbabilitySampler(0); + assert.strictEqual(sampler.shouldSample(), false); + }); + + it('should return a never sampler for <0', () => { + const sampler = new ProbabilitySampler(-1); + assert.strictEqual(sampler.shouldSample(), false); + }); + + it('should sample according to the probability', () => { + Math.random = () => 1 / 10; + const sampler = new ProbabilitySampler(0.2); + assert.strictEqual(sampler.shouldSample(), true); + + Math.random = () => 5 / 10; + assert.strictEqual(sampler.shouldSample(), false); + }); + + it('should return true for ALWAYS_SAMPLER', () => { + assert.strictEqual(ALWAYS_SAMPLER.shouldSample(), true); + }); + + it('should return false for NEVER_SAMPLER', () => { + assert.strictEqual(NEVER_SAMPLER.shouldSample(), false); + }); +}); diff --git a/packages/opentelemetry-types/src/index.ts b/packages/opentelemetry-types/src/index.ts index 7b6efd7584b..844195cb951 100644 --- a/packages/opentelemetry-types/src/index.ts +++ b/packages/opentelemetry-types/src/index.ts @@ -20,6 +20,7 @@ export * from './distributed_context/EntryValue'; export * from './resources/Resource'; export * from './trace/attributes'; export * from './trace/link'; +export * from './trace/Sampler'; export * from './trace/span'; export * from './trace/span_context'; export * from './trace/span_kind'; diff --git a/packages/opentelemetry-types/src/trace/Sampler.ts b/packages/opentelemetry-types/src/trace/Sampler.ts new file mode 100644 index 00000000000..cc9ca67362b --- /dev/null +++ b/packages/opentelemetry-types/src/trace/Sampler.ts @@ -0,0 +1,39 @@ +/** + * Copyright 2019, 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 { SpanContext } from './span_context'; + +/** + * This interface represent a sampler. Sampling is a mechanism to control the + * noise and overhead introduced by OpenTelemetry by reducing the number of + * samples of traces collected and sent to the backend. + */ +export interface Sampler { + /** + * A string that uniquely describes the sampling behavior of this instance. + */ + readonly description: string; + + /** + * Checks whether span needs to be created and tracked. + * + * TODO: Consider to add required arguments https://github.com/open-telemetry/opentelemetry-specification/blob/master/specification/sampling-api.md#shouldsample + * @param [parentContext] Parent span context. Typically taken from the wire. + * Can be null. + * @returns whether span should be sampled or not. + */ + shouldSample(parentContext?: SpanContext): boolean; +}