@ogcio/o11y-sdk-node
Version:
Opentelemetry standard instrumentation SDK for NodeJS based project
61 lines (60 loc) • 3.17 kB
JavaScript
import { OnEndingHookSpanProcessor } from "./on-ending-hook-span-processor.js";
const PROFILING_ATTRIBUTE_PREFIX = "profiling";
/**
* A SpanProcessor that captures pseudo-profiling data (CPU time and memory usage)
* for each span and adds them as span attributes.
*
* This processor wraps the span's end() method to capture profiling metrics
* just before the span is marked as ended, while the span is still writable.
*/
export class PseudoProfilingSpanProcessor extends OnEndingHookSpanProcessor {
_spanProfilingData = new WeakMap();
onStart(span, _context) {
super.onStart(span, _context);
const cpuUsageStart = process.cpuUsage();
const memoryUsageStart = process.memoryUsage();
// Store profiling data
this._spanProfilingData.set(span, {
cpuUsageStart,
memoryUsageStart,
});
}
onEnding(span) {
this._captureProfilingData(span);
}
/**
* Captures profiling data and sets attributes on the span.
* Called just before the span is ended, while it's still writable.
*/
_captureProfilingData(span) {
const profilingData = this._spanProfilingData.get(span);
if (!profilingData) {
return;
}
const { cpuUsageStart, memoryUsageStart } = profilingData;
const cpuUsageEnd = process.cpuUsage(cpuUsageStart);
const memoryUsageEnd = process.memoryUsage();
const memoryDelta = {
heapUsed: memoryUsageEnd.heapUsed - memoryUsageStart.heapUsed,
heapTotal: memoryUsageEnd.heapTotal - memoryUsageStart.heapTotal,
external: memoryUsageEnd.external - memoryUsageStart.external,
rss: memoryUsageEnd.rss - memoryUsageStart.rss,
arrayBuffers: memoryUsageEnd.arrayBuffers - memoryUsageStart.arrayBuffers,
};
// CPU time in microseconds
span.setAttribute(`${PROFILING_ATTRIBUTE_PREFIX}.cpu.user_time_us`, cpuUsageEnd.user);
span.setAttribute(`${PROFILING_ATTRIBUTE_PREFIX}.cpu.system_time_us`, cpuUsageEnd.system);
span.setAttribute(`${PROFILING_ATTRIBUTE_PREFIX}.cpu.total_time_us`, cpuUsageEnd.user + cpuUsageEnd.system);
// Memory delta in bytes
span.setAttribute(`${PROFILING_ATTRIBUTE_PREFIX}.memory.heap_used_delta_bytes`, memoryDelta.heapUsed);
span.setAttribute(`${PROFILING_ATTRIBUTE_PREFIX}.memory.heap_total_delta_bytes`, memoryDelta.heapTotal);
span.setAttribute(`${PROFILING_ATTRIBUTE_PREFIX}.memory.external_delta_bytes`, memoryDelta.external);
span.setAttribute(`${PROFILING_ATTRIBUTE_PREFIX}.memory.rss_delta_bytes`, memoryDelta.rss);
span.setAttribute(`${PROFILING_ATTRIBUTE_PREFIX}.memory.array_buffers_delta_bytes`, memoryDelta.arrayBuffers);
// Absolute memory values at span end (useful for overall monitoring)
span.setAttribute(`${PROFILING_ATTRIBUTE_PREFIX}.memory.heap_used_bytes`, memoryUsageEnd.heapUsed);
span.setAttribute(`${PROFILING_ATTRIBUTE_PREFIX}.memory.heap_total_bytes`, memoryUsageEnd.heapTotal);
// Clean up the WeakMap entry
this._spanProfilingData.delete(span);
}
}