diff --git a/benchmark/propagator.js b/benchmark/propagator.js index 0c5c137c26d..4e97fb564c4 100644 --- a/benchmark/propagator.js +++ b/benchmark/propagator.js @@ -23,14 +23,17 @@ const setups = [ } ]; +const traceId = Uint8Array.from(Buffer.from('d4cda95b652f4a1592b449d5929fda1b', 'hex')); +const spanId = Uint8Array.from(Buffer.from('6e0c63257de34c92', 'hex')); + for (const setup of setups) { console.log(`Beginning ${setup.name} Benchmark...`); const propagator = setup.propagator; const suite = benchmark(100) .add('#Inject', function () { propagator.inject({ - traceId: 'd4cda95b652f4a1592b449d5929fda1b', - spanId: '6e0c63257de34c92' + traceId, + spanId }, setup.name, setup.injectCarrier); }) .add('#Extract', function () { diff --git a/packages/opentelemetry-api/src/trace/NoopSpan.ts b/packages/opentelemetry-api/src/trace/NoopSpan.ts index cfa3c9c4c08..1fa42b1f984 100644 --- a/packages/opentelemetry-api/src/trace/NoopSpan.ts +++ b/packages/opentelemetry-api/src/trace/NoopSpan.ts @@ -21,8 +21,8 @@ import { SpanContext } from './span_context'; import { Status } from './status'; import { TraceFlags } from './trace_flags'; -export const INVALID_TRACE_ID = '0'; -export const INVALID_SPAN_ID = '0'; +export const INVALID_TRACE_ID = new Uint8Array(16); +export const INVALID_SPAN_ID = new Uint8Array(8); const INVALID_SPAN_CONTEXT: SpanContext = { traceId: INVALID_TRACE_ID, spanId: INVALID_SPAN_ID, diff --git a/packages/opentelemetry-api/src/trace/span_context.ts b/packages/opentelemetry-api/src/trace/span_context.ts index b901cf52eb8..66ca65098d0 100644 --- a/packages/opentelemetry-api/src/trace/span_context.ts +++ b/packages/opentelemetry-api/src/trace/span_context.ts @@ -25,16 +25,14 @@ export interface SpanContext { /** * The ID of the trace that this span belongs to. It is worldwide unique * with practically sufficient probability by being made as 16 randomly - * generated bytes, encoded as a 32 lowercase hex characters corresponding to - * 128 bits. + * generated bytes. */ - traceId: string; + traceId: Uint8Array; /** * The ID of the Span. It is globally unique with practically sufficient - * probability by being made as 8 randomly generated bytes, encoded as a 16 - * lowercase hex characters corresponding to 64 bits. + * probability by being made as 8 randomly generated bytes. */ - spanId: string; + spanId: Uint8Array; /** * Only true if the SpanContext was propagated from a remote parent. */ diff --git a/packages/opentelemetry-api/test/api/api.test.ts b/packages/opentelemetry-api/test/api/api.test.ts index cfc75dfe365..5e6bd06fefb 100644 --- a/packages/opentelemetry-api/test/api/api.test.ts +++ b/packages/opentelemetry-api/test/api/api.test.ts @@ -41,8 +41,25 @@ describe('API', () => { describe('GlobalTracerProvider', () => { const spanContext = { - traceId: 'd4cda95b652f4a1592b449d5929fda1b', - spanId: '6e0c63257de34c92', + traceId: new Uint8Array([ + 0xd4, + 0xcd, + 0xa9, + 0x5b, + 0x65, + 0x2f, + 0x4a, + 0x15, + 0x92, + 0xb4, + 0x49, + 0xd5, + 0x92, + 0x9f, + 0xda, + 0x1b, + ]), + spanId: new Uint8Array([0x6e, 0x0c, 0x63, 0x25, 0x7d, 0xe3, 0x4c, 0x92]), traceFlags: TraceFlags.UNSAMPLED, }; const dummySpan = new NoopSpan(spanContext); diff --git a/packages/opentelemetry-api/test/noop-implementations/noop-span.test.ts b/packages/opentelemetry-api/test/noop-implementations/noop-span.test.ts index a42d4711891..fa3a6b49e20 100644 --- a/packages/opentelemetry-api/test/noop-implementations/noop-span.test.ts +++ b/packages/opentelemetry-api/test/noop-implementations/noop-span.test.ts @@ -40,13 +40,56 @@ describe('NoopSpan', () => { span.addEvent('sent', { id: '42', key: 'value' }); span.addLink({ - traceId: 'd4cda95b652f4a1592b449d5929fda1b', - spanId: '6e0c63257de34c92', + traceId: new Uint8Array([ + 0xd4, + 0xcd, + 0xa9, + 0x5b, + 0x65, + 0x2f, + 0x4a, + 0x15, + 0x92, + 0xb4, + 0x49, + 0xd5, + 0x92, + 0x9f, + 0xda, + 0x1b, + ]), + spanId: new Uint8Array([0x6e, 0x0c, 0x63, 0x25, 0x7d, 0xe3, 0x4c, 0x92]), }); span.addLink( { - traceId: 'd4cda95b652f4a1592b449d5929fda1b', - spanId: '6e0c63257de34c92', + traceId: new Uint8Array([ + 0xd4, + 0xcd, + 0xa9, + 0x5b, + 0x65, + 0x2f, + 0x4a, + 0x15, + 0x92, + 0xb4, + 0x49, + 0xd5, + 0x92, + 0x9f, + 0xda, + 0x1b, + ]), + spanId: new Uint8Array([ + 0x6e, + 0x0c, + 0x63, + 0x25, + 0x7d, + 0xe3, + 0x4c, + 0x92, + ]), }, { id: '42', key: 'value' } ); diff --git a/packages/opentelemetry-api/test/noop-implementations/noop-tracer.test.ts b/packages/opentelemetry-api/test/noop-implementations/noop-tracer.test.ts index ed017dda998..ad0a78c255e 100644 --- a/packages/opentelemetry-api/test/noop-implementations/noop-tracer.test.ts +++ b/packages/opentelemetry-api/test/noop-implementations/noop-tracer.test.ts @@ -15,12 +15,18 @@ */ import * as assert from 'assert'; -import { NoopTracer, NOOP_SPAN, SpanKind } from '../../src'; +import { + NoopTracer, + NOOP_SPAN, + SpanKind, + INVALID_TRACE_ID, + INVALID_SPAN_ID, +} from '../../src'; import { Context } from '@opentelemetry/scope-base'; describe('NoopTracer', () => { it('should not crash', () => { - const spanContext = { traceId: '', spanId: '' }; + const spanContext = { traceId: INVALID_TRACE_ID, spanId: INVALID_SPAN_ID }; const tracer = new NoopTracer(); assert.deepStrictEqual(tracer.startSpan('span-name'), NOOP_SPAN); diff --git a/packages/opentelemetry-core/src/context/propagation/B3Format.ts b/packages/opentelemetry-core/src/context/propagation/B3Format.ts index 2f2b7c9142b..1fad649606c 100644 --- a/packages/opentelemetry-core/src/context/propagation/B3Format.ts +++ b/packages/opentelemetry-core/src/context/propagation/B3Format.ts @@ -21,21 +21,12 @@ import { TraceFlags, } from '@opentelemetry/api'; import { getParentSpanContext, setExtractedSpanContext } from '../context'; +import { hexToId, idToHex } from '../../platform'; +import { traceIdIsValid, spanIdIsValid } from '../../trace/spancontext-utils'; export const X_B3_TRACE_ID = 'x-b3-traceid'; export const X_B3_SPAN_ID = 'x-b3-spanid'; export const X_B3_SAMPLED = 'x-b3-sampled'; -const VALID_TRACEID_REGEX = /^[0-9a-f]{32}$/i; -const VALID_SPANID_REGEX = /^[0-9a-f]{16}$/i; -const INVALID_ID_REGEX = /^0+$/i; - -function isValidTraceId(traceId: string): boolean { - return VALID_TRACEID_REGEX.test(traceId) && !INVALID_ID_REGEX.test(traceId); -} - -function isValidSpanId(spanId: string): boolean { - return VALID_SPANID_REGEX.test(spanId) && !INVALID_ID_REGEX.test(spanId); -} /** * Propagator for the B3 HTTP header format. @@ -47,11 +38,11 @@ export class B3Format implements HttpTextFormat { if (!spanContext) return; if ( - isValidTraceId(spanContext.traceId) && - isValidSpanId(spanContext.spanId) + traceIdIsValid(spanContext.traceId) && + spanIdIsValid(spanContext.spanId) ) { - carrier[X_B3_TRACE_ID] = spanContext.traceId; - carrier[X_B3_SPAN_ID] = spanContext.spanId; + carrier[X_B3_TRACE_ID] = idToHex(spanContext.traceId); + carrier[X_B3_SPAN_ID] = idToHex(spanContext.spanId); // We set the header only if there is an existing sampling decision. // Otherwise we will omit it => Absent. @@ -66,15 +57,17 @@ export class B3Format implements HttpTextFormat { const spanIdHeader = carrier[X_B3_SPAN_ID]; const sampledHeader = carrier[X_B3_SAMPLED]; if (!traceIdHeader || !spanIdHeader) return context; - const traceId = Array.isArray(traceIdHeader) - ? traceIdHeader[0] - : traceIdHeader; - const spanId = Array.isArray(spanIdHeader) ? spanIdHeader[0] : spanIdHeader; + const traceId = hexToId( + Array.isArray(traceIdHeader) ? traceIdHeader[0] : traceIdHeader + ); + const spanId = hexToId( + Array.isArray(spanIdHeader) ? spanIdHeader[0] : spanIdHeader + ); const options = Array.isArray(sampledHeader) ? sampledHeader[0] : sampledHeader; - if (isValidTraceId(traceId) && isValidSpanId(spanId)) { + if (traceIdIsValid(traceId) && spanIdIsValid(spanId)) { return setExtractedSpanContext(context, { traceId, spanId, diff --git a/packages/opentelemetry-core/src/context/propagation/BinaryTraceContext.ts b/packages/opentelemetry-core/src/context/propagation/BinaryTraceContext.ts index ebcd0391cd2..65878e3c393 100644 --- a/packages/opentelemetry-core/src/context/propagation/BinaryTraceContext.ts +++ b/packages/opentelemetry-core/src/context/propagation/BinaryTraceContext.ts @@ -55,26 +55,19 @@ export class BinaryTraceContext implements BinaryFormat { * | `---------------------------------- traceID field ID (0) * `------------------------------------ version (0) */ - const traceId = spanContext.traceId; - const spanId = spanContext.spanId; + const traceId = new Uint8Array(spanContext.traceId); + const spanId = new Uint8Array(spanContext.spanId); const buf = new Uint8Array(FORMAT_LENGTH); - let j = TRACE_ID_OFFSET; - for (let i = TRACE_ID_OFFSET; i < SPAN_ID_FIELD_ID_OFFSET; i++) { - // tslint:disable-next-line:ban Needed to parse hexadecimal. - buf[j++] = parseInt(traceId.substr((i - TRACE_ID_OFFSET) * 2, 2), 16); - } - buf[j++] = SPAN_ID_FIELD_ID; - for (let i = SPAN_ID_OFFSET; i < TRACE_OPTION_FIELD_ID_OFFSET; i++) { - // tslint:disable-next-line:ban Needed to parse hexadecimal. - buf[j++] = parseInt(spanId.substr((i - SPAN_ID_OFFSET) * 2, 2), 16); - } - buf[j++] = TRACE_OPTION_FIELD_ID; - buf[j++] = Number(spanContext.traceFlags) || TraceFlags.UNSAMPLED; + buf.set(traceId, TRACE_ID_OFFSET); + buf[SPAN_ID_FIELD_ID_OFFSET] = SPAN_ID_FIELD_ID; + buf.set(spanId, SPAN_ID_OFFSET); + buf[TRACE_OPTION_FIELD_ID_OFFSET] = TRACE_OPTION_FIELD_ID; + buf[TRACE_OPTIONS_OFFSET] = + Number(spanContext.traceFlags) || TraceFlags.UNSAMPLED; return buf; } fromBytes(buf: Uint8Array): SpanContext | null { - const result: SpanContext = { traceId: '', spanId: '' }; // Length must be 29. if (buf.length !== FORMAT_LENGTH) return null; // Check version and field numbers. @@ -87,27 +80,16 @@ export class BinaryTraceContext implements BinaryFormat { return null; } + const result: SpanContext = { + traceId: new Uint8Array(TRACE_ID_SIZE), + spanId: new Uint8Array(SPAN_ID_SIZE), + }; result.isRemote = true; // See serializeSpanContext for byte offsets. - result.traceId = toHex(buf.slice(TRACE_ID_OFFSET, SPAN_ID_FIELD_ID_OFFSET)); - result.spanId = toHex( - buf.slice(SPAN_ID_OFFSET, TRACE_OPTION_FIELD_ID_OFFSET) - ); + result.traceId = buf.slice(TRACE_ID_OFFSET, SPAN_ID_FIELD_ID_OFFSET); + result.spanId = buf.slice(SPAN_ID_OFFSET, TRACE_OPTION_FIELD_ID_OFFSET); result.traceFlags = buf[TRACE_OPTIONS_OFFSET]; return result; } } - -function toHex(buff: Uint8Array) { - let out = ''; - for (let i = 0; i < buff.length; ++i) { - const n = buff[i]; - if (n < 16) { - out += '0' + n.toString(16); - } else { - out += n.toString(16); - } - } - return out; -} diff --git a/packages/opentelemetry-core/src/context/propagation/HttpTraceContext.ts b/packages/opentelemetry-core/src/context/propagation/HttpTraceContext.ts index c1495579f11..079fa9e0675 100644 --- a/packages/opentelemetry-core/src/context/propagation/HttpTraceContext.ts +++ b/packages/opentelemetry-core/src/context/propagation/HttpTraceContext.ts @@ -22,6 +22,7 @@ import { TraceFlags, } from '@opentelemetry/api'; import { TraceState } from '../../trace/TraceState'; +import { hexToId, idToHex } from '../../platform'; import { getParentSpanContext, setExtractedSpanContext } from '../context'; export const TRACE_PARENT_HEADER = 'traceparent'; @@ -50,8 +51,8 @@ export function parseTraceParent(traceParent: string): SpanContext | null { } return { - traceId: match[1], - spanId: match[2], + traceId: hexToId(match[1]), + spanId: hexToId(match[2]), traceFlags: parseInt(match[3], 16), }; } @@ -67,9 +68,9 @@ export class HttpTraceContext implements HttpTextFormat { const spanContext = getParentSpanContext(context); if (!spanContext) return; - const traceParent = `${VERSION}-${spanContext.traceId}-${ + const traceParent = `${VERSION}-${idToHex(spanContext.traceId)}-${idToHex( spanContext.spanId - }-0${Number(spanContext.traceFlags || TraceFlags.UNSAMPLED).toString(16)}`; + )}-0${Number(spanContext.traceFlags || TraceFlags.UNSAMPLED).toString(16)}`; carrier[TRACE_PARENT_HEADER] = traceParent; if (spanContext.traceState) { diff --git a/packages/opentelemetry-core/src/platform/browser/id.ts b/packages/opentelemetry-core/src/platform/browser/id.ts index ab1c8188ac1..57b43d063b8 100644 --- a/packages/opentelemetry-core/src/platform/browser/id.ts +++ b/packages/opentelemetry-core/src/platform/browser/id.ts @@ -21,24 +21,78 @@ declare type WindowWithMsCrypto = Window & { const cryptoLib = window.crypto || (window as WindowWithMsCrypto).msCrypto; const SPAN_ID_BYTES = 8; -const spanBytesArray = new Uint8Array(SPAN_ID_BYTES); +const TRACE_ID_BYTES = 16; -/** Returns a random 16-byte trace ID formatted as a 32-char hex string. */ -export function randomTraceId(): string { - return randomSpanId() + randomSpanId(); +const byteToHex: string[] = []; +for (let n = 0; n <= 0xff; ++n) { + const hexOctet = n.toString(16).padStart(2, '0'); + byteToHex.push(hexOctet); } -/** Returns a random 8-byte span ID formatted as a 16-char hex string. */ -export function randomSpanId(): string { - let spanId = ''; - cryptoLib.getRandomValues(spanBytesArray); - for (let i = 0; i < SPAN_ID_BYTES; i++) { - const hexStr = spanBytesArray[i].toString(16); +/** + * Encodes an Uint8Array into a hex string. + * @param buf the array buffer to encode + */ +export function idToHex(buf: Uint8Array): string { + const hex = new Array(buf.length); + for (let i = 0; i < buf.length; ++i) { + hex.push(byteToHex[buf[i]]); + } + return hex.join(''); +} + +/** + * Encodes an Uint8Array into a base64 encoded string. + * @param buf the buffer to encode + */ +export function idToBase64(buf: Uint8Array): string { + let s = ''; + for (let i = 0; i < buf.byteLength; i++) { + s += String.fromCharCode(buf[i]); + } + return btoa(s); +} - // Zero pad bytes whose hex values are single digit. - if (hexStr.length === 1) spanId += '0'; +/** + * Converts hex encoded string into an Uint8Array + * @param s the string to convert + */ +export function hexToId(s: string): Uint8Array { + const cnt = s.length / 2; + const buf = new Uint8Array(cnt); + for (let i = 0; i < cnt; i++) { + buf[i] = parseInt(s.substring(2 * i, 2 * i + 2), 16); + } + return buf; +} - spanId += hexStr; +/* + * Compare if two id are equal. + * @param id1 first id to compare + * @param id2 second id to compare + */ +export function idsEquals(id1: Uint8Array, id2: Uint8Array): boolean { + if (id1.byteLength !== id2.byteLength) { + return false; + } + for (let i = 0; i < id1.byteLength; i++) { + if (id1[i] !== id2[i]) { + return false; + } } + return true; +} + +/** Returns a random 16-byte trace ID. */ +export function randomTraceId(): Uint8Array { + const traceId = new Uint8Array(TRACE_ID_BYTES); + cryptoLib.getRandomValues(traceId); + return traceId; +} + +/** Returns a random 8-byte span ID. */ +export function randomSpanId(): Uint8Array { + let spanId = new Uint8Array(SPAN_ID_BYTES); + cryptoLib.getRandomValues(spanId); return spanId; } diff --git a/packages/opentelemetry-core/src/platform/node/id.ts b/packages/opentelemetry-core/src/platform/node/id.ts index 75350e6eff2..9604d0b65b7 100644 --- a/packages/opentelemetry-core/src/platform/node/id.ts +++ b/packages/opentelemetry-core/src/platform/node/id.ts @@ -17,19 +17,58 @@ import * as crypto from 'crypto'; 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. + * Encodes an Uint8Array into a hex string. + * @param buf the buffer to encode */ -export function randomTraceId(): string { - return randomSpanId() + randomSpanId(); +export function idToHex(buf: Uint8Array): string { + return Buffer.from(buf.buffer, buf.byteOffset, buf.byteLength).toString( + 'hex' + ); } /** - * Returns a random 8-byte span ID formatted/encoded as a 16 lowercase hex - * characters corresponding to 64 bits. + * Encodes an Uint8Array into a base64 encoded string. + * @param buf the buffer to encode */ -export function randomSpanId(): string { - return crypto.randomBytes(SPAN_ID_BYTES).toString('hex'); +export function idToBase64(buf: Uint8Array): string { + return Buffer.from(buf.buffer, buf.byteOffset, buf.byteLength).toString( + 'base64' + ); +} + +/** + * Converts hex encoded string into an Uint8Array + * @param s the string to convert + */ +export function hexToId(s: string): Uint8Array { + const buf = Buffer.from(s, 'hex'); + return new Uint8Array(buf.buffer, buf.byteOffset, buf.byteLength); +} + +/** + * Compare if two id are equal. + * @param id1 first id to compare + * @param id2 second id to compare + */ +export function idsEquals(id1: Uint8Array, id2: Uint8Array): boolean { + return Buffer.compare(id1, id2) === 0; +} + +/** + * Returns a random 16-byte trace ID. + */ +export function randomTraceId(): Uint8Array { + const traceId = crypto.randomBytes(TRACE_ID_BYTES); + return new Uint8Array(traceId.buffer, traceId.byteOffset, traceId.byteLength); +} + +/** + * Returns a random 8-byte span ID. + */ +export function randomSpanId(): Uint8Array { + const spanId = crypto.randomBytes(SPAN_ID_BYTES); + return new Uint8Array(spanId.buffer, spanId.byteOffset, spanId.byteLength); } diff --git a/packages/opentelemetry-core/src/trace/spancontext-utils.ts b/packages/opentelemetry-core/src/trace/spancontext-utils.ts index 1f20afd2347..64e784182c3 100644 --- a/packages/opentelemetry-core/src/trace/spancontext-utils.ts +++ b/packages/opentelemetry-core/src/trace/spancontext-utils.ts @@ -15,22 +15,38 @@ */ import { SpanContext, TraceFlags } from '@opentelemetry/api'; +import { idsEquals } from '../platform'; -export const INVALID_SPANID = '0'; -export const INVALID_TRACEID = '0'; +export const INVALID_SPANID = new Uint8Array(8); +export const INVALID_TRACEID = new Uint8Array(16); export const INVALID_SPAN_CONTEXT: SpanContext = { traceId: INVALID_TRACEID, spanId: INVALID_SPANID, traceFlags: TraceFlags.UNSAMPLED, }; +/** + * Returns true if traceId is valid. + * @return true if traceId is valid. + */ +export function traceIdIsValid(traceId: Uint8Array): boolean { + return traceId.byteLength === 16 && !idsEquals(traceId, INVALID_TRACEID); +} + +/** + * Returns true if spanId is valid. + * @return true if spanId is valid. + */ +export function spanIdIsValid(spanId: Uint8Array): boolean { + return spanId.byteLength === 8 && !idsEquals(spanId, INVALID_SPANID); +} + /** * Returns true if this {@link SpanContext} is valid. * @return true if this {@link SpanContext} is valid. */ export function isValid(spanContext: SpanContext): boolean { return ( - spanContext.traceId !== INVALID_TRACEID && - spanContext.spanId !== INVALID_SPANID + spanIdIsValid(spanContext.spanId) && traceIdIsValid(spanContext.traceId) ); } diff --git a/packages/opentelemetry-core/test/context/B3Format.test.ts b/packages/opentelemetry-core/test/context/B3Format.test.ts index df7a1e6162c..3722b63ba5a 100644 --- a/packages/opentelemetry-core/test/context/B3Format.test.ts +++ b/packages/opentelemetry-core/test/context/B3Format.test.ts @@ -28,6 +28,7 @@ import { X_B3_TRACE_ID, } from '../../src/context/propagation/B3Format'; import { TraceState } from '../../src/trace/TraceState'; +import { INVALID_SPANID, INVALID_TRACEID } from '../../src'; describe('B3Format', () => { const b3Format = new B3Format(); @@ -40,8 +41,34 @@ describe('B3Format', () => { describe('.inject()', () => { it('should set b3 traceId and spanId headers', () => { const spanContext: SpanContext = { - traceId: 'd4cda95b652f4a1592b449d5929fda1b', - spanId: '6e0c63257de34c92', + traceId: new Uint8Array([ + 0xd4, + 0xcd, + 0xa9, + 0x5b, + 0x65, + 0x2f, + 0x4a, + 0x15, + 0x92, + 0xb4, + 0x49, + 0xd5, + 0x92, + 0x9f, + 0xda, + 0x1b, + ]), + spanId: new Uint8Array([ + 0x6e, + 0x0c, + 0x63, + 0x25, + 0x7d, + 0xe3, + 0x4c, + 0x92, + ]), traceFlags: TraceFlags.SAMPLED, }; @@ -59,8 +86,34 @@ describe('B3Format', () => { it('should set b3 traceId and spanId headers - ignore tracestate', () => { const spanContext: SpanContext = { - traceId: 'd4cda95b652f4a1592b449d5929fda1b', - spanId: '6e0c63257de34c92', + traceId: new Uint8Array([ + 0xd4, + 0xcd, + 0xa9, + 0x5b, + 0x65, + 0x2f, + 0x4a, + 0x15, + 0x92, + 0xb4, + 0x49, + 0xd5, + 0x92, + 0x9f, + 0xda, + 0x1b, + ]), + spanId: new Uint8Array([ + 0x6e, + 0x0c, + 0x63, + 0x25, + 0x7d, + 0xe3, + 0x4c, + 0x92, + ]), traceFlags: TraceFlags.UNSAMPLED, traceState: new TraceState('foo=bar,baz=qux'), isRemote: false, @@ -80,8 +133,8 @@ describe('B3Format', () => { it('should not inject empty spancontext', () => { const emptySpanContext = { - traceId: '', - spanId: '', + traceId: INVALID_TRACEID, + spanId: INVALID_SPANID, }; b3Format.inject( setExtractedSpanContext(Context.ROOT_CONTEXT, emptySpanContext), @@ -93,8 +146,34 @@ describe('B3Format', () => { it('should handle absence of sampling decision', () => { const spanContext: SpanContext = { - traceId: 'd4cda95b652f4a1592b449d5929fda1b', - spanId: '6e0c63257de34c92', + traceId: new Uint8Array([ + 0xd4, + 0xcd, + 0xa9, + 0x5b, + 0x65, + 0x2f, + 0x4a, + 0x15, + 0x92, + 0xb4, + 0x49, + 0xd5, + 0x92, + 0x9f, + 0xda, + 0x1b, + ]), + spanId: new Uint8Array([ + 0x6e, + 0x0c, + 0x63, + 0x25, + 0x7d, + 0xe3, + 0x4c, + 0x92, + ]), }; b3Format.inject( @@ -119,8 +198,34 @@ describe('B3Format', () => { ); assert.deepStrictEqual(extractedSpanContext, { - spanId: 'b7ad6b7169203331', - traceId: '0af7651916cd43dd8448eb211c80319c', + spanId: new Uint8Array([ + 0xb7, + 0xad, + 0x6b, + 0x71, + 0x69, + 0x20, + 0x33, + 0x31, + ]), + traceId: new Uint8Array([ + 0x0a, + 0xf7, + 0x65, + 0x19, + 0x16, + 0xcd, + 0x43, + 0xdd, + 0x84, + 0x48, + 0xeb, + 0x21, + 0x1c, + 0x80, + 0x31, + 0x9c, + ]), isRemote: true, traceFlags: TraceFlags.UNSAMPLED, }); @@ -135,8 +240,34 @@ describe('B3Format', () => { ); assert.deepStrictEqual(extractedSpanContext, { - spanId: 'b7ad6b7169203331', - traceId: '0af7651916cd43dd8448eb211c80319c', + spanId: new Uint8Array([ + 0xb7, + 0xad, + 0x6b, + 0x71, + 0x69, + 0x20, + 0x33, + 0x31, + ]), + traceId: new Uint8Array([ + 0x0a, + 0xf7, + 0x65, + 0x19, + 0x16, + 0xcd, + 0x43, + 0xdd, + 0x84, + 0x48, + 0xeb, + 0x21, + 0x1c, + 0x80, + 0x31, + 0x9c, + ]), isRemote: true, traceFlags: TraceFlags.SAMPLED, }); @@ -151,8 +282,34 @@ describe('B3Format', () => { ); assert.deepStrictEqual(extractedSpanContext, { - spanId: 'b7ad6b7169203331', - traceId: '0af7651916cd43dd8448eb211c80319c', + spanId: new Uint8Array([ + 0xb7, + 0xad, + 0x6b, + 0x71, + 0x69, + 0x20, + 0x33, + 0x31, + ]), + traceId: new Uint8Array([ + 0x0a, + 0xf7, + 0x65, + 0x19, + 0x16, + 0xcd, + 0x43, + 0xdd, + 0x84, + 0x48, + 0xeb, + 0x21, + 0x1c, + 0x80, + 0x31, + 0x9c, + ]), isRemote: true, traceFlags: TraceFlags.SAMPLED, }); @@ -167,8 +324,34 @@ describe('B3Format', () => { ); assert.deepStrictEqual(extractedSpanContext, { - spanId: 'b7ad6b7169203331', - traceId: '0af7651916cd43dd8448eb211c80319c', + spanId: new Uint8Array([ + 0xb7, + 0xad, + 0x6b, + 0x71, + 0x69, + 0x20, + 0x33, + 0x31, + ]), + traceId: new Uint8Array([ + 0x0a, + 0xf7, + 0x65, + 0x19, + 0x16, + 0xcd, + 0x43, + 0xdd, + 0x84, + 0x48, + 0xeb, + 0x21, + 0x1c, + 0x80, + 0x31, + 0x9c, + ]), isRemote: true, traceFlags: TraceFlags.UNSAMPLED, }); @@ -223,8 +406,34 @@ describe('B3Format', () => { b3Format.extract(Context.ROOT_CONTEXT, carrier) ); assert.deepStrictEqual(extractedSpanContext, { - spanId: 'b7ad6b7169203331', - traceId: '0af7651916cd43dd8448eb211c80319c', + spanId: new Uint8Array([ + 0xb7, + 0xad, + 0x6b, + 0x71, + 0x69, + 0x20, + 0x33, + 0x31, + ]), + traceId: new Uint8Array([ + 0x0a, + 0xf7, + 0x65, + 0x19, + 0x16, + 0xcd, + 0x43, + 0xdd, + 0x84, + 0x48, + 0xeb, + 0x21, + 0x1c, + 0x80, + 0x31, + 0x9c, + ]), isRemote: true, traceFlags: TraceFlags.SAMPLED, }); diff --git a/packages/opentelemetry-core/test/context/BinaryTraceContext.test.ts b/packages/opentelemetry-core/test/context/BinaryTraceContext.test.ts index 0b5c303fd46..e816772005a 100644 --- a/packages/opentelemetry-core/test/context/BinaryTraceContext.test.ts +++ b/packages/opentelemetry-core/test/context/BinaryTraceContext.test.ts @@ -20,8 +20,34 @@ import { SpanContext, TraceFlags } from '@opentelemetry/api'; describe('BinaryTraceContext', () => { const binaryTraceContext = new BinaryTraceContext(); - const commonTraceId = 'd4cda95b652f4a1592b449d5929fda1b'; - const commonSpanId = '75e8ed491aec7eca'; + const commonTraceId = new Uint8Array([ + 0xd4, + 0xcd, + 0xa9, + 0x5b, + 0x65, + 0x2f, + 0x4a, + 0x15, + 0x92, + 0xb4, + 0x49, + 0xd5, + 0x92, + 0x9f, + 0xda, + 0x1b, + ]); + const commonSpanId = new Uint8Array([ + 0x75, + 0xe8, + 0xed, + 0x49, + 0x1a, + 0xec, + 0x7e, + 0xca, + ]); const testCases: Array<{ structured: SpanContext | null; diff --git a/packages/opentelemetry-core/test/context/HttpTraceContext.test.ts b/packages/opentelemetry-core/test/context/HttpTraceContext.test.ts index bc74b8d6828..eae01400a8a 100644 --- a/packages/opentelemetry-core/test/context/HttpTraceContext.test.ts +++ b/packages/opentelemetry-core/test/context/HttpTraceContext.test.ts @@ -39,8 +39,34 @@ describe('HttpTraceContext', () => { describe('.inject()', () => { it('should set traceparent header', () => { const spanContext: SpanContext = { - traceId: 'd4cda95b652f4a1592b449d5929fda1b', - spanId: '6e0c63257de34c92', + traceId: new Uint8Array([ + 0xd4, + 0xcd, + 0xa9, + 0x5b, + 0x65, + 0x2f, + 0x4a, + 0x15, + 0x92, + 0xb4, + 0x49, + 0xd5, + 0x92, + 0x9f, + 0xda, + 0x1b, + ]), + spanId: new Uint8Array([ + 0x6e, + 0x0c, + 0x63, + 0x25, + 0x7d, + 0xe3, + 0x4c, + 0x92, + ]), traceFlags: TraceFlags.SAMPLED, }; @@ -57,8 +83,34 @@ describe('HttpTraceContext', () => { it('should set traceparent and tracestate header', () => { const spanContext: SpanContext = { - traceId: 'd4cda95b652f4a1592b449d5929fda1b', - spanId: '6e0c63257de34c92', + traceId: new Uint8Array([ + 0xd4, + 0xcd, + 0xa9, + 0x5b, + 0x65, + 0x2f, + 0x4a, + 0x15, + 0x92, + 0xb4, + 0x49, + 0xd5, + 0x92, + 0x9f, + 0xda, + 0x1b, + ]), + spanId: new Uint8Array([ + 0x6e, + 0x0c, + 0x63, + 0x25, + 0x7d, + 0xe3, + 0x4c, + 0x92, + ]), traceFlags: TraceFlags.SAMPLED, traceState: new TraceState('foo=bar,baz=qux'), }; @@ -84,8 +136,34 @@ describe('HttpTraceContext', () => { ); assert.deepStrictEqual(extractedSpanContext, { - spanId: 'b7ad6b7169203331', - traceId: '0af7651916cd43dd8448eb211c80319c', + spanId: new Uint8Array([ + 0xb7, + 0xad, + 0x6b, + 0x71, + 0x69, + 0x20, + 0x33, + 0x31, + ]), + traceId: new Uint8Array([ + 0x0a, + 0xf7, + 0x65, + 0x19, + 0x16, + 0xcd, + 0x43, + 0xdd, + 0x84, + 0x48, + 0xeb, + 0x21, + 0x1c, + 0x80, + 0x31, + 0x9c, + ]), isRemote: true, traceFlags: TraceFlags.SAMPLED, }); @@ -118,8 +196,34 @@ describe('HttpTraceContext', () => { httpTraceContext.extract(Context.ROOT_CONTEXT, carrier) ); assert.deepStrictEqual(extractedSpanContext, { - spanId: 'b7ad6b7169203331', - traceId: '0af7651916cd43dd8448eb211c80319c', + spanId: new Uint8Array([ + 0xb7, + 0xad, + 0x6b, + 0x71, + 0x69, + 0x20, + 0x33, + 0x31, + ]), + traceId: new Uint8Array([ + 0x0a, + 0xf7, + 0x65, + 0x19, + 0x16, + 0xcd, + 0x43, + 0xdd, + 0x84, + 0x48, + 0xeb, + 0x21, + 0x1c, + 0x80, + 0x31, + 0x9c, + ]), isRemote: true, traceFlags: TraceFlags.SAMPLED, }); @@ -151,8 +255,34 @@ describe('HttpTraceContext', () => { httpTraceContext.extract(Context.ROOT_CONTEXT, carrier) ); assert.deepStrictEqual(extractedSpanContext, { - spanId: 'b7ad6b7169203331', - traceId: '0af7651916cd43dd8448eb211c80319c', + spanId: new Uint8Array([ + 0xb7, + 0xad, + 0x6b, + 0x71, + 0x69, + 0x20, + 0x33, + 0x31, + ]), + traceId: new Uint8Array([ + 0x0a, + 0xf7, + 0x65, + 0x19, + 0x16, + 0xcd, + 0x43, + 0xdd, + 0x84, + 0x48, + 0xeb, + 0x21, + 0x1c, + 0x80, + 0x31, + 0x9c, + ]), isRemote: true, traceFlags: TraceFlags.SAMPLED, traceState: new TraceState('foo=bar,baz=qux,quux=quuz'), diff --git a/packages/opentelemetry-core/test/platform/id.test.ts b/packages/opentelemetry-core/test/platform/id.test.ts index 4a7226d3928..11a36f99cc9 100644 --- a/packages/opentelemetry-core/test/platform/id.test.ts +++ b/packages/opentelemetry-core/test/platform/id.test.ts @@ -15,18 +15,109 @@ */ import * as assert from 'assert'; -import { randomSpanId, randomTraceId } from '../../src/platform'; +import { + randomSpanId, + randomTraceId, + idToHex, + hexToId, + idsEquals, + idToBase64, +} from '../../src/platform'; describe('randomTraceId', () => { - it('returns different 32-char hex strings', () => { + it('returns different 16 bytes Uint8Array', () => { const traceId = randomTraceId(); - assert.ok(traceId.match(/[a-f0-9]{32}/)); + assert.ok(traceId instanceof Uint8Array); + assert.strictEqual(traceId.byteLength, 16); }); }); describe('randomSpanId', () => { - it('returns different 16-char hex string', () => { + it('returns different 8 bytes Uint8Array', () => { const spanId = randomSpanId(); - assert.ok(spanId.match(/[a-f0-9]{16}/)); + assert.ok(spanId instanceof Uint8Array); + assert.strictEqual(spanId.byteLength, 8); + }); +}); + +describe('idToHex', () => { + it('converts it to hex string', () => { + assert.strictEqual( + idToHex(new Uint8Array([0x01, 0xf8, 0xab, 0x56])), + '01f8ab56' + ); + }); +}); + +describe('idToBase64', () => { + it('converts it to a base64 string', () => { + const id1 = new Uint8Array([ + 0x7d, + 0xeb, + 0x73, + 0x9e, + 0x02, + 0xe4, + 0x4e, + 0xf2, + ]); + const id2 = new Uint8Array([ + 0x46, + 0xce, + 0xf8, + 0x37, + 0xb9, + 0x19, + 0xa1, + 0x6f, + 0xf2, + 0x6e, + 0x60, + 0x8c, + 0x8c, + 0xf4, + 0x2c, + 0x80, + ]); + assert.strictEqual(idToBase64(id1), 'fetzngLkTvI='); + assert.strictEqual(idToBase64(id2), 'Rs74N7kZoW/ybmCMjPQsgA=='); + }); +}); + +describe('hexToId', () => { + it('coverts hex encoded string to id', () => { + assert.deepStrictEqual( + hexToId('01f8ab56'), + new Uint8Array([0x01, 0xf8, 0xab, 0x56]) + ); + }); +}); + +describe('idsEquals', () => { + it('returns if ids match', () => { + assert.ok( + idsEquals( + new Uint8Array([0x11, 0x12, 0x13]), + new Uint8Array([0x11, 0x12, 0x13]) + ) + ); + assert.ok( + !idsEquals( + new Uint8Array([0x11, 0x12, 0x13]), + new Uint8Array([0x11, 0x12, 0x13, 0x14]) + ) + ); + assert.ok( + !idsEquals( + new Uint8Array([0x11, 0x12, 0x13, 0x14]), + new Uint8Array([0x11, 0x12, 0x13]) + ) + ); + assert.ok( + !idsEquals( + new Uint8Array([0x11, 0x12, 0x13]), + new Uint8Array([0x11, 0x12, 0x14]) + ) + ); }); }); diff --git a/packages/opentelemetry-core/test/trace/NoRecordingSpan.test.ts b/packages/opentelemetry-core/test/trace/NoRecordingSpan.test.ts index f1706f733e4..105bd8b87ff 100644 --- a/packages/opentelemetry-core/test/trace/NoRecordingSpan.test.ts +++ b/packages/opentelemetry-core/test/trace/NoRecordingSpan.test.ts @@ -21,8 +21,25 @@ import { TraceFlags } from '@opentelemetry/api'; describe('NoRecordingSpan', () => { it('propagates span contexts', () => { const spanContext = { - traceId: 'd4cda95b652f4a1592b449d5929fda1b', - spanId: '6e0c63257de34c92', + traceId: new Uint8Array([ + 0xd4, + 0xcd, + 0xa9, + 0x5b, + 0x65, + 0x2f, + 0x4a, + 0x15, + 0x92, + 0xb4, + 0x49, + 0xd5, + 0x92, + 0x9f, + 0xda, + 0x1b, + ]), + spanId: new Uint8Array([0x6e, 0x0c, 0x63, 0x25, 0x7d, 0xe3, 0x4c, 0x92]), traceFlags: TraceFlags.UNSAMPLED, }; diff --git a/packages/opentelemetry-core/test/trace/ProbabilitySampler.test.ts b/packages/opentelemetry-core/test/trace/ProbabilitySampler.test.ts index 9195682a4bd..7c6ad7d4b11 100644 --- a/packages/opentelemetry-core/test/trace/ProbabilitySampler.test.ts +++ b/packages/opentelemetry-core/test/trace/ProbabilitySampler.test.ts @@ -26,8 +26,34 @@ describe('ProbabilitySampler', () => { const sampler = new ProbabilitySampler(1); assert.strictEqual( sampler.shouldSample({ - traceId: 'd4cda95b652f4a1592b449d5929fda1b', - spanId: '6e0c63257de34c92', + traceId: new Uint8Array([ + 0xd4, + 0xcd, + 0xa9, + 0x5b, + 0x65, + 0x2f, + 0x4a, + 0x15, + 0x92, + 0xb4, + 0x49, + 0xd5, + 0x92, + 0x9f, + 0xda, + 0x1b, + ]), + spanId: new Uint8Array([ + 0x6e, + 0x0c, + 0x63, + 0x25, + 0x7d, + 0xe3, + 0x4c, + 0x92, + ]), }), true ); diff --git a/packages/opentelemetry-core/test/trace/spancontext-utils.test.ts b/packages/opentelemetry-core/test/trace/spancontext-utils.test.ts index 612ca34a8c0..487b25e5efb 100644 --- a/packages/opentelemetry-core/test/trace/spancontext-utils.test.ts +++ b/packages/opentelemetry-core/test/trace/spancontext-utils.test.ts @@ -20,8 +20,25 @@ import * as context from '../../src/trace/spancontext-utils'; describe('spancontext-utils', () => { it('should return true for valid spancontext', () => { const spanContext = { - traceId: 'd4cda95b652f4a1592b449d5929fda1b', - spanId: '6e0c63257de34c92', + traceId: new Uint8Array([ + 0xd4, + 0xcd, + 0xa9, + 0x5b, + 0x65, + 0x2f, + 0x4a, + 0x15, + 0x92, + 0xb4, + 0x49, + 0xd5, + 0x92, + 0x9f, + 0xda, + 0x1b, + ]), + spanId: new Uint8Array([0x6e, 0x0c, 0x63, 0x25, 0x7d, 0xe3, 0x4c, 0x92]), }; assert.ok(context.isValid(spanContext)); }); @@ -29,14 +46,31 @@ describe('spancontext-utils', () => { it('should return false when traceId is invalid', () => { const spanContext = { traceId: context.INVALID_TRACEID, - spanId: '6e0c63257de34c92', + spanId: new Uint8Array([0x6e, 0x0c, 0x63, 0x25, 0x7d, 0xe3, 0x4c, 0x92]), }; assert.ok(!context.isValid(spanContext)); }); it('should return false when spanId is invalid', () => { const spanContext = { - traceId: 'd4cda95b652f4a1592b449d5929fda1b', + traceId: new Uint8Array([ + 0xd4, + 0xcd, + 0xa9, + 0x5b, + 0x65, + 0x2f, + 0x4a, + 0x15, + 0x92, + 0xb4, + 0x49, + 0xd5, + 0x92, + 0x9f, + 0xda, + 0x1b, + ]), spanId: context.INVALID_SPANID, }; assert.ok(!context.isValid(spanContext)); diff --git a/packages/opentelemetry-exporter-collector/src/transform.ts b/packages/opentelemetry-exporter-collector/src/transform.ts index 1d60c442e27..c5138453cc7 100644 --- a/packages/opentelemetry-exporter-collector/src/transform.ts +++ b/packages/opentelemetry-exporter-collector/src/transform.ts @@ -14,7 +14,7 @@ * limitations under the License. */ -import { hexToBase64, hrTimeToTimeStamp } from '@opentelemetry/core'; +import { hrTimeToTimeStamp, idsEquals, idToBase64 } from '@opentelemetry/core'; import { ReadableSpan } from '@opentelemetry/tracing'; import { Attributes, Link, TimedEvent, TraceState } from '@opentelemetry/api'; import * as collectorTypes from './types'; @@ -145,7 +145,11 @@ export function toCollectorLinkType( const spanParentId = span.parentSpanId; const spanTraceId = span.spanContext.traceId; - if (linkSpanId === spanParentId && linkTraceId === spanTraceId) { + if ( + spanParentId != null && + idsEquals(linkSpanId, spanParentId) && + idsEquals(linkTraceId, spanTraceId) + ) { return collectorTypes.LinkType.PARENT_LINKED_SPAN; } return collectorTypes.LinkType.UNSPECIFIED; @@ -158,8 +162,8 @@ export function toCollectorLinkType( export function toCollectorLinks(span: ReadableSpan): collectorTypes.Links { const collectorLinks: collectorTypes.Link[] = span.links.map((link: Link) => { const collectorLink: collectorTypes.Link = { - traceId: hexToBase64(link.spanContext.traceId), - spanId: hexToBase64(link.spanContext.spanId), + traceId: idToBase64(link.spanContext.traceId), + spanId: idToBase64(link.spanContext.spanId), type: toCollectorLinkType(span, link), }; @@ -181,11 +185,9 @@ export function toCollectorLinks(span: ReadableSpan): collectorTypes.Links { */ export function toCollectorSpan(span: ReadableSpan): collectorTypes.Span { return { - traceId: hexToBase64(span.spanContext.traceId), - spanId: hexToBase64(span.spanContext.spanId), - parentSpanId: span.parentSpanId - ? hexToBase64(span.parentSpanId) - : undefined, + traceId: idToBase64(span.spanContext.traceId), + spanId: idToBase64(span.spanContext.spanId), + parentSpanId: span.parentSpanId ? idToBase64(span.parentSpanId) : undefined, tracestate: toCollectorTraceState(span.spanContext.traceState), name: toCollectorTruncatableString(span.name), kind: span.kind, diff --git a/packages/opentelemetry-exporter-collector/test/helper.ts b/packages/opentelemetry-exporter-collector/test/helper.ts index 46071b7e7fe..b7d14658299 100644 --- a/packages/opentelemetry-exporter-collector/test/helper.ts +++ b/packages/opentelemetry-exporter-collector/test/helper.ts @@ -25,11 +25,37 @@ export const mockedReadableSpan: ReadableSpan = { name: 'documentFetch', kind: 0, spanContext: { - traceId: '1f1008dc8e270e85c40a0d7c3939b278', - spanId: '5e107261f64fa53e', + traceId: new Uint8Array([ + 0x1f, + 0x10, + 0x08, + 0xdc, + 0x8e, + 0x27, + 0x0e, + 0x85, + 0xc4, + 0x0a, + 0x0d, + 0x7c, + 0x39, + 0x39, + 0xb2, + 0x78, + ]), + spanId: new Uint8Array([0x5e, 0x10, 0x72, 0x61, 0xf6, 0x4f, 0xa5, 0x3e]), traceFlags: 1, }, - parentSpanId: '78a8915098864388', + parentSpanId: new Uint8Array([ + 0x78, + 0xa8, + 0x91, + 0x50, + 0x98, + 0x86, + 0x43, + 0x88, + ]), startTime: [1574120165, 429803070], endTime: [1574120165, 438688070], status: { code: 0 }, @@ -37,8 +63,34 @@ export const mockedReadableSpan: ReadableSpan = { links: [ { spanContext: { - traceId: '1f1008dc8e270e85c40a0d7c3939b278', - spanId: '78a8915098864388', + traceId: new Uint8Array([ + 0x1f, + 0x10, + 0x08, + 0xdc, + 0x8e, + 0x27, + 0x0e, + 0x85, + 0xc4, + 0x0a, + 0x0d, + 0x7c, + 0x39, + 0x39, + 0xb2, + 0x78, + ]), + spanId: new Uint8Array([ + 0x78, + 0xa8, + 0x91, + 0x50, + 0x98, + 0x86, + 0x43, + 0x88, + ]), traceFlags: 1, }, attributes: { component: 'document-load' }, diff --git a/packages/opentelemetry-exporter-jaeger/src/transform.ts b/packages/opentelemetry-exporter-jaeger/src/transform.ts index 5ed607e4534..0bff24c6ab6 100644 --- a/packages/opentelemetry-exporter-jaeger/src/transform.ts +++ b/packages/opentelemetry-exporter-jaeger/src/transform.ts @@ -40,11 +40,11 @@ const DEFAULT_FLAGS = 0x1; * @param span Span to be translated */ export function spanToThrift(span: ReadableSpan): ThriftSpan { - const traceId = span.spanContext.traceId.padStart(32, '0'); - const traceIdHigh = traceId.slice(0, 16); - const traceIdLow = traceId.slice(16); + const traceId = span.spanContext.traceId; + const traceIdHigh = Buffer.from(traceId.slice(0, 8).buffer); + const traceIdLow = Buffer.from(traceId.slice(8).buffer); const parentSpan = span.parentSpanId - ? Utils.encodeInt64(span.parentSpanId) + ? Buffer.from(span.parentSpanId) : ThriftUtils.emptyBuffer; const tags = Object.keys(span.attributes).map( @@ -82,9 +82,9 @@ export function spanToThrift(span: ReadableSpan): ThriftSpan { const spanLogs: ThriftLog[] = ThriftUtils.getThriftLogs(logs); return { - traceIdLow: Utils.encodeInt64(traceIdLow), - traceIdHigh: Utils.encodeInt64(traceIdHigh), - spanId: Utils.encodeInt64(span.spanContext.spanId), + traceIdLow, + traceIdHigh, + spanId: Buffer.from(span.spanContext.spanId), parentSpanId: parentSpan, operationName: span.name, references: spanLinksToThriftRefs(span.links, span.parentSpanId), @@ -99,16 +99,19 @@ export function spanToThrift(span: ReadableSpan): ThriftSpan { /** Translate OpenTelemetry {@link Link}s to Jaeger ThriftReference. */ function spanLinksToThriftRefs( links: Link[], - parentSpanId?: string + parentSpanId?: Uint8Array ): ThriftReference[] { return links .map((link): ThriftReference | null => { - if (link.spanContext.spanId === parentSpanId) { + if ( + parentSpanId != null && + Buffer.compare(link.spanContext.spanId, parentSpanId) === 0 + ) { const refType = ThriftReferenceType.CHILD_OF; const traceId = link.spanContext.traceId; - const traceIdHigh = Utils.encodeInt64(traceId.slice(0, 16)); - const traceIdLow = Utils.encodeInt64(traceId.slice(16)); - const spanId = Utils.encodeInt64(link.spanContext.spanId); + const traceIdHigh = Buffer.from(traceId.slice(0, 8)); + const traceIdLow = Buffer.from(traceId.slice(8)); + const spanId = Buffer.from(link.spanContext.spanId); return { traceIdLow, traceIdHigh, spanId, refType }; } return null; diff --git a/packages/opentelemetry-exporter-jaeger/test/jaeger.test.ts b/packages/opentelemetry-exporter-jaeger/test/jaeger.test.ts index 20ef8467c8b..e168b441e41 100644 --- a/packages/opentelemetry-exporter-jaeger/test/jaeger.test.ts +++ b/packages/opentelemetry-exporter-jaeger/test/jaeger.test.ts @@ -108,8 +108,34 @@ describe('JaegerExporter', () => { it('should send spans to Jaeger backend and return with Success', () => { const spanContext = { - traceId: 'd4cda95b652f4a1592b449d5929fda1b', - spanId: '6e0c63257de34c92', + traceId: new Uint8Array([ + 0xd4, + 0xcd, + 0xa9, + 0x5b, + 0x65, + 0x2f, + 0x4a, + 0x15, + 0x92, + 0xb4, + 0x49, + 0xd5, + 0x92, + 0x9f, + 0xda, + 0x1b, + ]), + spanId: new Uint8Array([ + 0x6e, + 0x0c, + 0x63, + 0x25, + 0x7d, + 0xe3, + 0x4c, + 0x92, + ]), }; const readableSpan: ReadableSpan = { name: 'my-span1', diff --git a/packages/opentelemetry-exporter-jaeger/test/transform.test.ts b/packages/opentelemetry-exporter-jaeger/test/transform.test.ts index 2189b97d4d3..8e0da5cf5c6 100644 --- a/packages/opentelemetry-exporter-jaeger/test/transform.test.ts +++ b/packages/opentelemetry-exporter-jaeger/test/transform.test.ts @@ -23,8 +23,25 @@ import { hrTimeToMicroseconds } from '@opentelemetry/core'; describe('transform', () => { const spanContext = { - traceId: 'd4cda95b652f4a1592b449d5929fda1b', - spanId: '6e0c63257de34c92', + traceId: new Uint8Array([ + 0xd4, + 0xcd, + 0xa9, + 0x5b, + 0x65, + 0x2f, + 0x4a, + 0x15, + 0x92, + 0xb4, + 0x49, + 0xd5, + 0x92, + 0x9f, + 0xda, + 0x1b, + ]), + spanId: new Uint8Array([0x6e, 0x0c, 0x63, 0x25, 0x7d, 0xe3, 0x4c, 0x92]), }; describe('spanToThrift', () => { @@ -46,8 +63,34 @@ describe('transform', () => { links: [ { spanContext: { - traceId: 'a4cda95b652f4a1592b449d5929fda1b', - spanId: '3e0c63257de34c92', + traceId: new Uint8Array([ + 0xa4, + 0xcd, + 0xa9, + 0x5b, + 0x65, + 0x2f, + 0x4a, + 0x15, + 0x92, + 0xb4, + 0x49, + 0xd5, + 0x92, + 0x9f, + 0xda, + 0x1b, + ]), + spanId: new Uint8Array([ + 0x3e, + 0x0c, + 0x63, + 0x25, + 0x7d, + 0xe3, + 0x4c, + 0x92, + ]), }, attributes: { testBool: true, @@ -191,12 +234,47 @@ describe('transform', () => { code: types.CanonicalCode.OK, }, attributes: {}, - parentSpanId: '3e0c63257de34c92', + parentSpanId: new Uint8Array([ + 0x3e, + 0x0c, + 0x63, + 0x25, + 0x7d, + 0xe3, + 0x4c, + 0x92, + ]), links: [ { spanContext: { - traceId: 'a4cda95b652f4a1592b449d5929fda1b', - spanId: '3e0c63257de34c92', + traceId: new Uint8Array([ + 0xa4, + 0xcd, + 0xa9, + 0x5b, + 0x65, + 0x2f, + 0x4a, + 0x15, + 0x92, + 0xb4, + 0x49, + 0xd5, + 0x92, + 0x9f, + 0xda, + 0x1b, + ]), + spanId: new Uint8Array([ + 0x3e, + 0x0c, + 0x63, + 0x25, + 0x7d, + 0xe3, + 0x4c, + 0x92, + ]), }, }, ], @@ -219,37 +297,5 @@ describe('transform', () => { assert.strictEqual(ref1.spanId.toString('hex'), '3e0c63257de34c92'); assert.strictEqual(ref1.refType, ThriftReferenceType.CHILD_OF); }); - - it('should left pad trace ids', () => { - const readableSpan: ReadableSpan = { - name: 'my-span1', - kind: types.SpanKind.CLIENT, - spanContext: { - traceId: '92b449d5929fda1b', - spanId: '6e0c63257de34c92', - }, - startTime: [1566156729, 709], - endTime: [1566156731, 709], - status: { - code: types.CanonicalCode.DATA_LOSS, - message: 'data loss', - }, - attributes: {}, - links: [], - events: [], - duration: [32, 800000000], - }; - - const thriftSpan = spanToThrift(readableSpan); - - assert.strictEqual( - thriftSpan.traceIdLow.toString('hex'), - '92b449d5929fda1b' - ); - assert.strictEqual( - thriftSpan.traceIdHigh.toString('hex'), - '0000000000000000' - ); - }); }); }); diff --git a/packages/opentelemetry-exporter-stackdriver-trace/src/transform.ts b/packages/opentelemetry-exporter-stackdriver-trace/src/transform.ts index e88b6e9b2a1..c17923e98ed 100644 --- a/packages/opentelemetry-exporter-stackdriver-trace/src/transform.ts +++ b/packages/opentelemetry-exporter-stackdriver-trace/src/transform.ts @@ -17,6 +17,7 @@ import { hrTimeToTimeStamp, VERSION as CORE_VERSION, + idToHex, } from '@opentelemetry/core'; import { ReadableSpan } from '@opentelemetry/tracing'; import * as ot from '@opentelemetry/api'; @@ -51,8 +52,10 @@ export function getReadableSpanTransformer( }, endTime: hrTimeToTimeStamp(span.endTime), startTime: hrTimeToTimeStamp(span.startTime), - name: `projects/${projectId}/traces/${span.spanContext.traceId}/spans/${span.spanContext.spanId}`, - spanId: span.spanContext.spanId, + name: `projects/${projectId}/traces/${idToHex( + span.spanContext.traceId + )}/spans/${idToHex(span.spanContext.spanId)}`, + spanId: idToHex(span.spanContext.spanId), sameProcessAsParentSpan: !span.spanContext.isRemote, status: span.status, timeEvents: { @@ -67,7 +70,7 @@ export function getReadableSpanTransformer( }; if (span.parentSpanId) { - out.parentSpanId = span.parentSpanId; + out.parentSpanId = idToHex(span.parentSpanId); } return out; @@ -77,8 +80,8 @@ export function getReadableSpanTransformer( function transformLink(link: ot.Link): Link { return { attributes: transformAttributes(link.attributes), - spanId: link.spanContext.spanId, - traceId: link.spanContext.traceId, + spanId: idToHex(link.spanContext.spanId), + traceId: idToHex(link.spanContext.traceId), type: LinkType.UNSPECIFIED, }; } diff --git a/packages/opentelemetry-exporter-stackdriver-trace/test/exporter.test.ts b/packages/opentelemetry-exporter-stackdriver-trace/test/exporter.test.ts index 68e60baf23d..12acc551f2a 100644 --- a/packages/opentelemetry-exporter-stackdriver-trace/test/exporter.test.ts +++ b/packages/opentelemetry-exporter-stackdriver-trace/test/exporter.test.ts @@ -113,8 +113,34 @@ describe('Stackdriver Trace Exporter', () => { links: [], name: 'my-span', spanContext: { - traceId: 'd4cda95b652f4a1592b449d5929fda1b', - spanId: '6e0c63257de34c92', + traceId: new Uint8Array([ + 0xd4, + 0xcd, + 0xa9, + 0x5b, + 0x65, + 0x2f, + 0x4a, + 0x15, + 0x92, + 0xb4, + 0x49, + 0xd5, + 0x92, + 0x9f, + 0xda, + 0x1b, + ]), + spanId: new Uint8Array([ + 0x6e, + 0x0c, + 0x63, + 0x25, + 0x7d, + 0xe3, + 0x4c, + 0x92, + ]), isRemote: true, }, status: { code: types.CanonicalCode.OK }, @@ -145,8 +171,34 @@ describe('Stackdriver Trace Exporter', () => { links: [], name: 'my-span', spanContext: { - traceId: 'd4cda95b652f4a1592b449d5929fda1b', - spanId: '6e0c63257de34c92', + traceId: new Uint8Array([ + 0xd4, + 0xcd, + 0xa9, + 0x5b, + 0x65, + 0x2f, + 0x4a, + 0x15, + 0x92, + 0xb4, + 0x49, + 0xd5, + 0x92, + 0x9f, + 0xda, + 0x1b, + ]), + spanId: new Uint8Array([ + 0x6e, + 0x0c, + 0x63, + 0x25, + 0x7d, + 0xe3, + 0x4c, + 0x92, + ]), isRemote: true, }, status: { code: types.CanonicalCode.OK }, @@ -176,8 +228,34 @@ describe('Stackdriver Trace Exporter', () => { links: [], name: 'my-span', spanContext: { - traceId: 'd4cda95b652f4a1592b449d5929fda1b', - spanId: '6e0c63257de34c92', + traceId: new Uint8Array([ + 0xd4, + 0xcd, + 0xa9, + 0x5b, + 0x65, + 0x2f, + 0x4a, + 0x15, + 0x92, + 0xb4, + 0x49, + 0xd5, + 0x92, + 0x9f, + 0xda, + 0x1b, + ]), + spanId: new Uint8Array([ + 0x6e, + 0x0c, + 0x63, + 0x25, + 0x7d, + 0xe3, + 0x4c, + 0x92, + ]), isRemote: true, }, status: { code: types.CanonicalCode.OK }, @@ -205,8 +283,34 @@ describe('Stackdriver Trace Exporter', () => { links: [], name: 'my-span', spanContext: { - traceId: 'd4cda95b652f4a1592b449d5929fda1b', - spanId: '6e0c63257de34c92', + traceId: new Uint8Array([ + 0xd4, + 0xcd, + 0xa9, + 0x5b, + 0x65, + 0x2f, + 0x4a, + 0x15, + 0x92, + 0xb4, + 0x49, + 0xd5, + 0x92, + 0x9f, + 0xda, + 0x1b, + ]), + spanId: new Uint8Array([ + 0x6e, + 0x0c, + 0x63, + 0x25, + 0x7d, + 0xe3, + 0x4c, + 0x92, + ]), isRemote: true, }, status: { code: types.CanonicalCode.OK }, diff --git a/packages/opentelemetry-exporter-stackdriver-trace/test/transform.test.ts b/packages/opentelemetry-exporter-stackdriver-trace/test/transform.test.ts index 6d9ddf7969f..98b65edee2a 100644 --- a/packages/opentelemetry-exporter-stackdriver-trace/test/transform.test.ts +++ b/packages/opentelemetry-exporter-stackdriver-trace/test/transform.test.ts @@ -29,8 +29,25 @@ describe('transform', () => { beforeEach(() => { spanContext = { - traceId: 'd4cda95b652f4a1592b449d5929fda1b', - spanId: '6e0c63257de34c92', + traceId: new Uint8Array([ + 0xd4, + 0xcd, + 0xa9, + 0x5b, + 0x65, + 0x2f, + 0x4a, + 0x15, + 0x92, + 0xb4, + 0x49, + 0xd5, + 0x92, + 0x9f, + 0xda, + 0x1b, + ]), + spanId: new Uint8Array([0x6e, 0x0c, 0x63, 0x25, 0x7d, 0xe3, 0x4c, 0x92]), isRemote: true, }; @@ -79,7 +96,16 @@ describe('transform', () => { }); it('should transform spans with parent', () => { - (readableSpan as any).parentSpanId = '3e0c63257de34c92'; + (readableSpan as any).parentSpanId = new Uint8Array([ + 0x3e, + 0x0c, + 0x63, + 0x25, + 0x7d, + 0xe3, + 0x4c, + 0x92, + ]); const result = transformer(readableSpan); assert.deepStrictEqual(result.parentSpanId, '3e0c63257de34c92'); }); @@ -132,8 +158,34 @@ describe('transform', () => { it('should transform links', () => { readableSpan.links.push({ spanContext: { - traceId: 'a4cda95b652f4a1592b449d5929fda1b', - spanId: '3e0c63257de34c92', + traceId: new Uint8Array([ + 0xa4, + 0xcd, + 0xa9, + 0x5b, + 0x65, + 0x2f, + 0x4a, + 0x15, + 0x92, + 0xb4, + 0x49, + 0xd5, + 0x92, + 0x9f, + 0xda, + 0x1b, + ]), + spanId: new Uint8Array([ + 0x3e, + 0x0c, + 0x63, + 0x25, + 0x7d, + 0xe3, + 0x4c, + 0x92, + ]), isRemote: true, traceFlags: types.TraceFlags.SAMPLED, }, @@ -159,8 +211,34 @@ describe('transform', () => { it('should transform links with attributes', () => { readableSpan.links.push({ spanContext: { - traceId: 'a4cda95b652f4a1592b449d5929fda1b', - spanId: '3e0c63257de34c92', + traceId: new Uint8Array([ + 0xa4, + 0xcd, + 0xa9, + 0x5b, + 0x65, + 0x2f, + 0x4a, + 0x15, + 0x92, + 0xb4, + 0x49, + 0xd5, + 0x92, + 0x9f, + 0xda, + 0x1b, + ]), + spanId: new Uint8Array([ + 0x3e, + 0x0c, + 0x63, + 0x25, + 0x7d, + 0xe3, + 0x4c, + 0x92, + ]), isRemote: true, traceFlags: types.TraceFlags.SAMPLED, }, diff --git a/packages/opentelemetry-exporter-zipkin/src/transform.ts b/packages/opentelemetry-exporter-zipkin/src/transform.ts index cbf09085261..9f4f07fc3d8 100644 --- a/packages/opentelemetry-exporter-zipkin/src/transform.ts +++ b/packages/opentelemetry-exporter-zipkin/src/transform.ts @@ -16,7 +16,7 @@ import * as types from '@opentelemetry/api'; import { ReadableSpan } from '@opentelemetry/tracing'; -import { hrTimeToMicroseconds } from '@opentelemetry/core'; +import { hrTimeToMicroseconds, idToHex } from '@opentelemetry/core'; import * as zipkinTypes from './types'; const ZIPKIN_SPAN_KIND_MAPPING = { @@ -42,10 +42,13 @@ export function toZipkinSpan( statusDescriptionTagName: string ): zipkinTypes.Span { const zipkinSpan: zipkinTypes.Span = { - traceId: span.spanContext.traceId, - parentId: span.parentSpanId, + traceId: idToHex(span.spanContext.traceId), + parentId: + span.parentSpanId != null + ? idToHex(span.parentSpanId) + : span.parentSpanId, name: span.name, - id: span.spanContext.spanId, + id: idToHex(span.spanContext.spanId), kind: ZIPKIN_SPAN_KIND_MAPPING[span.kind], timestamp: hrTimeToMicroseconds(span.startTime), duration: hrTimeToMicroseconds(span.duration), diff --git a/packages/opentelemetry-exporter-zipkin/test/transform.test.ts b/packages/opentelemetry-exporter-zipkin/test/transform.test.ts index f32512003f7..54692633f40 100644 --- a/packages/opentelemetry-exporter-zipkin/test/transform.test.ts +++ b/packages/opentelemetry-exporter-zipkin/test/transform.test.ts @@ -35,10 +35,36 @@ const logger = new NoopLogger(); const tracer = new BasicTracerProvider({ logger, }).getTracer('default'); -const parentId = '5c1c63257de34c67'; +const parentId = new Uint8Array([ + 0x5c, + 0x1c, + 0x63, + 0x25, + 0x7d, + 0xe3, + 0x4c, + 0x67, +]); const spanContext: types.SpanContext = { - traceId: 'd4cda95b652f4a1592b449d5929fda1b', - spanId: '6e0c63257de34c92', + traceId: new Uint8Array([ + 0xd4, + 0xcd, + 0xa9, + 0x5b, + 0x65, + 0x2f, + 0x4a, + 0x15, + 0x92, + 0xb4, + 0x49, + 0xd5, + 0x92, + 0x9f, + 0xda, + 0x1b, + ]), + spanId: new Uint8Array([0x6e, 0x0c, 0x63, 0x25, 0x7d, 0xe3, 0x4c, 0x92]), traceFlags: types.TraceFlags.SAMPLED, }; @@ -76,19 +102,19 @@ describe('transform', () => { duration: hrTimeToMicroseconds( hrTimeDuration(span.startTime, span.endTime) ), - id: span.spanContext.spanId, + id: '6e0c63257de34c92', localEndpoint: { serviceName: 'my-service', }, name: span.name, - parentId, + parentId: '5c1c63257de34c67', tags: { key1: 'value1', key2: 'value2', [statusCodeTagName]: 'OK', }, timestamp: hrTimeToMicroseconds(span.startTime), - traceId: span.spanContext.traceId, + traceId: 'd4cda95b652f4a1592b449d5929fda1b', }); }); it("should skip parentSpanId if doesn't exist", () => { @@ -112,7 +138,7 @@ describe('transform', () => { duration: hrTimeToMicroseconds( hrTimeDuration(span.startTime, span.endTime) ), - id: span.spanContext.spanId, + id: '6e0c63257de34c92', localEndpoint: { serviceName: 'my-service', }, @@ -122,7 +148,7 @@ describe('transform', () => { [statusCodeTagName]: 'OK', }, timestamp: hrTimeToMicroseconds(span.startTime), - traceId: span.spanContext.traceId, + traceId: 'd4cda95b652f4a1592b449d5929fda1b', }); }); // SpanKind mapping tests @@ -151,7 +177,7 @@ describe('transform', () => { duration: hrTimeToMicroseconds( hrTimeDuration(span.startTime, span.endTime) ), - id: span.spanContext.spanId, + id: '6e0c63257de34c92', localEndpoint: { serviceName: 'my-service', }, @@ -161,7 +187,7 @@ describe('transform', () => { [statusCodeTagName]: 'OK', }, timestamp: hrTimeToMicroseconds(span.startTime), - traceId: span.spanContext.traceId, + traceId: 'd4cda95b652f4a1592b449d5929fda1b', }); }) ); diff --git a/packages/opentelemetry-exporter-zipkin/test/zipkin.test.ts b/packages/opentelemetry-exporter-zipkin/test/zipkin.test.ts index b4b0a5177a0..9f504a9fa1b 100644 --- a/packages/opentelemetry-exporter-zipkin/test/zipkin.test.ts +++ b/packages/opentelemetry-exporter-zipkin/test/zipkin.test.ts @@ -33,8 +33,25 @@ function getReadableSpan() { name: 'my-span', kind: types.SpanKind.INTERNAL, spanContext: { - traceId: 'd4cda95b652f4a1592b449d5929fda1b', - spanId: '6e0c63257de34c92', + traceId: new Uint8Array([ + 0xd4, + 0xcd, + 0xa9, + 0x5b, + 0x65, + 0x2f, + 0x4a, + 0x15, + 0x92, + 0xb4, + 0x49, + 0xd5, + 0x92, + 0x9f, + 0xda, + 0x1b, + ]), + spanId: new Uint8Array([0x6e, 0x0c, 0x63, 0x25, 0x7d, 0xe3, 0x4c, 0x92]), }, startTime: [startTime, 0], endTime: [startTime + duration, 0], @@ -127,7 +144,16 @@ describe('ZipkinExporter', () => { }) .reply(202); - const parentSpanId = '5c1c63257de34c67'; + const parentSpanId = new Uint8Array([ + 0x5c, + 0x1c, + 0x63, + 0x25, + 0x7d, + 0xe3, + 0x4c, + 0x67, + ]); const startTime = 1566156729709; const duration = 2000; @@ -136,8 +162,34 @@ describe('ZipkinExporter', () => { kind: types.SpanKind.INTERNAL, parentSpanId, spanContext: { - traceId: 'd4cda95b652f4a1592b449d5929fda1b', - spanId: '6e0c63257de34c92', + traceId: new Uint8Array([ + 0xd4, + 0xcd, + 0xa9, + 0x5b, + 0x65, + 0x2f, + 0x4a, + 0x15, + 0x92, + 0xb4, + 0x49, + 0xd5, + 0x92, + 0x9f, + 0xda, + 0x1b, + ]), + spanId: new Uint8Array([ + 0x6e, + 0x0c, + 0x63, + 0x25, + 0x7d, + 0xe3, + 0x4c, + 0x92, + ]), }, startTime: [startTime, 0], endTime: [startTime + duration, 0], @@ -162,8 +214,34 @@ describe('ZipkinExporter', () => { name: 'my-span', kind: types.SpanKind.SERVER, spanContext: { - traceId: 'd4cda95b652f4a1592b449d5929fda1b', - spanId: '6e0c63257de34c92', + traceId: new Uint8Array([ + 0xd4, + 0xcd, + 0xa9, + 0x5b, + 0x65, + 0x2f, + 0x4a, + 0x15, + 0x92, + 0xb4, + 0x49, + 0xd5, + 0x92, + 0x9f, + 0xda, + 0x1c, + ]), + spanId: new Uint8Array([ + 0x6e, + 0x0c, + 0x63, + 0x25, + 0x7d, + 0xe3, + 0x4c, + 0x93, + ]), }, startTime: [startTime, 0], endTime: [startTime + duration, 0], @@ -194,24 +272,24 @@ describe('ZipkinExporter', () => { }, ], duration: duration * MICROS_PER_SECS, - id: span1.spanContext.spanId, + id: '6e0c63257de34c92', localEndpoint: { serviceName: 'my-service', }, name: span1.name, - parentId: parentSpanId, + parentId: '5c1c63257de34c67', tags: { key1: 'value1', key2: 'value2', 'ot.status_code': 'OK', }, timestamp: startTime * MICROS_PER_SECS, - traceId: span1.spanContext.traceId, + traceId: 'd4cda95b652f4a1592b449d5929fda1b', }, // Span 2 { duration: duration * MICROS_PER_SECS, - id: span2.spanContext.spanId, + id: '6e0c63257de34c93', kind: 'SERVER', localEndpoint: { serviceName: 'my-service', @@ -221,7 +299,7 @@ describe('ZipkinExporter', () => { 'ot.status_code': 'OK', }, timestamp: hrTimeToMicroseconds([startTime, 0]), - traceId: span2.spanContext.traceId, + traceId: 'd4cda95b652f4a1592b449d5929fda1c', }, ]); }); diff --git a/packages/opentelemetry-plugin-dns/test/functionals/utils.test.ts b/packages/opentelemetry-plugin-dns/test/functionals/utils.test.ts index cc35f6ec61c..d7bad2c0839 100644 --- a/packages/opentelemetry-plugin-dns/test/functionals/utils.test.ts +++ b/packages/opentelemetry-plugin-dns/test/functionals/utils.test.ts @@ -164,7 +164,7 @@ describe('Utility', () => { const span = new Span( new BasicTracerProvider().getTracer('default'), 'test', - { spanId: '', traceId: '' }, + { spanId: new Uint8Array(8), traceId: new Uint8Array(16) }, SpanKind.INTERNAL ); utils.setError(new Error(errorMessage), span, process.versions.node); diff --git a/packages/opentelemetry-plugin-dns/test/utils/assertSpan.ts b/packages/opentelemetry-plugin-dns/test/utils/assertSpan.ts index e6238651f59..f7e42885f92 100644 --- a/packages/opentelemetry-plugin-dns/test/utils/assertSpan.ts +++ b/packages/opentelemetry-plugin-dns/test/utils/assertSpan.ts @@ -31,10 +31,10 @@ export const assertSpan = ( } ) => { if (span.spanContext.traceId) { - assert.strictEqual(span.spanContext.traceId.length, 32); + assert.strictEqual(span.spanContext.traceId.length, 16); } if (span.spanContext.spanId) { - assert.strictEqual(span.spanContext.spanId.length, 16); + assert.strictEqual(span.spanContext.spanId.length, 8); } assert.strictEqual(span.kind, SpanKind.CLIENT); diff --git a/packages/opentelemetry-plugin-document-load/test/documentLoad.test.ts b/packages/opentelemetry-plugin-document-load/test/documentLoad.test.ts index 541044e05a4..b9022ce9854 100644 --- a/packages/opentelemetry-plugin-document-load/test/documentLoad.test.ts +++ b/packages/opentelemetry-plugin-document-load/test/documentLoad.test.ts @@ -363,13 +363,47 @@ describe('DocumentLoad Plugin', () => { assert.strictEqual(rootSpan.name, 'documentFetch'); assert.strictEqual(fetchSpan.name, 'documentLoad'); - assert.strictEqual( + assert.deepStrictEqual( rootSpan.spanContext.traceId, - 'ab42124a3c573678d4d8b21ba52df3bf' + new Uint8Array([ + 0xab, + 0x42, + 0x12, + 0x4a, + 0x3c, + 0x57, + 0x36, + 0x78, + 0xd4, + 0xd8, + 0xb2, + 0x1b, + 0xa5, + 0x2d, + 0xf3, + 0xbf, + ]) ); - assert.strictEqual( + assert.deepStrictEqual( fetchSpan.spanContext.traceId, - 'ab42124a3c573678d4d8b21ba52df3bf' + new Uint8Array([ + 0xab, + 0x42, + 0x12, + 0x4a, + 0x3c, + 0x57, + 0x36, + 0x78, + 0xd4, + 0xd8, + 0xb2, + 0x1b, + 0xa5, + 0x2d, + 0xf3, + 0xbf, + ]) ); assert.strictEqual(spyOnEnd.callCount, 2); diff --git a/packages/opentelemetry-plugin-grpc/test/grpc.test.ts b/packages/opentelemetry-plugin-grpc/test/grpc.test.ts index 0cd3b67669e..c463d5578f4 100644 --- a/packages/opentelemetry-plugin-grpc/test/grpc.test.ts +++ b/packages/opentelemetry-plugin-grpc/test/grpc.test.ts @@ -437,11 +437,11 @@ describe('GrpcPlugin', () => { assertSpan(serverSpan, SpanKind.SERVER, validations); assertSpan(clientSpan, SpanKind.CLIENT, validations); assertPropagation(serverSpan, clientSpan); - assert.strictEqual( + assert.deepStrictEqual( rootSpan.context().traceId, serverSpan.spanContext.traceId ); - assert.strictEqual( + assert.deepStrictEqual( rootSpan.context().spanId, clientSpan.parentSpanId ); @@ -539,11 +539,11 @@ describe('GrpcPlugin', () => { assertSpan(serverSpan, SpanKind.SERVER, validations); assertSpan(clientSpan, SpanKind.CLIENT, validations); assertPropagation(serverSpan, clientSpan); - assert.strictEqual( + assert.deepStrictEqual( rootSpan.context().traceId, serverSpan.spanContext.traceId ); - assert.strictEqual( + assert.deepStrictEqual( rootSpan.context().spanId, clientSpan.parentSpanId ); diff --git a/packages/opentelemetry-plugin-grpc/test/utils/assertionUtils.ts b/packages/opentelemetry-plugin-grpc/test/utils/assertionUtils.ts index b484a1561e7..085bc10e823 100644 --- a/packages/opentelemetry-plugin-grpc/test/utils/assertionUtils.ts +++ b/packages/opentelemetry-plugin-grpc/test/utils/assertionUtils.ts @@ -30,8 +30,8 @@ export const assertSpan = ( kind: SpanKind, validations: { name: string; status: grpc.status } ) => { - assert.strictEqual(span.spanContext.traceId.length, 32); - assert.strictEqual(span.spanContext.spanId.length, 16); + assert.strictEqual(span.spanContext.traceId.length, 16); + assert.strictEqual(span.spanContext.spanId.length, 8); assert.strictEqual(span.kind, kind); assert.strictEqual( @@ -63,11 +63,11 @@ export const assertPropagation = ( ) => { const targetSpanContext = incomingSpan.spanContext; const sourceSpanContext = outgoingSpan.spanContext; - assert.strictEqual(targetSpanContext.traceId, sourceSpanContext.traceId); - assert.strictEqual(incomingSpan.parentSpanId, sourceSpanContext.spanId); + assert.deepStrictEqual(targetSpanContext.traceId, sourceSpanContext.traceId); + assert.deepStrictEqual(incomingSpan.parentSpanId, sourceSpanContext.spanId); assert.strictEqual( targetSpanContext.traceFlags, sourceSpanContext.traceFlags ); - assert.notStrictEqual(targetSpanContext.spanId, sourceSpanContext.spanId); + assert.notDeepStrictEqual(targetSpanContext.spanId, sourceSpanContext.spanId); }; diff --git a/packages/opentelemetry-plugin-http/test/functionals/utils.test.ts b/packages/opentelemetry-plugin-http/test/functionals/utils.test.ts index 8bfb673fcf1..c10e4a27117 100644 --- a/packages/opentelemetry-plugin-http/test/functionals/utils.test.ts +++ b/packages/opentelemetry-plugin-http/test/functionals/utils.test.ts @@ -14,7 +14,11 @@ * limitations under the License. */ -import { NoopLogger } from '@opentelemetry/core'; +import { + NoopLogger, + INVALID_SPANID, + INVALID_TRACEID, +} from '@opentelemetry/core'; import { NoopScopeManager } from '@opentelemetry/scope-base'; import { BasicTracerProvider, Span } from '@opentelemetry/tracing'; import { CanonicalCode, SpanKind } from '@opentelemetry/api'; @@ -259,7 +263,7 @@ describe('Utility', () => { scopeManager: new NoopScopeManager(), }).getTracer('default'), 'test', - { spanId: '', traceId: '' }, + { spanId: INVALID_SPANID, traceId: INVALID_TRACEID }, SpanKind.INTERNAL ); /* tslint:disable-next-line:no-any */ diff --git a/packages/opentelemetry-plugin-http/test/utils/DummyPropagation.ts b/packages/opentelemetry-plugin-http/test/utils/DummyPropagation.ts index 5c65bd16d7c..cbc1f91f726 100644 --- a/packages/opentelemetry-plugin-http/test/utils/DummyPropagation.ts +++ b/packages/opentelemetry-plugin-http/test/utils/DummyPropagation.ts @@ -19,20 +19,21 @@ import { getParentSpanContext, } from '@opentelemetry/core'; import * as http from 'http'; +import { hexToId, idToHex } from '@opentelemetry/core'; export class DummyPropagation implements HttpTextFormat { static TRACE_CONTEXT_KEY = 'x-dummy-trace-id'; static SPAN_CONTEXT_KEY = 'x-dummy-span-id'; extract(context: Context, carrier: http.OutgoingHttpHeaders) { return setExtractedSpanContext(context, { - traceId: carrier[DummyPropagation.TRACE_CONTEXT_KEY] as string, - spanId: DummyPropagation.SPAN_CONTEXT_KEY, + traceId: hexToId(carrier[DummyPropagation.TRACE_CONTEXT_KEY] as string), + spanId: hexToId(carrier[DummyPropagation.SPAN_CONTEXT_KEY] as string), }); } inject(context: Context, headers: { [custom: string]: string }): void { const spanContext = getParentSpanContext(context); if (!spanContext) return; - headers[DummyPropagation.TRACE_CONTEXT_KEY] = spanContext.traceId; - headers[DummyPropagation.SPAN_CONTEXT_KEY] = spanContext.spanId; + headers[DummyPropagation.TRACE_CONTEXT_KEY] = idToHex(spanContext.traceId); + headers[DummyPropagation.SPAN_CONTEXT_KEY] = idToHex(spanContext.spanId); } } diff --git a/packages/opentelemetry-plugin-http/test/utils/assertSpan.ts b/packages/opentelemetry-plugin-http/test/utils/assertSpan.ts index cc70a654b91..b04309dd246 100644 --- a/packages/opentelemetry-plugin-http/test/utils/assertSpan.ts +++ b/packages/opentelemetry-plugin-http/test/utils/assertSpan.ts @@ -39,8 +39,8 @@ export const assertSpan = ( component: string; } ) => { - assert.strictEqual(span.spanContext.traceId.length, 32); - assert.strictEqual(span.spanContext.spanId.length, 16); + assert.strictEqual(span.spanContext.traceId.length, 16); + assert.strictEqual(span.spanContext.spanId.length, 8); assert.strictEqual(span.kind, kind); assert.strictEqual( span.name, @@ -122,7 +122,7 @@ export const assertSpan = ( 'must have HOST_IP' ); } - assert.strictEqual(span.parentSpanId, DummyPropagation.SPAN_CONTEXT_KEY); + assert.strictEqual(span.parentSpanId!.byteLength, 8); } else if (validations.reqHeaders) { assert.ok(validations.reqHeaders[DummyPropagation.TRACE_CONTEXT_KEY]); assert.ok(validations.reqHeaders[DummyPropagation.SPAN_CONTEXT_KEY]); diff --git a/packages/opentelemetry-plugin-https/test/utils/DummyPropagation.ts b/packages/opentelemetry-plugin-https/test/utils/DummyPropagation.ts index 5c65bd16d7c..cbc1f91f726 100644 --- a/packages/opentelemetry-plugin-https/test/utils/DummyPropagation.ts +++ b/packages/opentelemetry-plugin-https/test/utils/DummyPropagation.ts @@ -19,20 +19,21 @@ import { getParentSpanContext, } from '@opentelemetry/core'; import * as http from 'http'; +import { hexToId, idToHex } from '@opentelemetry/core'; export class DummyPropagation implements HttpTextFormat { static TRACE_CONTEXT_KEY = 'x-dummy-trace-id'; static SPAN_CONTEXT_KEY = 'x-dummy-span-id'; extract(context: Context, carrier: http.OutgoingHttpHeaders) { return setExtractedSpanContext(context, { - traceId: carrier[DummyPropagation.TRACE_CONTEXT_KEY] as string, - spanId: DummyPropagation.SPAN_CONTEXT_KEY, + traceId: hexToId(carrier[DummyPropagation.TRACE_CONTEXT_KEY] as string), + spanId: hexToId(carrier[DummyPropagation.SPAN_CONTEXT_KEY] as string), }); } inject(context: Context, headers: { [custom: string]: string }): void { const spanContext = getParentSpanContext(context); if (!spanContext) return; - headers[DummyPropagation.TRACE_CONTEXT_KEY] = spanContext.traceId; - headers[DummyPropagation.SPAN_CONTEXT_KEY] = spanContext.spanId; + headers[DummyPropagation.TRACE_CONTEXT_KEY] = idToHex(spanContext.traceId); + headers[DummyPropagation.SPAN_CONTEXT_KEY] = idToHex(spanContext.spanId); } } diff --git a/packages/opentelemetry-plugin-https/test/utils/assertSpan.ts b/packages/opentelemetry-plugin-https/test/utils/assertSpan.ts index 91afcab1708..ea02ab49d17 100644 --- a/packages/opentelemetry-plugin-https/test/utils/assertSpan.ts +++ b/packages/opentelemetry-plugin-https/test/utils/assertSpan.ts @@ -40,8 +40,8 @@ export const assertSpan = ( component: string; } ) => { - assert.strictEqual(span.spanContext.traceId.length, 32); - assert.strictEqual(span.spanContext.spanId.length, 16); + assert.strictEqual(span.spanContext.traceId.length, 16); + assert.strictEqual(span.spanContext.spanId.length, 8); assert.strictEqual(span.kind, kind); assert.strictEqual( span.name, @@ -118,7 +118,7 @@ export const assertSpan = ( 'must have HOST_PORT' ); assert.ok(span.attributes[AttributeNames.NET_HOST_IP], 'must have HOST_IP'); - assert.strictEqual(span.parentSpanId, DummyPropagation.SPAN_CONTEXT_KEY); + assert.strictEqual(span.parentSpanId!.byteLength, 8); } else if (validations.reqHeaders) { assert.ok(validations.reqHeaders[DummyPropagation.TRACE_CONTEXT_KEY]); assert.ok(validations.reqHeaders[DummyPropagation.SPAN_CONTEXT_KEY]); diff --git a/packages/opentelemetry-plugin-xml-http-request/test/xhr.test.ts b/packages/opentelemetry-plugin-xml-http-request/test/xhr.test.ts index 97a28908c0f..069c5f141da 100644 --- a/packages/opentelemetry-plugin-xml-http-request/test/xhr.test.ts +++ b/packages/opentelemetry-plugin-xml-http-request/test/xhr.test.ts @@ -23,6 +23,7 @@ import { X_B3_SAMPLED, X_B3_SPAN_ID, X_B3_TRACE_ID, + idToHex, } from '@opentelemetry/core'; import { ZoneScopeManager } from '@opentelemetry/scope-zone'; import * as tracing from '@opentelemetry/tracing'; @@ -327,12 +328,12 @@ describe('xhr', () => { const span: types.Span = exportSpy.args[0][0][0]; assert.strictEqual( requests[0].requestHeaders[X_B3_TRACE_ID], - span.context().traceId, + idToHex(span.context().traceId), `trace header '${X_B3_TRACE_ID}' not set` ); assert.strictEqual( requests[0].requestHeaders[X_B3_SPAN_ID], - span.context().spanId, + idToHex(span.context().spanId), `trace header '${X_B3_SPAN_ID}' not set` ); assert.strictEqual( @@ -359,12 +360,12 @@ describe('xhr', () => { const span: types.Span = exportSpy.args[0][0][0]; assert.strictEqual( requests[0].requestHeaders[X_B3_TRACE_ID], - span.context().traceId, + idToHex(span.context().traceId), `trace header '${X_B3_TRACE_ID}' not set` ); assert.strictEqual( requests[0].requestHeaders[X_B3_SPAN_ID], - span.context().spanId, + idToHex(span.context().spanId), `trace header '${X_B3_SPAN_ID}' not set` ); assert.strictEqual( diff --git a/packages/opentelemetry-propagator-jaeger/src/JaegerHttpTraceFormat.ts b/packages/opentelemetry-propagator-jaeger/src/JaegerHttpTraceFormat.ts index be166154c0e..e62244d8400 100644 --- a/packages/opentelemetry-propagator-jaeger/src/JaegerHttpTraceFormat.ts +++ b/packages/opentelemetry-propagator-jaeger/src/JaegerHttpTraceFormat.ts @@ -25,6 +25,7 @@ import { getParentSpanContext, setExtractedSpanContext, } from '@opentelemetry/core'; +import { idToHex, hexToId } from '@opentelemetry/core'; export const UBER_TRACE_ID_HEADER = 'uber-trace-id'; @@ -61,9 +62,9 @@ export class JaegerHttpTraceFormat implements HttpTextFormat { spanContext.traceFlags || TraceFlags.UNSAMPLED ).toString(16)}`; - carrier[ - this._jaegerTraceHeader - ] = `${spanContext.traceId}:${spanContext.spanId}:0:${traceFlags}`; + carrier[this._jaegerTraceHeader] = `${idToHex( + spanContext.traceId + )}:${idToHex(spanContext.spanId)}:0:${traceFlags}`; } extract(context: Context, carrier: Carrier): Context { @@ -93,5 +94,10 @@ function deserializeSpanContext(serializedString: string): SpanContext | null { const traceFlags = flags.match(/^[0-9a-f]{2}$/i) ? parseInt(flags) & 1 : 1; - return { traceId, spanId, isRemote: true, traceFlags }; + return { + traceId: hexToId(traceId), + spanId: hexToId(spanId), + isRemote: true, + traceFlags, + }; } diff --git a/packages/opentelemetry-propagator-jaeger/test/JaegerHttpTraceFormat.test.ts b/packages/opentelemetry-propagator-jaeger/test/JaegerHttpTraceFormat.test.ts index c8e5e1b406d..7496686df90 100644 --- a/packages/opentelemetry-propagator-jaeger/test/JaegerHttpTraceFormat.test.ts +++ b/packages/opentelemetry-propagator-jaeger/test/JaegerHttpTraceFormat.test.ts @@ -38,8 +38,34 @@ describe('JaegerHttpTraceFormat', () => { describe('.inject()', () => { it('should set uber trace id header', () => { const spanContext: SpanContext = { - traceId: 'd4cda95b652f4a1592b449d5929fda1b', - spanId: '6e0c63257de34c92', + traceId: new Uint8Array([ + 0xd4, + 0xcd, + 0xa9, + 0x5b, + 0x65, + 0x2f, + 0x4a, + 0x15, + 0x92, + 0xb4, + 0x49, + 0xd5, + 0x92, + 0x9f, + 0xda, + 0x1b, + ]), + spanId: new Uint8Array([ + 0x6e, + 0x0c, + 0x63, + 0x25, + 0x7d, + 0xe3, + 0x4c, + 0x92, + ]), traceFlags: TraceFlags.SAMPLED, }; @@ -55,8 +81,34 @@ describe('JaegerHttpTraceFormat', () => { it('should use custom header if provided', () => { const spanContext: SpanContext = { - traceId: 'd4cda95b652f4a1592b449d5929fda1b', - spanId: '6e0c63257de34c92', + traceId: new Uint8Array([ + 0xd4, + 0xcd, + 0xa9, + 0x5b, + 0x65, + 0x2f, + 0x4a, + 0x15, + 0x92, + 0xb4, + 0x49, + 0xd5, + 0x92, + 0x9f, + 0xda, + 0x1b, + ]), + spanId: new Uint8Array([ + 0x6e, + 0x0c, + 0x63, + 0x25, + 0x7d, + 0xe3, + 0x4c, + 0x92, + ]), traceFlags: TraceFlags.SAMPLED, }; @@ -80,8 +132,34 @@ describe('JaegerHttpTraceFormat', () => { ); assert.deepStrictEqual(extractedSpanContext, { - spanId: '6e0c63257de34c92', - traceId: 'd4cda95b652f4a1592b449d5929fda1b', + spanId: new Uint8Array([ + 0x6e, + 0x0c, + 0x63, + 0x25, + 0x7d, + 0xe3, + 0x4c, + 0x92, + ]), + traceId: new Uint8Array([ + 0xd4, + 0xcd, + 0xa9, + 0x5b, + 0x65, + 0x2f, + 0x4a, + 0x15, + 0x92, + 0xb4, + 0x49, + 0xd5, + 0x92, + 0x9f, + 0xda, + 0x1b, + ]), isRemote: true, traceFlags: TraceFlags.SAMPLED, }); @@ -95,8 +173,26 @@ describe('JaegerHttpTraceFormat', () => { ); assert.deepStrictEqual(extractedSpanContext, { - spanId: '45fd2a9709dadcf1', - traceId: '9c41e35aeb6d1272', + spanId: new Uint8Array([ + 0x45, + 0xfd, + 0x2a, + 0x97, + 0x09, + 0xda, + 0xdc, + 0xf1, + ]), + traceId: new Uint8Array([ + 0x9c, + 0x41, + 0xe3, + 0x5a, + 0xeb, + 0x6d, + 0x12, + 0x72, + ]), isRemote: true, traceFlags: TraceFlags.SAMPLED, }); @@ -110,8 +206,26 @@ describe('JaegerHttpTraceFormat', () => { ); assert.deepStrictEqual(extractedSpanContext, { - spanId: '5ac292c4a11a163e', - traceId: 'ac1f3dc3c2c0b06e', + spanId: new Uint8Array([ + 0x5a, + 0xc2, + 0x92, + 0xc4, + 0xa1, + 0x1a, + 0x16, + 0x3e, + ]), + traceId: new Uint8Array([ + 0xac, + 0x1f, + 0x3d, + 0xc3, + 0xc2, + 0xc0, + 0xb0, + 0x6e, + ]), isRemote: true, traceFlags: TraceFlags.SAMPLED, }); @@ -125,8 +239,34 @@ describe('JaegerHttpTraceFormat', () => { ); assert.deepStrictEqual(extractedSpanContext, { - spanId: '6e0c63257de34c92', - traceId: 'd4cda95b652f4a1592b449d5929fda1b', + spanId: new Uint8Array([ + 0x6e, + 0x0c, + 0x63, + 0x25, + 0x7d, + 0xe3, + 0x4c, + 0x92, + ]), + traceId: new Uint8Array([ + 0xd4, + 0xcd, + 0xa9, + 0x5b, + 0x65, + 0x2f, + 0x4a, + 0x15, + 0x92, + 0xb4, + 0x49, + 0xd5, + 0x92, + 0x9f, + 0xda, + 0x1b, + ]), isRemote: true, traceFlags: TraceFlags.SAMPLED, }); diff --git a/packages/opentelemetry-shim-opentracing/src/shim.ts b/packages/opentelemetry-shim-opentracing/src/shim.ts index 07fb689ccfd..12017656d60 100644 --- a/packages/opentelemetry-shim-opentracing/src/shim.ts +++ b/packages/opentelemetry-shim-opentracing/src/shim.ts @@ -19,6 +19,7 @@ import { getExtractedSpanContext, NoopLogger, setExtractedSpanContext, + idToHex, } from '@opentelemetry/core'; import * as opentracing from 'opentracing'; @@ -82,14 +83,14 @@ export class SpanContextShim extends opentracing.SpanContext { * Returns the trace ID as a string. */ toTraceId(): string { - return this._spanContext.traceId; + return idToHex(this._spanContext.traceId); } /** * Returns the span ID as a string. */ toSpanId(): string { - return this._spanContext.spanId; + return idToHex(this._spanContext.spanId); } } diff --git a/packages/opentelemetry-shim-opentracing/test/Shim.test.ts b/packages/opentelemetry-shim-opentracing/test/Shim.test.ts index fbecde28f42..277728f4fad 100644 --- a/packages/opentelemetry-shim-opentracing/test/Shim.test.ts +++ b/packages/opentelemetry-shim-opentracing/test/Shim.test.ts @@ -18,7 +18,11 @@ import * as assert from 'assert'; import * as opentracing from 'opentracing'; import { BasicTracerProvider, Span } from '@opentelemetry/tracing'; import { TracerShim, SpanShim, SpanContextShim } from '../src/shim'; -import { INVALID_SPAN_CONTEXT, timeInputToHrTime } from '@opentelemetry/core'; +import { + INVALID_SPAN_CONTEXT, + timeInputToHrTime, + idToHex, +} from '@opentelemetry/core'; import { performance } from 'perf_hooks'; describe('OpenTracing Shim', () => { @@ -87,7 +91,7 @@ describe('OpenTracing Shim', () => { childOf: span, }) as SpanShim; assert.strictEqual( - (childSpan.getSpan() as Span).parentSpanId, + idToHex((childSpan.getSpan() as Span).parentSpanId!), context.toSpanId() ); assert.strictEqual( @@ -101,7 +105,7 @@ describe('OpenTracing Shim', () => { childOf: context, }) as SpanShim; assert.strictEqual( - (childSpan.getSpan() as Span).parentSpanId, + idToHex((childSpan.getSpan() as Span).parentSpanId!), context.toSpanId() ); assert.strictEqual( @@ -131,8 +135,11 @@ describe('OpenTracing Shim', () => { it('returns the correct context', () => { const shim = new SpanContextShim(INVALID_SPAN_CONTEXT); assert.strictEqual(shim.getSpanContext(), INVALID_SPAN_CONTEXT); - assert.strictEqual(shim.toTraceId(), INVALID_SPAN_CONTEXT.traceId); - assert.strictEqual(shim.toSpanId(), INVALID_SPAN_CONTEXT.spanId); + assert.strictEqual( + shim.toTraceId(), + idToHex(INVALID_SPAN_CONTEXT.traceId) + ); + assert.strictEqual(shim.toSpanId(), idToHex(INVALID_SPAN_CONTEXT.spanId)); }); }); diff --git a/packages/opentelemetry-test-utils/testUtils.ts b/packages/opentelemetry-test-utils/testUtils.ts index 21478e3f9e3..0ea80ba9953 100644 --- a/packages/opentelemetry-test-utils/testUtils.ts +++ b/packages/opentelemetry-test-utils/testUtils.ts @@ -81,8 +81,8 @@ export const assertSpan = ( events: Event[], status: Status ) => { - assert.strictEqual(span.spanContext.traceId.length, 32); - assert.strictEqual(span.spanContext.spanId.length, 16); + assert.strictEqual(span.spanContext.traceId.length, 16); + assert.strictEqual(span.spanContext.spanId.length, 8); assert.strictEqual(span.kind, kind); assert.ok(span.endTime); @@ -112,11 +112,11 @@ export const assertPropagation = ( ) => { const targetSpanContext = childSpan.spanContext; const sourceSpanContext = parentSpan.context(); - assert.strictEqual(targetSpanContext.traceId, sourceSpanContext.traceId); - assert.strictEqual(childSpan.parentSpanId, sourceSpanContext.spanId); + assert.deepStrictEqual(targetSpanContext.traceId, sourceSpanContext.traceId); + assert.deepStrictEqual(childSpan.parentSpanId, sourceSpanContext.spanId); assert.strictEqual( targetSpanContext.traceFlags, sourceSpanContext.traceFlags ); - assert.notStrictEqual(targetSpanContext.spanId, sourceSpanContext.spanId); + assert.notDeepStrictEqual(targetSpanContext.spanId, sourceSpanContext.spanId); }; diff --git a/packages/opentelemetry-tracing/src/Span.ts b/packages/opentelemetry-tracing/src/Span.ts index 0ae73d8f93a..e82c816b7d6 100644 --- a/packages/opentelemetry-tracing/src/Span.ts +++ b/packages/opentelemetry-tracing/src/Span.ts @@ -34,7 +34,7 @@ export class Span implements types.Span, ReadableSpan { // purposes but are not intended to be written-to directly. readonly spanContext: types.SpanContext; readonly kind: types.SpanKind; - readonly parentSpanId?: string; + readonly parentSpanId?: Uint8Array; readonly attributes: types.Attributes = {}; readonly links: types.Link[] = []; readonly events: types.TimedEvent[] = []; @@ -56,7 +56,7 @@ export class Span implements types.Span, ReadableSpan { spanName: string, spanContext: types.SpanContext, kind: types.SpanKind, - parentSpanId?: string, + parentSpanId?: Uint8Array, links: types.Link[] = [], startTime: types.TimeInput = hrTime() ) { diff --git a/packages/opentelemetry-tracing/src/export/ReadableSpan.ts b/packages/opentelemetry-tracing/src/export/ReadableSpan.ts index 039752268de..46d7c0dbfc6 100644 --- a/packages/opentelemetry-tracing/src/export/ReadableSpan.ts +++ b/packages/opentelemetry-tracing/src/export/ReadableSpan.ts @@ -28,7 +28,7 @@ export interface ReadableSpan { readonly name: string; readonly kind: SpanKind; readonly spanContext: SpanContext; - readonly parentSpanId?: string; + readonly parentSpanId?: Uint8Array; readonly startTime: HrTime; readonly endTime: HrTime; readonly status: Status; diff --git a/packages/opentelemetry-tracing/test/BasicTracerRegistry.test.ts b/packages/opentelemetry-tracing/test/BasicTracerRegistry.test.ts index f829de1ff76..1532875e17a 100644 --- a/packages/opentelemetry-tracing/test/BasicTracerRegistry.test.ts +++ b/packages/opentelemetry-tracing/test/BasicTracerRegistry.test.ts @@ -145,8 +145,8 @@ describe('BasicTracerProvider', () => { assert.ok(span); assert.ok(span instanceof Span); const context = span.context(); - assert.ok(context.traceId.match(/[a-f0-9]{32}/)); - assert.ok(context.spanId.match(/[a-f0-9]{16}/)); + assert.strictEqual(context.traceId.byteLength, 16); + assert.strictEqual(context.spanId.byteLength, 8); assert.strictEqual(context.traceFlags, TraceFlags.SAMPLED); assert.deepStrictEqual(context.traceState, undefined); span.end(); @@ -186,14 +186,60 @@ describe('BasicTracerProvider', () => { const state = new TraceState('a=1,b=2'); const span = tracer.startSpan('my-span', { parent: { - traceId: 'd4cda95b652f4a1592b449d5929fda1b', - spanId: '6e0c63257de34c92', + traceId: new Uint8Array([ + 0xd4, + 0xcd, + 0xa9, + 0x5b, + 0x65, + 0x2f, + 0x4a, + 0x15, + 0x92, + 0xb4, + 0x49, + 0xd5, + 0x92, + 0x9f, + 0xda, + 0x1b, + ]), + spanId: new Uint8Array([ + 0x6e, + 0x0c, + 0x63, + 0x25, + 0x7d, + 0xe3, + 0x4c, + 0x92, + ]), traceState: state, }, }); assert.ok(span instanceof Span); const context = span.context(); - assert.strictEqual(context.traceId, 'd4cda95b652f4a1592b449d5929fda1b'); + assert.deepStrictEqual( + context.traceId, + new Uint8Array([ + 0xd4, + 0xcd, + 0xa9, + 0x5b, + 0x65, + 0x2f, + 0x4a, + 0x15, + 0x92, + 0xb4, + 0x49, + 0xd5, + 0x92, + 0x9f, + 0xda, + 0x1b, + ]) + ); assert.strictEqual(context.traceFlags, TraceFlags.SAMPLED); assert.deepStrictEqual(context.traceState, state); span.end(); @@ -223,12 +269,12 @@ describe('BasicTracerProvider', () => { it('should start a span with name and with invalid spancontext', () => { const tracer = new BasicTracerProvider().getTracer('default'); const span = tracer.startSpan('my-span', { - parent: { traceId: '0', spanId: '0' }, + parent: { traceId: new Uint8Array(16), spanId: new Uint8Array(8) }, }); assert.ok(span instanceof Span); const context = span.context(); - assert.ok(context.traceId.match(/[a-f0-9]{32}/)); - assert.ok(context.spanId.match(/[a-f0-9]{16}/)); + assert.strictEqual(context.traceId.byteLength, 16); + assert.strictEqual(context.spanId.byteLength, 8); assert.strictEqual(context.traceFlags, TraceFlags.SAMPLED); assert.deepStrictEqual(context.traceState, undefined); }); @@ -241,8 +287,8 @@ describe('BasicTracerProvider', () => { const span = tracer.startSpan('my-span'); assert.ok(span instanceof NoRecordingSpan); const context = span.context(); - assert.ok(context.traceId.match(/[a-f0-9]{32}/)); - assert.ok(context.spanId.match(/[a-f0-9]{16}/)); + assert.strictEqual(context.traceId.byteLength, 16); + assert.strictEqual(context.spanId.byteLength, 8); assert.strictEqual(context.traceFlags, TraceFlags.UNSAMPLED); assert.deepStrictEqual(context.traceState, undefined); span.end(); diff --git a/packages/opentelemetry-tracing/test/Span.test.ts b/packages/opentelemetry-tracing/test/Span.test.ts index 7c56dc5e713..db915498c2d 100644 --- a/packages/opentelemetry-tracing/test/Span.test.ts +++ b/packages/opentelemetry-tracing/test/Span.test.ts @@ -38,8 +38,25 @@ describe('Span', () => { }).getTracer('default'); const name = 'span1'; const spanContext: SpanContext = { - traceId: 'd4cda95b652f4a1592b449d5929fda1b', - spanId: '6e0c63257de34c92', + traceId: new Uint8Array([ + 0xd4, + 0xcd, + 0xa9, + 0x5b, + 0x65, + 0x2f, + 0x4a, + 0x15, + 0x92, + 0xb4, + 0x49, + 0xd5, + 0x92, + 0x9f, + 0xda, + 0x1b, + ]), + spanId: new Uint8Array([0x6e, 0x0c, 0x63, 0x25, 0x7d, 0xe3, 0x4c, 0x92]), traceFlags: TraceFlags.SAMPLED, }; @@ -135,7 +152,7 @@ describe('Span', () => { assert.strictEqual(context.traceId, spanContext.traceId); assert.strictEqual(context.traceFlags, TraceFlags.SAMPLED); assert.strictEqual(context.traceState, undefined); - assert.ok(context.spanId.match(/[a-f0-9]{16}/)); + assert.strictEqual(context.spanId.byteLength, 8); assert.ok(span.isRecording()); span.end(); }); @@ -165,15 +182,36 @@ describe('Span', () => { it('should set a link', () => { const spanContext: SpanContext = { - traceId: 'a3cda95b652f4a1592b449d5929fda1b', - spanId: '5e0c63257de34c92', + traceId: new Uint8Array([ + 0xa3, + 0xcd, + 0xa9, + 0x5b, + 0x65, + 0x2f, + 0x4a, + 0x15, + 0x92, + 0xb4, + 0x49, + 0xd5, + 0x92, + 0x9f, + 0xda, + 0x1b, + ]), + spanId: new Uint8Array([0x5e, 0x0c, 0x63, 0x25, 0x7d, 0xe3, 0x4c, 0x92]), traceFlags: TraceFlags.SAMPLED, }; const attributes = { attr1: 'value', attr2: 123, attr3: true }; - const span = new Span(tracer, name, spanContext, SpanKind.CLIENT, '12345', [ - { spanContext }, - { spanContext, attributes }, - ]); + const span = new Span( + tracer, + name, + spanContext, + SpanKind.CLIENT, + new Uint8Array([0x12, 0x34, 0x50]), + [{ spanContext }, { spanContext, attributes }] + ); span.end(); }); @@ -202,7 +240,16 @@ describe('Span', () => { }); it('should return ReadableSpan', () => { - const parentId = '5c1c63257de34c67'; + const parentId = new Uint8Array([ + 0x5c, + 0x1c, + 0x63, + 0x25, + 0x7d, + 0xe3, + 0x4c, + 0x67, + ]); const span = new Span( tracer, 'my-span', diff --git a/packages/opentelemetry-tracing/test/export/SimpleSpanProcessor.test.ts b/packages/opentelemetry-tracing/test/export/SimpleSpanProcessor.test.ts index ad4b3f6d514..560c0a4bb8f 100644 --- a/packages/opentelemetry-tracing/test/export/SimpleSpanProcessor.test.ts +++ b/packages/opentelemetry-tracing/test/export/SimpleSpanProcessor.test.ts @@ -38,8 +38,34 @@ describe('SimpleSpanProcessor', () => { it('should handle span started and ended when SAMPLED', () => { const processor = new SimpleSpanProcessor(exporter); const spanContext: SpanContext = { - traceId: 'a3cda95b652f4a1592b449d5929fda1b', - spanId: '5e0c63257de34c92', + traceId: new Uint8Array([ + 0xa3, + 0xcd, + 0xa9, + 0x5b, + 0x65, + 0x2f, + 0x4a, + 0x15, + 0x92, + 0xb4, + 0x49, + 0xd5, + 0x92, + 0x9f, + 0xda, + 0x1b, + ]), + spanId: new Uint8Array([ + 0x5e, + 0x0c, + 0x63, + 0x25, + 0x7d, + 0xe3, + 0x4c, + 0x92, + ]), traceFlags: TraceFlags.SAMPLED, }; const span = new Span( @@ -61,8 +87,34 @@ describe('SimpleSpanProcessor', () => { it('should handle span started and ended when UNSAMPLED', () => { const processor = new SimpleSpanProcessor(exporter); const spanContext: SpanContext = { - traceId: 'a3cda95b652f4a1592b449d5929fda1b', - spanId: '5e0c63257de34c92', + traceId: new Uint8Array([ + 0xa3, + 0xcd, + 0xa9, + 0x5b, + 0x65, + 0x2f, + 0x4a, + 0x15, + 0x92, + 0xb4, + 0x49, + 0xd5, + 0x92, + 0x9f, + 0xda, + 0x1b, + ]), + spanId: new Uint8Array([ + 0x5e, + 0x0c, + 0x63, + 0x25, + 0x7d, + 0xe3, + 0x4c, + 0x92, + ]), traceFlags: TraceFlags.UNSAMPLED, }; const span = new Span(