diff --git a/packages/opentelemetry-core/src/index.ts b/packages/opentelemetry-core/src/index.ts index e6bab81b1ec..d1bf17a580f 100644 --- a/packages/opentelemetry-core/src/index.ts +++ b/packages/opentelemetry-core/src/index.ts @@ -35,5 +35,6 @@ export * from './trace/sampler/ParentOrElseSampler'; export * from './trace/sampler/ProbabilitySampler'; export * from './trace/spancontext-utils'; export * from './trace/TraceState'; +export * from './trace/IdGenerator'; export * from './utils/url'; export * from './utils/wrap'; diff --git a/packages/opentelemetry-core/src/platform/browser/RandomIdGenerator.ts b/packages/opentelemetry-core/src/platform/browser/RandomIdGenerator.ts new file mode 100644 index 00000000000..7ab4ce1ea35 --- /dev/null +++ b/packages/opentelemetry-core/src/platform/browser/RandomIdGenerator.ts @@ -0,0 +1,64 @@ +/* + * 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 { IdGenerator } from '../../trace/IdGenerator'; + +type WindowWithMsCrypto = Window & { + msCrypto?: Crypto; +}; +const cryptoLib = window.crypto || (window as WindowWithMsCrypto).msCrypto; +const SPAN_ID_BYTES = 8; +const TRACE_ID_BYTES = 16; +const randomBytesArray = new Uint8Array(TRACE_ID_BYTES); + +export class RandomIdGenerator implements IdGenerator { + /** + * Returns a random 16-byte trace ID formatted/encoded as a 32 lowercase hex + * characters corresponding to 128 bits. + */ + generateTraceId(): string { + cryptoLib.getRandomValues(randomBytesArray); + return this.toHex(randomBytesArray.slice(0, TRACE_ID_BYTES)); + } + + /** + * Returns a random 8-byte span ID formatted/encoded as a 16 lowercase hex + * characters corresponding to 64 bits. + */ + generateSpanId(): string { + cryptoLib.getRandomValues(randomBytesArray); + return this.toHex(randomBytesArray.slice(0, SPAN_ID_BYTES)); + } + + /** + * Get the hex string representation of a byte array + * + * @param byteArray + */ + private toHex(byteArray: Uint8Array) { + const chars: number[] = new Array(byteArray.length * 2); + const alpha = 'a'.charCodeAt(0) - 10; + const digit = '0'.charCodeAt(0); + + let p = 0; + for (let i = 0; i < byteArray.length; i++) { + let nibble = (byteArray[i] >>> 4) & 0xf; + chars[p++] = nibble > 9 ? nibble + alpha : nibble + digit; + nibble = byteArray[i] & 0xf; + chars[p++] = nibble > 9 ? nibble + alpha : nibble + digit; + } + return String.fromCharCode.apply(null, chars); + } +} diff --git a/packages/opentelemetry-core/src/platform/browser/id.ts b/packages/opentelemetry-core/src/platform/browser/id.ts deleted file mode 100644 index 24f33972fd0..00000000000 --- a/packages/opentelemetry-core/src/platform/browser/id.ts +++ /dev/null @@ -1,56 +0,0 @@ -/* - * 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. - */ -declare type WindowWithMsCrypto = Window & { - msCrypto?: Crypto; -}; -const cryptoLib = window.crypto || (window as WindowWithMsCrypto).msCrypto; - -const SPAN_ID_BYTES = 8; -const TRACE_ID_BYTES = 16; -const randomBytesArray = new Uint8Array(TRACE_ID_BYTES); - -/** Returns a random 16-byte trace ID formatted as a 32-char hex string. */ -export function randomTraceId(): string { - cryptoLib.getRandomValues(randomBytesArray); - return toHex(randomBytesArray.slice(0, TRACE_ID_BYTES)); -} - -/** Returns a random 8-byte span ID formatted as a 16-char hex string. */ -export function randomSpanId(): string { - cryptoLib.getRandomValues(randomBytesArray); - return toHex(randomBytesArray.slice(0, SPAN_ID_BYTES)); -} - -/** - * Get the hex string representation of a byte array - * - * @param byteArray - */ -function toHex(byteArray: Uint8Array) { - const chars: number[] = new Array(byteArray.length * 2); - const alpha = 'a'.charCodeAt(0) - 10; - const digit = '0'.charCodeAt(0); - - let p = 0; - for (let i = 0; i < byteArray.length; i++) { - let nibble = (byteArray[i] >>> 4) & 0xf; - chars[p++] = nibble > 9 ? nibble + alpha : nibble + digit; - nibble = byteArray[i] & 0xf; - chars[p++] = nibble > 9 ? nibble + alpha : nibble + digit; - } - - return String.fromCharCode.apply(null, chars); -} diff --git a/packages/opentelemetry-core/src/platform/browser/index.ts b/packages/opentelemetry-core/src/platform/browser/index.ts index 139731376ba..e14dac0d3bb 100644 --- a/packages/opentelemetry-core/src/platform/browser/index.ts +++ b/packages/opentelemetry-core/src/platform/browser/index.ts @@ -17,7 +17,7 @@ export * from './BasePlugin'; export * from './environment'; export * from './hex-to-base64'; -export * from './id'; +export * from './RandomIdGenerator'; export * from './performance'; export * from './sdk-info'; export * from './timer-util'; diff --git a/packages/opentelemetry-core/src/platform/node/id.ts b/packages/opentelemetry-core/src/platform/node/RandomIdGenerator.ts similarity index 56% rename from packages/opentelemetry-core/src/platform/node/id.ts rename to packages/opentelemetry-core/src/platform/node/RandomIdGenerator.ts index 970025385c6..b262ab1da83 100644 --- a/packages/opentelemetry-core/src/platform/node/id.ts +++ b/packages/opentelemetry-core/src/platform/node/RandomIdGenerator.ts @@ -15,22 +15,25 @@ */ import * as crypto from 'crypto'; +import { IdGenerator } from '../../trace/IdGenerator'; const SPAN_ID_BYTES = 8; const TRACE_ID_BYTES = 16; -/** - * Returns a random 16-byte trace ID formatted/encoded as a 32 lowercase hex - * characters corresponding to 128 bits. - */ -export function randomTraceId(): string { - return crypto.randomBytes(TRACE_ID_BYTES).toString('hex'); -} +export class RandomIdGenerator implements IdGenerator { + /** + * Returns a random 16-byte trace ID formatted/encoded as a 32 lowercase hex + * characters corresponding to 128 bits. + */ + generateTraceId(): string { + return crypto.randomBytes(TRACE_ID_BYTES).toString('hex'); + } -/** - * Returns a random 8-byte span ID formatted/encoded as a 16 lowercase hex - * characters corresponding to 64 bits. - */ -export function randomSpanId(): string { - return crypto.randomBytes(SPAN_ID_BYTES).toString('hex'); + /** + * Returns a random 8-byte span ID formatted/encoded as a 16 lowercase hex + * characters corresponding to 64 bits. + */ + generateSpanId(): string { + return crypto.randomBytes(SPAN_ID_BYTES).toString('hex'); + } } diff --git a/packages/opentelemetry-core/src/platform/node/index.ts b/packages/opentelemetry-core/src/platform/node/index.ts index 139731376ba..e14dac0d3bb 100644 --- a/packages/opentelemetry-core/src/platform/node/index.ts +++ b/packages/opentelemetry-core/src/platform/node/index.ts @@ -17,7 +17,7 @@ export * from './BasePlugin'; export * from './environment'; export * from './hex-to-base64'; -export * from './id'; +export * from './RandomIdGenerator'; export * from './performance'; export * from './sdk-info'; export * from './timer-util'; diff --git a/packages/opentelemetry-core/src/trace/IdGenerator.ts b/packages/opentelemetry-core/src/trace/IdGenerator.ts new file mode 100644 index 00000000000..65f63f9c0ca --- /dev/null +++ b/packages/opentelemetry-core/src/trace/IdGenerator.ts @@ -0,0 +1,23 @@ +/* + * 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. + */ + +/** IdGenerator provides an interface for generating Trace Id and Span Id */ +export interface IdGenerator { + /** Returns a trace ID composed of 32 lowercase hex characters. */ + generateTraceId(): string; + /** Returns a span ID composed of 16 lowercase hex characters. */ + generateSpanId(): string; +} diff --git a/packages/opentelemetry-core/test/context/composite.test.ts b/packages/opentelemetry-core/test/context/composite.test.ts index dce823dfe4a..a26c6c5ac37 100644 --- a/packages/opentelemetry-core/test/context/composite.test.ts +++ b/packages/opentelemetry-core/test/context/composite.test.ts @@ -25,8 +25,7 @@ import * as assert from 'assert'; import { CompositePropagator, HttpTraceContext, - randomSpanId, - randomTraceId, + RandomIdGenerator, } from '../../src'; import { getExtractedSpanContext, @@ -49,8 +48,9 @@ describe('Composite Propagator', () => { let spanId: string; beforeEach(() => { - traceId = randomTraceId(); - spanId = randomSpanId(); + const idGenerator = new RandomIdGenerator(); + traceId = idGenerator.generateTraceId(); + spanId = idGenerator.generateSpanId(); }); describe('inject', () => { diff --git a/packages/opentelemetry-core/test/platform/id.test.ts b/packages/opentelemetry-core/test/platform/RandomIdGenerator.test.ts similarity index 63% rename from packages/opentelemetry-core/test/platform/id.test.ts rename to packages/opentelemetry-core/test/platform/RandomIdGenerator.test.ts index c73e09fb0eb..2400fa6ccca 100644 --- a/packages/opentelemetry-core/test/platform/id.test.ts +++ b/packages/opentelemetry-core/test/platform/RandomIdGenerator.test.ts @@ -13,36 +13,41 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - import * as assert from 'assert'; -import { randomSpanId, randomTraceId } from '../../src/platform'; +import { RandomIdGenerator } from '../../src/platform'; + +const idGenerator = new RandomIdGenerator(); describe('randomTraceId', () => { + let traceId1: string, traceId2: string; + beforeEach(() => { + traceId1 = idGenerator.generateTraceId(); + traceId2 = idGenerator.generateTraceId(); + }); + it('returns 32 character hex strings', () => { - const traceId = randomTraceId(); - assert.ok(traceId.match(/[a-f0-9]{32}/)); - assert.ok(!traceId.match(/^0+$/)); + assert.ok(traceId1.match(/[a-f0-9]{32}/)); + assert.ok(!traceId1.match(/^0+$/)); }); it('returns different ids on each call', () => { - const traceId1 = randomTraceId(); - const traceId2 = randomTraceId(); - assert.notDeepStrictEqual(traceId1, traceId2); }); }); describe('randomSpanId', () => { + let spanId1: string, spanId2: string; + beforeEach(() => { + spanId1 = idGenerator.generateSpanId(); + spanId2 = idGenerator.generateSpanId(); + }); + it('returns 16 character hex strings', () => { - const spanId = randomSpanId(); - assert.ok(spanId.match(/[a-f0-9]{16}/)); - assert.ok(!spanId.match(/^0+$/)); + assert.ok(spanId1.match(/[a-f0-9]{16}/)); + assert.ok(!spanId1.match(/^0+$/)); }); it('returns different ids on each call', () => { - const spanId1 = randomSpanId(); - const spanId2 = randomSpanId(); - assert.notDeepStrictEqual(spanId1, spanId2); }); }); diff --git a/packages/opentelemetry-exporter-collector/src/platform/node/protos b/packages/opentelemetry-exporter-collector/src/platform/node/protos index 9ffeee0ec53..b5468856918 160000 --- a/packages/opentelemetry-exporter-collector/src/platform/node/protos +++ b/packages/opentelemetry-exporter-collector/src/platform/node/protos @@ -1 +1 @@ -Subproject commit 9ffeee0ec532efe02285af84880deb2a53a3eab1 +Subproject commit b54688569186e0b862bf7462a983ccf2c50c0547 diff --git a/packages/opentelemetry-tracing/src/Tracer.ts b/packages/opentelemetry-tracing/src/Tracer.ts index dc513d6dad2..6f8fcc6f18b 100644 --- a/packages/opentelemetry-tracing/src/Tracer.ts +++ b/packages/opentelemetry-tracing/src/Tracer.ts @@ -22,8 +22,8 @@ import { InstrumentationLibrary, isValid, NoRecordingSpan, - randomSpanId, - randomTraceId, + IdGenerator, + RandomIdGenerator, setActiveSpan, } from '@opentelemetry/core'; import { Resource } from '@opentelemetry/resources'; @@ -38,6 +38,7 @@ import { mergeConfig } from './utility'; export class Tracer implements api.Tracer { private readonly _sampler: api.Sampler; private readonly _traceParams: TraceParams; + private readonly _idGenerator: IdGenerator; readonly resource: Resource; readonly instrumentationLibrary: InstrumentationLibrary; readonly logger: api.Logger; @@ -53,6 +54,7 @@ export class Tracer implements api.Tracer { const localConfig = mergeConfig(config); this._sampler = localConfig.sampler; this._traceParams = localConfig.traceParams; + this._idGenerator = config.idGenerator || new RandomIdGenerator(); this.resource = _tracerProvider.resource; this.instrumentationLibrary = instrumentationLibrary; this.logger = config.logger || new ConsoleLogger(config.logLevel); @@ -68,12 +70,12 @@ export class Tracer implements api.Tracer { context = api.context.active() ): api.Span { const parentContext = getParent(options, context); - const spanId = randomSpanId(); + const spanId = this._idGenerator.generateSpanId(); let traceId; let traceState; if (!parentContext || !isValid(parentContext)) { // New root span. - traceId = randomTraceId(); + traceId = this._idGenerator.generateTraceId(); } else { // New child span. traceId = parentContext.traceId; diff --git a/packages/opentelemetry-tracing/src/types.ts b/packages/opentelemetry-tracing/src/types.ts index a2ecc3939c8..5bb34b12b3c 100644 --- a/packages/opentelemetry-tracing/src/types.ts +++ b/packages/opentelemetry-tracing/src/types.ts @@ -15,7 +15,8 @@ */ import { HttpTextPropagator, Logger, Sampler } from '@opentelemetry/api'; -import { LogLevel } from '@opentelemetry/core'; +import { LogLevel, IdGenerator } from '@opentelemetry/core'; + import { ContextManager } from '@opentelemetry/context-base'; import { Resource } from '@opentelemetry/resources'; @@ -44,6 +45,12 @@ export interface TracerConfig { /** Bool for whether or not graceful shutdown is enabled */ gracefulShutdown?: boolean; + + /** + * Generator of trace and span IDs + * The default idGenerator generates random ids + */ + idGenerator?: IdGenerator; } /**