UNPKG

@splunk/otel

Version:

The Splunk distribution of OpenTelemetry Node Instrumentation provides a Node agent that automatically instruments your Node application to capture and report distributed traces to Splunk APM.

168 lines 6.4 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.encode = exports.serialize = exports.StringTable = void 0; exports.serializeHeapProfile = serializeHeapProfile; /* * Copyright Splunk Inc. * * 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 * * http://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. */ const zlib_1 = require("zlib"); const util_1 = require("util"); const profile_1 = require("./proto/profile"); const gzipPromise = (0, util_1.promisify)(zlib_1.gzip); class StringTable { constructor() { this._stringMap = new Map(); this.getIndex(''); } getIndex(str) { let idx = this._stringMap.get(str); if (idx !== undefined) { return idx; } idx = this._stringMap.size; this._stringMap.set(str, idx); return idx; } serialize() { return [...this._stringMap.keys()]; } } exports.StringTable = StringTable; class Serializer { constructor() { this.stringTable = new StringTable(); this.locationsMap = new Map(); this.functionsMap = new Map(); } getLocation(fileName, functionName, lineNumber) { const key = `${fileName}:${functionName}:${lineNumber}`; let location = this.locationsMap.get(key); if (!location) { location = new profile_1.perftools.profiles.Location({ id: this.locationsMap.size + 1, line: [this.getLine(fileName, functionName, lineNumber)], }); this.locationsMap.set(key, location); } return location; } getFunction(fileName, functionName) { const key = `${fileName}:${functionName}`; let fun = this.functionsMap.get(key); if (!fun) { const functionNameId = this.stringTable.getIndex(functionName); fun = new profile_1.perftools.profiles.Function({ id: this.functionsMap.size + 1, name: functionNameId, systemName: functionNameId, filename: this.stringTable.getIndex(fileName), }); this.functionsMap.set(key, fun); } return fun; } getLine(fileName, functionName, lineNumber) { return new profile_1.perftools.profiles.Line({ functionId: this.getFunction(fileName, functionName).id, line: lineNumber !== 0 ? lineNumber : -1, }); } serializeHeapProfile(profile) { const SOURCE_EVENT_TIME = this.stringTable.getIndex('source.event.time'); const label = [{ key: SOURCE_EVENT_TIME, num: profile.timestamp }]; const sample = []; const { samples, treeMap } = profile; for (const s of samples) { let node = treeMap[s.nodeId]; const path = []; while (node !== undefined) { const location = this.getLocation(node.scriptName, node.name, node.lineNumber); path.push(location.id); node = treeMap[node.parentId]; } sample.push({ locationId: path, value: [s.size], label, }); } return profile_1.perftools.profiles.Profile.create({ sample, location: [...this.locationsMap.values()], function: [...this.functionsMap.values()], stringTable: this.stringTable.serialize(), }); } serializeCpuProfile(profile, options) { const { stacktraces } = profile; const STR = { TIMESTAMP: this.stringTable.getIndex('source.event.time'), TRACE_ID: this.stringTable.getIndex('trace_id'), SPAN_ID: this.stringTable.getIndex('span_id'), SOURCE_EVENT_PERIOD: this.stringTable.getIndex('source.event.period'), }; const eventPeriodLabel = new profile_1.perftools.profiles.Label({ key: STR.SOURCE_EVENT_PERIOD, num: options.samplingPeriodMillis, }); const samples = stacktraces.map(({ stacktrace, timestamp, spanId, traceId }) => { const labels = [ new profile_1.perftools.profiles.Label({ key: STR.TIMESTAMP, num: Number(BigInt(timestamp) / BigInt(1000000)), }), eventPeriodLabel, ]; if (traceId) { labels.push(new profile_1.perftools.profiles.Label({ key: STR.TRACE_ID, str: this.stringTable.getIndex(traceId.toString('hex')), })); } if (spanId) { labels.push(new profile_1.perftools.profiles.Label({ key: STR.SPAN_ID, str: this.stringTable.getIndex(spanId.toString('hex')), })); } return new profile_1.perftools.profiles.Sample({ locationId: stacktrace.map(([fileName, functionName, lineNumber]) => { return this.getLocation(fileName, functionName, lineNumber).id; }), value: [], label: labels, }); }); return profile_1.perftools.profiles.Profile.create({ sample: samples, location: [...this.locationsMap.values()], function: [...this.functionsMap.values()], stringTable: this.stringTable.serialize(), }); } } const serialize = (profile, options) => { return new Serializer().serializeCpuProfile(profile, options); }; exports.serialize = serialize; function serializeHeapProfile(profile) { return new Serializer().serializeHeapProfile(profile); } const encode = async function encode(profile) { const buffer = profile_1.perftools.profiles.Profile.encode(profile).finish(); return gzipPromise(buffer); }; exports.encode = encode; //# sourceMappingURL=utils.js.map