Tumortisch-Dist/resources/app/node_modules/electron-process-reporter/lib/index.js
2021-06-15 16:00:08 +02:00

150 lines
5.9 KiB
JavaScript

"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const electron_1 = require("electron");
const memoize = require("memoizee");
// @ts-ignore: no declaration file
const pidtree = require("pidtree");
// @ts-ignore: no declaration file
const pidusage = require("pidusage");
const rxjs_1 = require("rxjs");
const extractURLDomain_1 = require("./extractURLDomain");
exports.getAppUsage = (pid) => {
return pidtree(pid, { root: true })
.then(pidusage)
.then((usages) => Object.values(usages).filter(Boolean));
};
let getSharedProcessMetricsPollerByPid = (pid, samplingInterval) => rxjs_1.Observable.timer(0, samplingInterval)
.map(() => rxjs_1.Observable.fromPromise(exports.getAppUsage(pid)))
.mergeAll()
.share();
getSharedProcessMetricsPollerByPid = memoize(getSharedProcessMetricsPollerByPid);
let getSharedProcessMetricsPollerByApp = (app, samplingInterval) => rxjs_1.Observable.timer(0, samplingInterval)
.map(() => app.getAppMetrics())
.share();
getSharedProcessMetricsPollerByApp = memoize(getSharedProcessMetricsPollerByApp);
/**
* Returns an Observable that emits Electron.ProcessMetric[] on a regular interval.
*
* For a given `app` and a given `samplingInterval`, the returned observable is shared
* for performance reasons.
*
* options.samplingInterval = 1000 (1s) by default
* @param app
* @param options
*/
exports.onProcessMetrics = (app, options) => {
options = Object.assign({ samplingInterval: 1000 }, options);
return getSharedProcessMetricsPollerByApp(app, options.samplingInterval);
};
/**
* Returns an Rx.Observable that emits `PidUsage[]` every `options.samplingInterval` ms.
*
* For a given `pid` and a given `samplingInterval`, the returned observable is shared
* for performance reasons.
* `pid` is the root of the process tree.
*
* @param pid
* @param {object} options
* @param {number} options.samplingInterval - 1000 (1s) by default
*
* @example
* - pid: main process
* - rendererPid1: renderer process
* - rendererPid2: renderer process
*/
exports.onProcessTreeMetricsForPid = (pid, options) => {
options = Object.assign({ samplingInterval: 1000 }, options);
return getSharedProcessMetricsPollerByPid(pid, options.samplingInterval);
};
const getExtendedAppMetrics = (appMetrics) => {
const allWebContents = electron_1.webContents.getAllWebContents();
const webContentsInfo = allWebContents.map((wc) => ({
type: wc.getType(),
id: wc.id,
pid: wc.getOSProcessId(),
URL: wc.getURL(),
URLDomain: extractURLDomain_1.default(wc.getURL()),
}));
return appMetrics.map(proc => {
const report = proc;
const wc = webContentsInfo.find(wc => wc.pid === proc.pid);
if (!wc)
return report;
report.webContents = [wc];
return report;
});
};
/**
* Returns an Rx.Observable that emits reports of `ExtendedProcessMetric`
* every `options.samplingInterval` ms.
*
* Default `options.samplingInterval` = 1000ms
*
* Compared to `onProcessMetrics` it adds data on the `webContents` associated
* to the given process.
*
* @param app the electron app instance
* @param options
*/
exports.onExtendedProcessMetrics = (app, options = {}) => exports.onProcessMetrics(app, options).map(getExtendedAppMetrics);
/**
* Will emit an array of `PidUsage` when a process of the tree exceeds the
* `options.percentCPUUsageThreshold` on more than `options.samplesCount`
* samples.
* It monitors the whole tree of pids, starting from `childPid`.
* The reason behind this is that the `process.pid` of the main process is at the same
* level as all renderers.
* So we fetch their common ancestor, which is the `ppid` of the main process.
* The parent pid of `childPid` is not part of the end result
* (that way, we monitor the same processes as `getAppMetrics`).
*
* In opposite to onExcessiveCPUUsage, onExcessiveCPUUsageInProcessTree does not use
* Electron's internal measurement but rather use `pidusage`, a cross-platform
* process cpu % and memory usage of a PID. It is known to have lower pressure on CPU.
* Also, as this leverage `pidusage`, the measures on Windows can be considered
* as not accurate.
*
* Default `options.samplesCount` = 10
* Default `options.percentCPUUsageThreshold` = 80
*
* @param pid - the pid of the main process
* @param options
*/
exports.onExcessiveCPUUsageInProcessTree = (pid, options) => {
options = Object.assign({ samplesCount: 10, percentCPUUsageThreshold: 80 }, options);
return exports.onProcessTreeMetricsForPid(pid, options)
.map(appUsage => rxjs_1.Observable.from(appUsage))
.mergeAll()
.groupBy(appUsage => appUsage.pid)
.map(g => g.bufferCount(options.samplesCount))
.mergeAll()
.filter(processMetricsSamples => {
const excessiveSamplesCount = processMetricsSamples.filter(p => p.cpu >= options.percentCPUUsageThreshold).length;
return excessiveSamplesCount === processMetricsSamples.length;
});
};
/**
* Will emit an array `ExtendedProcessMetric` when a process exceeds the
* `options.percentCPUUsageThreshold` on more than `options.samplesCount`
* samples.
*
* Default `options.samplesCount` = 10
* Default `options.percentCPUUsageThreshold` = 80
*
* @param app the electron app instance
* @param options
*/
exports.onExcessiveCPUUsage = (app, options) => {
options = Object.assign({ samplesCount: 10, percentCPUUsageThreshold: 80 }, options);
return exports.onExtendedProcessMetrics(app, options)
.map(report => rxjs_1.Observable.from(report))
.mergeAll()
.groupBy(processMetric => processMetric.pid)
.map(g => g.bufferCount(options.samplesCount))
.mergeAll()
.filter(processMetricsSamples => {
const excessiveSamplesCount = processMetricsSamples.filter(p => p.cpu.percentCPUUsage >= options.percentCPUUsageThreshold).length;
return excessiveSamplesCount == processMetricsSamples.length;
});
};
//# sourceMappingURL=index.js.map