UNPKG

newrelic

Version:
109 lines (94 loc) 3.09 kB
/* * Copyright 2026 New Relic Corporation. All rights reserved. * SPDX-License-Identifier: Apache-2.0 */ 'use strict' const logger = require('../logger').child({ component: 'pprof_aggregator' }) const BaseAggregator = require('./base-aggregator') const ProfilingManager = require('#agentlib/profiling/index.js') /** * Serves as a means for transmitting pprof data as it is being collected. * This doesn't really work as an "aggregator". It instead leverages the `BaseAggregator` * to integrate with the `Harvester` and `Collector` * * The `ProfilingAggregator` aggregator overrides the base `start` method. * It sets up the interval based on configuration but instead of calling `send`, * it calls `collectData` which instructs the Profiler to collect profiling data * for every registered profiler(cpu, heap at the moment if enabled) * * @private * @class */ class ProfilingAggregator extends BaseAggregator { constructor(opts = {}, agent) { const { collector, harvester } = agent opts.method = opts.method || 'pprof_data' super(opts, collector, harvester) this.agent = agent this.profilingManager = new ProfilingManager({ agent, samplingInterval: opts.periodMs }) this.pprofData = null } // simply returns what was given from the profiler collect method _toPayloadSync() { return this.pprofData } /** * This overrides the default `start` method * as we want to collect profiling data for `cpu` and/or `heap` * and send the gzipped binary encoded data for each profiler */ start() { this.profilingManager.register() const started = this.profilingManager.start() if (!started) { return } logger.trace(`${this.method} aggregator started.`) if (!this.sendTimer) { this.sendTimer = setInterval(this.collectData.bind(this), this.periodMs) this.sendTimer.unref() } } /** * This overrides the default `stop` method * as we want to clear the setInterval but also stop * all the registered profilers */ stop() { super.stop() this.profilingManager.stop() } /** * Called on an interval. Iterates over all registered profilers * and collects data for the given time period. Then asynchronously * calls send which takes care of sending the data to the collector */ async collectData() { let profilingData = [] try { profilingData = await this.profilingManager.collect() } catch (err) { logger.error(err, 'Failed to collect profiling data') } for (const pprofData of profilingData) { if (pprofData) { this.pprofData = pprofData this.send() } } } // `pprof_data` is not retained/merged in any way to just return null _getMergeData() { return null } // this implies the transmission fails // we log this error in `lib/collector/api.js#_handleResponseCode` _merge() { return null } // clears the `this.pprofData` for the next iteration of profiling collection clear() { this.pprofData = null } } module.exports = ProfilingAggregator