Skip to content

Commit

Permalink
Add BinaryFormat interface and implementation (#74)
Browse files Browse the repository at this point in the history
* Add BinaryFormat interface and implementation

* Incorporate newly added TraceOptions & merge master

* Use ArrayBuffer instead of Buffer
  • Loading branch information
mayurkale22 authored Jul 12, 2019
1 parent fbd291b commit 5870457
Show file tree
Hide file tree
Showing 4 changed files with 291 additions and 0 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
/**
* Copyright 2019, OpenTelemetry Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

import { BinaryFormat, SpanContext, TraceOptions } from '@opentelemetry/types';

const VERSION_ID = 0;
const TRACE_ID_FIELD_ID = 0;
const SPAN_ID_FIELD_ID = 1;
const TRACE_OPTION_FIELD_ID = 2;

// Sizes are number of bytes.
const ID_SIZE = 1;
const TRACE_ID_SIZE = 16;
const SPAN_ID_SIZE = 8;
const TRACE_OPTION_SIZE = 1;

const VERSION_ID_OFFSET = 0;
const TRACE_ID_FIELD_ID_OFFSET = VERSION_ID_OFFSET + ID_SIZE;
const TRACE_ID_OFFSET = TRACE_ID_FIELD_ID_OFFSET + ID_SIZE;
const SPAN_ID_FIELD_ID_OFFSET = TRACE_ID_OFFSET + TRACE_ID_SIZE;
const SPAN_ID_OFFSET = SPAN_ID_FIELD_ID_OFFSET + ID_SIZE;
const TRACE_OPTION_FIELD_ID_OFFSET = SPAN_ID_OFFSET + SPAN_ID_SIZE;
const TRACE_OPTIONS_OFFSET = TRACE_OPTION_FIELD_ID_OFFSET + ID_SIZE;

const FORMAT_LENGTH =
4 * ID_SIZE + TRACE_ID_SIZE + SPAN_ID_SIZE + TRACE_OPTION_SIZE;

export class BinaryTraceContext implements BinaryFormat {
toBytes(spanContext: SpanContext): Uint8Array {
/**
* 0 1 2
* 0 1 2345678901234567 8 90123456 7 8
* -------------------------------------
* | | | | | | | |
* -------------------------------------
* ^ ^ ^ ^ ^ ^ ^
* | | | | | | `-- options value
* | | | | | `---- options field ID (2)
* | | | | `---------- spanID value
* | | | `--------------- spanID field ID (1)
* | | `--------------------------- traceID value
* | `---------------------------------- traceID field ID (0)
* `------------------------------------ version (0)
*/
const traceId = spanContext.traceId;
const spanId = 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.traceOptions) || TraceOptions.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.
if (
buf[VERSION_ID_OFFSET] !== VERSION_ID ||
buf[TRACE_ID_FIELD_ID_OFFSET] !== TRACE_ID_FIELD_ID ||
buf[SPAN_ID_FIELD_ID_OFFSET] !== SPAN_ID_FIELD_ID ||
buf[TRACE_OPTION_FIELD_ID_OFFSET] !== TRACE_OPTION_FIELD_ID
) {
return null;
}
// 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.traceOptions = 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;
}
144 changes: 144 additions & 0 deletions packages/opentelemetry-core/test/context/BinaryTraceContext.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,144 @@
/**
* Copyright 2019, OpenTelemetry Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

import * as assert from 'assert';
import { BinaryTraceContext } from '../../src/context/propagation/BinaryTraceContext';
import { SpanContext, TraceOptions } from '@opentelemetry/types';

describe('BinaryTraceContext', () => {
const binaryTraceContext = new BinaryTraceContext();
const commonTraceId = 'd4cda95b652f4a1592b449d5929fda1b';
const commonSpanId = '75e8ed491aec7eca';

const testCases: Array<{
structured: SpanContext | null;
binary: Uint8Array;
description: string;
}> = [
{
structured: {
traceId: commonTraceId,
spanId: commonSpanId,
traceOptions: TraceOptions.SAMPLED,
},
binary: new Uint8Array([
0,
0,
212,
205,
169,
91,
101,
47,
74,
21,
146,
180,
73,
213,
146,
159,
218,
27,
1,
117,
232,
237,
73,
26,
236,
126,
202,
2,
1,
]),
description: 'span context with 64-bit span ID',
},
{
structured: { traceId: commonTraceId, spanId: commonSpanId },
binary: new Uint8Array([
0,
0,
212,
205,
169,
91,
101,
47,
74,
21,
146,
180,
73,
213,
146,
159,
218,
27,
1,
117,
232,
237,
73,
26,
236,
126,
202,
2,
0,
]),
description: 'span context with no traceOptions',
},
{
structured: null,
binary: new Uint8Array([0, 0]),
description: 'incomplete binary span context (by returning null)',
},
{
structured: null,
binary: new Uint8Array(58),
description: 'bad binary span context (by returning null)',
},
];

describe('toBytes', () => {
testCases.forEach(
testCase =>
testCase.structured &&
it(`should serialize ${testCase.description}`, () => {
assert.deepStrictEqual(
binaryTraceContext.toBytes(testCase.structured!),
testCase.binary
);
})
);
});

describe('fromBytes', () => {
testCases.forEach(testCase =>
it(`should deserialize ${testCase.description}`, () => {
assert.deepStrictEqual(
binaryTraceContext.fromBytes(testCase.binary),
testCase.structured &&
Object.assign(
{ traceOptions: TraceOptions.UNSAMPLED },
testCase.structured
)
);
})
);
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
/**
* Copyright 2019, OpenTelemetry Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

import { SpanContext } from '../../trace/span_context';

/**
* Formatter to serializing and deserializing a value with into a binary format.
*/
export interface BinaryFormat {
/**
* Serialize the given span context into a Buffer.
* @param spanContext The span context to serialize.
*/
toBytes(spanContext: SpanContext): ArrayBuffer;

/**
* Deseralize the given span context from binary encoding. If the input is a
* Buffer of incorrect size or unexpected fields, then this function will
* return `null`.
* @param buffer The span context to deserialize.
*/
fromBytes(buffer: ArrayBuffer): SpanContext | null;
}
1 change: 1 addition & 0 deletions packages/opentelemetry-types/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
*/

export * from './common/Logger';
export * from './context/propagation/BinaryFormat';
export * from './context/propagation/Propagator';
export * from './distributed_context/DistributedContext';
export * from './distributed_context/EntryValue';
Expand Down

0 comments on commit 5870457

Please sign in to comment.