UNPKG

dd-trace

Version:

Datadog APM tracing client for JavaScript

115 lines (96 loc) 3.45 kB
'use strict' const { normalizeSpan } = require('./tags-processors') const { AgentEncoder: BaseEncoder, stringifySpanEvents } = require('./0.4') const ARRAY_OF_TWO = 0x92 const ARRAY_OF_TWELVE = 0x9C function formatSpan (span) { span = normalizeSpan(span) // v0.5 has no native span_events slot; always serialize as a meta tag. if (span.span_events) { span.meta.events = stringifySpanEvents(span.span_events) // `= undefined` over `delete` to keep the span's hidden class. span.span_events = undefined } return span } class AgentEncoder extends BaseEncoder { makePayload () { const prefixSize = 1 const stringSize = this._stringBytes.length + 5 const traceSize = this._traceBytes.length + 5 const buffer = Buffer.allocUnsafe(prefixSize + stringSize + traceSize) buffer[0] = ARRAY_OF_TWO const offset = this._writeStrings(buffer, 1) this._writeTraces(buffer, offset) this._reset() return buffer } _encode (bytes, trace) { this._encodeArrayPrefix(bytes, trace) for (let span of trace) { span = formatSpan(span) this._encodeByte(bytes, ARRAY_OF_TWELVE) this._encodeString(bytes, span.service) this._encodeString(bytes, span.name) this._encodeString(bytes, span.resource) this._encodeId(bytes, span.trace_id) this._encodeId(bytes, span.span_id) this._encodeId(bytes, span.parent_id) this._encodeIntOrFloat(bytes, span.start || 0) this._encodeIntOrFloat(bytes, span.duration || 0) this._encodeIntOrFloat(bytes, span.error) this._encodeMap(bytes, span.meta || {}) this._encodeMap(bytes, span.metrics || {}) this._encodeString(bytes, span.type) } } // Override the inherited 0.4 `_encodeMap` so the v0.5 wire emits each numeric // value via `_encodeIntOrFloat` (compact unsigned/signed int when integer, // float64 otherwise) instead of always float64. The 0.4 base method stays on // float64 because the CI-visibility encoders inherit it and target a // different intake. _encodeMap (bytes, value) { const offset = bytes.length bytes.reserve(5) bytes.buffer[offset] = 0xDF let count = 0 for (const key of Object.keys(value)) { const entryValue = value[key] if (typeof entryValue === 'string') { this._encodeString(bytes, key) this._encodeString(bytes, entryValue) count++ } else if (typeof entryValue === 'number') { this._encodeString(bytes, key) this._encodeIntOrFloat(bytes, entryValue) count++ } } const target = bytes.buffer target[offset + 1] = count >>> 24 target[offset + 2] = count >>> 16 target[offset + 3] = count >>> 8 target[offset + 4] = count } _encodeString (bytes, value = '') { let index = this._stringMap[value] if (index === undefined) { index = this._stringCount++ this._stringMap[value] = index this._stringBytes.write(value) } this._encodeInteger(bytes, index) } _cacheString (value) { if (this._stringMap[value] === undefined) { this._stringMap[value] = this._stringCount++ this._stringBytes.write(value) } } _writeStrings (buffer, offset) { offset = this._writeArrayPrefix(buffer, offset, this._stringCount) offset += this._stringBytes.buffer.copy(buffer, offset, 0, this._stringBytes.length) return offset } } module.exports = { AgentEncoder }