-
Notifications
You must be signed in to change notification settings - Fork 825
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add BinaryFormat interface and implementation (#74)
* Add BinaryFormat interface and implementation * Incorporate newly added TraceOptions & merge master * Use ArrayBuffer instead of Buffer
- Loading branch information
1 parent
fbd291b
commit 5870457
Showing
4 changed files
with
291 additions
and
0 deletions.
There are no files selected for viewing
110 changes: 110 additions & 0 deletions
110
packages/opentelemetry-core/src/context/propagation/BinaryTraceContext.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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
144
packages/opentelemetry-core/test/context/BinaryTraceContext.test.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 | ||
) | ||
); | ||
}) | ||
); | ||
}); | ||
}); |
36 changes: 36 additions & 0 deletions
36
packages/opentelemetry-types/src/context/propagation/BinaryFormat.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters