@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.
122 lines • 5.31 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.SnapshotProfiler = void 0;
exports.startSnapshotProfiling = startSnapshotProfiling;
exports.stopSnapshotProfiling = stopSnapshotProfiling;
exports.isSnapshotProfilingEnabled = isSnapshotProfilingEnabled;
exports.snapshotSpanProcessor = snapshotSpanProcessor;
exports.snapshotProfiler = snapshotProfiler;
const profiling_1 = require("../../profiling");
const utils_1 = require("../../utils");
const SnapshotSpanProcessor_1 = require("./SnapshotSpanProcessor");
const OtlpHttpProfilingExporter_1 = require("../../profiling/OtlpHttpProfilingExporter");
const profiling_2 = require("../../profiling");
// After the last snapshot has ended, keep the profiler running to avoid cold starts.
const LINGER_PERIOD_MS = 60000;
class SnapshotProfiler {
constructor(options) {
var _a;
this.extension = (0, profiling_2.loadExtension)() || (0, profiling_1.noopExtension)();
this.profilerHandle = -1;
// The number traces currently being profiled.
this.activeSnapshots = 0;
(0, profiling_1.ensureProfilingContextManager)();
this.processor = new SnapshotSpanProcessor_1.SnapshotSpanProcessor({
traceSnapshotBegin: (traceId) => {
this.extension.addTraceIdFilter(this.profilerHandle, traceId);
this.extension.startCpuProfiler(this.profilerHandle);
this.activeSnapshots += 1;
},
traceSnapshotEnd: (traceId) => {
this.activeSnapshots = Math.max(this.activeSnapshots - 1, 0);
this.extension.removeTraceIdFilter(this.profilerHandle, traceId);
if (this.stopTimeout !== undefined) {
clearTimeout(this.stopTimeout);
this.stopTimeout = undefined;
}
if (this.activeSnapshots === 0) {
this.stopTimeout = setTimeout(async () => {
const profile = this.extension.stop(this.profilerHandle);
await this._export(profile);
this.stopTimeout = undefined;
}, LINGER_PERIOD_MS);
this.stopTimeout.unref();
}
},
});
const samplingIntervalMicroseconds = options.samplingIntervalMs * 1000;
this.profilerHandle =
(_a = this.extension.createCpuProfiler({
name: 'splunk-snapshot-profiler',
samplingIntervalMicroseconds,
maxSampleCutoffDelayMicroseconds: samplingIntervalMicroseconds / 2,
recordDebugInfo: false,
onlyFilteredStacktraces: true,
})) !== null && _a !== void 0 ? _a : -1;
this.collectionLoop = setInterval(async () => {
const profile = this.extension.collect(this.profilerHandle);
await this._export(profile);
}, options.collectionIntervalMs);
this.collectionLoop.unref();
process.on('exit', () => {
this.extension.stop(this.profilerHandle);
});
// Tracing needs to be started after profiling, setting up the profiling exporter
// causes @grpc/grpc-js to be loaded, but to avoid any loads before tracing's setup
// has finished, load it next event loop.
setImmediate(() => {
this.exporter = new OtlpHttpProfilingExporter_1.OtlpHttpProfilingExporter({
endpoint: options.endpoint,
callstackInterval: options.samplingIntervalMs,
resource: options.resource,
instrumentationSource: 'snapshot',
});
});
}
async _export(profile) {
if (!profile || !this.exporter) {
return;
}
if (profile.stacktraces.length > 0) {
await this.exporter.send(profile);
}
}
async stop() {
clearTimeout(this.stopTimeout);
clearInterval(this.collectionLoop);
const profile = this.extension.stop(this.profilerHandle);
if (profile) {
await this._export(profile);
}
}
}
exports.SnapshotProfiler = SnapshotProfiler;
let profiler;
function startSnapshotProfiling(options) {
var _a, _b;
const samplingIntervalMs = (_a = options.samplingIntervalMs) !== null && _a !== void 0 ? _a : (0, utils_1.getEnvNumber)('SPLUNK_SNAPSHOT_PROFILER_SAMPLING_INTERVAL', 1);
const collectionIntervalMs = (_b = options.collectionIntervalMs) !== null && _b !== void 0 ? _b : (0, utils_1.getEnvNumber)('SPLUNK_CPU_PROFILER_COLLECTION_INTERVAL', 30000);
profiler = new SnapshotProfiler({
serviceName: options.serviceName,
endpoint: options.endpoint,
resource: options.resource,
samplingIntervalMs,
collectionIntervalMs,
});
}
async function stopSnapshotProfiling() {
if (!profiler) {
return;
}
await profiler.stop();
}
function isSnapshotProfilingEnabled() {
return (0, utils_1.getEnvBoolean)('SPLUNK_SNAPSHOT_PROFILER_ENABLED', false);
}
function snapshotSpanProcessor() {
return profiler === null || profiler === void 0 ? void 0 : profiler.processor;
}
function snapshotProfiler() {
return profiler;
}
//# sourceMappingURL=Snapshots.js.map