Skip to content

Commit

Permalink
Add BinaryFormat interface and implementation
Browse files Browse the repository at this point in the history
  • Loading branch information
mayurkale22 committed Jul 1, 2019
1 parent 7b629d6 commit a9788a5
Show file tree
Hide file tree
Showing 4 changed files with 213 additions and 0 deletions.
@@ -0,0 +1,95 @@
/**
* 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 } 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): Buffer {
/**
* 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 result = Buffer.alloc(FORMAT_LENGTH, 0);
result.write(spanContext.traceId, TRACE_ID_OFFSET, TRACE_ID_SIZE, 'hex');
result.writeUInt8(SPAN_ID_FIELD_ID, SPAN_ID_FIELD_ID_OFFSET);
result.write(spanContext.spanId, SPAN_ID_OFFSET, SPAN_ID_SIZE, 'hex');
result.writeUInt8(TRACE_OPTION_FIELD_ID, TRACE_OPTION_FIELD_ID_OFFSET);
result.writeUInt8(
Number(spanContext.traceOptions) || 0,
TRACE_OPTIONS_OFFSET
);
return result;
}

fromBytes(buffer: Buffer): SpanContext | null {
const result: SpanContext = { traceId: '', spanId: '' };
// Length must be 29.
if (buffer.length !== FORMAT_LENGTH) {
return null;
}
// Check version and field numbers.
if (
buffer.readUInt8(VERSION_ID_OFFSET) !== VERSION_ID ||
buffer.readUInt8(TRACE_ID_FIELD_ID_OFFSET) !== TRACE_ID_FIELD_ID ||
buffer.readUInt8(SPAN_ID_FIELD_ID_OFFSET) !== SPAN_ID_FIELD_ID ||
buffer.readUInt8(TRACE_OPTION_FIELD_ID_OFFSET) !== TRACE_OPTION_FIELD_ID
) {
return null;
}
// See serializeSpanContext for byte offsets.
result.traceId = buffer
.slice(TRACE_ID_OFFSET, SPAN_ID_FIELD_ID_OFFSET)
.toString('hex');
result.spanId = buffer
.slice(SPAN_ID_OFFSET, TRACE_OPTION_FIELD_ID_OFFSET)
.toString('hex');
result.traceOptions = buffer.readUInt8(TRACE_OPTIONS_OFFSET);
return result;
}
}
@@ -0,0 +1,81 @@
/**
* 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 } from '@opentelemetry/types';

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

const testCases: Array<{
structured: SpanContext | null;
binary: string;
description: string;
}> = [
{
structured: {
traceId: commonTraceId,
spanId: commonSpanId,
traceOptions: 1,
},
binary: `0000${commonTraceId}01${commonSpanId}02${'01'}`,
description: 'span context with 64-bit span ID',
},
{
structured: { traceId: commonTraceId, spanId: commonSpanId },
binary: `0000${commonTraceId}01${commonSpanId}02${'00'}`,
description: 'span context with no traceOptions',
},
{
structured: null,
binary: '00',
description: 'incomplete binary span context (by returning null)',
},
{
structured: null,
binary: '0'.repeat(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!).toString('hex'),
testCase.binary
);
})
);
});

describe('fromBytes', () => {
testCases.forEach(testCase =>
it(`should deserialize ${testCase.description}`, () => {
assert.deepStrictEqual(
binaryTraceContext.fromBytes(Buffer.from(testCase.binary, 'hex')),
testCase.structured &&
Object.assign({ traceOptions: 0 }, testCase.structured)
);
})
);
});
});
@@ -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): Buffer;

/**
* 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: Buffer): SpanContext | null;
}
1 change: 1 addition & 0 deletions packages/opentelemetry-types/src/index.ts
Expand Up @@ -14,6 +14,7 @@
* limitations under the License.
*/

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 a9788a5

Please sign in to comment.