Skip to content

Commit 7bac95e

Browse files
author
Stephen Belanger
committed
feat(context): create trace context class
1 parent fb19268 commit 7bac95e

File tree

2 files changed

+175
-0
lines changed

2 files changed

+175
-0
lines changed

lib/instrumentation/context.js

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
const crypto = require('crypto')
2+
3+
function fromHex (hex) {
4+
return Buffer.from(hex, 'hex')
5+
}
6+
7+
function toHex (buffer) {
8+
return buffer.toString('hex')
9+
}
10+
11+
class TraceContext {
12+
constructor (opts = {}) {
13+
// 1 byte
14+
this.version = opts.version
15+
// 16 bytes
16+
this.traceId = opts.traceId
17+
// 8 bytes
18+
this.id = opts.id
19+
// 1 byte
20+
this.flags = opts.flags
21+
// 8 bytes
22+
this.parentId = opts.parentId
23+
}
24+
25+
static create () {
26+
const bytes = crypto.randomBytes(24)
27+
28+
return new TraceContext({
29+
version: Buffer.alloc(1),
30+
traceId: bytes.slice(0, 16),
31+
id: bytes.slice(16),
32+
flags: Buffer.alloc(1)
33+
})
34+
}
35+
36+
static fromString (header) {
37+
const [
38+
version,
39+
traceId,
40+
id,
41+
flags
42+
] = header.split('-').map(fromHex)
43+
44+
return new TraceContext({
45+
version,
46+
traceId,
47+
id,
48+
flags
49+
})
50+
}
51+
52+
child () {
53+
const { version, traceId, id: parentId, flags } = this
54+
const id = crypto.randomBytes(8)
55+
56+
return new TraceContext({
57+
version,
58+
traceId,
59+
id,
60+
flags,
61+
parentId
62+
})
63+
}
64+
65+
toString () {
66+
const parts = [
67+
this.version,
68+
this.traceId,
69+
this.id,
70+
this.flags
71+
]
72+
73+
return parts.map(toHex).join('-')
74+
}
75+
76+
toJSON () {
77+
return {
78+
version: this.version.toString('hex'),
79+
traceId: this.traceId.toString('hex'),
80+
id: this.id.toString('hex'),
81+
flags: this.flags.toString('hex'),
82+
parentId: this.parentId && this.parentId.toString('hex')
83+
}
84+
}
85+
}
86+
87+
module.exports = TraceContext

test/instrumentation/context.js

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
'use strict'
2+
3+
const crypto = require('crypto')
4+
const test = require('tape')
5+
6+
const TraceContext = require('../../lib/instrumentation/context')
7+
8+
const version = Buffer.alloc(1)
9+
const traceId = crypto.randomBytes(16)
10+
const id = crypto.randomBytes(8)
11+
const flags = Buffer.alloc(1)
12+
13+
const header = `00-${traceId.toString('hex')}-${id.toString('hex')}-00`
14+
15+
test('constructor', t => {
16+
const context = new TraceContext({
17+
version,
18+
traceId,
19+
id,
20+
flags
21+
})
22+
23+
t.ok(context instanceof TraceContext, 'has a trace context object')
24+
t.ok(version.equals(context.version), 'version matches')
25+
t.ok(traceId.equals(context.traceId), 'traceId matches')
26+
t.ok(id.equals(context.id), 'id matches')
27+
t.ok(flags.equals(context.flags), 'flags matches')
28+
29+
t.end()
30+
})
31+
32+
test('fromString', t => {
33+
const context = TraceContext.fromString(header)
34+
35+
t.ok(context instanceof TraceContext, 'has a trace context object')
36+
t.ok(version.equals(context.version), 'version matches')
37+
t.ok(traceId.equals(context.traceId), 'traceId matches')
38+
t.ok(id.equals(context.id), 'id matches')
39+
t.ok(flags.equals(context.flags), 'flags matches')
40+
41+
t.end()
42+
})
43+
44+
test('toString', t => {
45+
const result = TraceContext.fromString(header).toString()
46+
t.equal(result, header, 'trace context stringifies to valid header')
47+
t.end()
48+
})
49+
50+
test('toJSON', t => {
51+
const context = TraceContext.fromString(header)
52+
53+
t.deepEqual(context.toJSON(), {
54+
version: version.toString('hex'),
55+
traceId: traceId.toString('hex'),
56+
id: id.toString('hex'),
57+
flags: flags.toString('hex'),
58+
parentId: undefined
59+
}, 'trace context serializes fields to hex strings, in JSON form')
60+
61+
t.end()
62+
})
63+
64+
test('create', t => {
65+
const context = TraceContext.create()
66+
67+
t.ok(context instanceof TraceContext, 'has a trace context object')
68+
t.ok(version.equals(context.version), 'version matches')
69+
t.notOk(traceId.equals(context.traceId), 'has new traceId')
70+
t.notOk(id.equals(context.id), 'has new spanId')
71+
t.ok(flags.equals(context.flags), 'flags matches')
72+
73+
t.end()
74+
})
75+
76+
test('child', t => {
77+
const parent = TraceContext.fromString(header)
78+
const context = parent.child()
79+
80+
t.ok(context instanceof TraceContext, 'has a trace context object')
81+
t.ok(version.equals(context.version), 'version matches')
82+
t.ok(traceId.equals(context.traceId), 'traceId matches')
83+
t.notOk(id.equals(context.id), 'has new id')
84+
t.ok(flags.equals(context.flags), 'flags matches')
85+
t.ok(parent.id.equals(context.parentId), 'parentId matches parent.id')
86+
87+
t.end()
88+
})

0 commit comments

Comments
 (0)