@nearform/heap-profiler
Version:
Heap dump, sample profiler and allocation timeline generator for Node.
90 lines (72 loc) • 2.05 kB
JavaScript
const { Session } = require('inspector')
const SonicBoom = require('sonic-boom')
const { ensurePromiseCallback, destinationFile, validateDestinationFile } = require('./utils')
module.exports = function generateHeapSnapshot(options, cb) {
/* istanbul ignore if */
if (typeof options === 'function') {
cb = options
options = null
}
// Prepare the context
const [callback, promise] = ensurePromiseCallback(cb)
const { destination, runGC } = Object.assign({ destination: destinationFile('heapsnapshot'), runGC: false }, options)
const session = new Session()
let error = null
let handled = false
if (typeof destination !== 'string' || destination.length === 0) {
throw new Error('The destination option must be a non empty string')
}
validateDestinationFile(destination, err => {
if (err) {
return callback(err)
}
const writer = new SonicBoom({ dest: destination })
function onWriterEnd(err) {
/* istanbul ignore if */
if (handled) {
return
}
handled = true
session.disconnect()
callback(err || error, destination)
}
writer.on('error', onWriterEnd)
writer.on('close', onWriterEnd)
if (runGC && typeof global.gc === 'function') {
try {
global.gc()
} catch (e) {
error = e
writer.end()
return promise
}
}
// Start the session
session.connect()
// Prepare chunk appending
session.on('HeapProfiler.addHeapSnapshotChunk', m => {
// A write failed, discard all the rest
/* istanbul ignore if */
if (error) {
return
}
try {
writer.write(m.params.chunk)
} catch (e) {
/* istanbul ignore next */
error = e
}
})
// Request heap snapshot
session.post('HeapProfiler.takeHeapSnapshot', null, (err, r) => {
/* istanbul ignore next */
if (err && !error) {
error = err
}
// Cleanup
writer.end()
})
})
return promise
}