renovate
Version:
Automated dependency updates. Flexible so you don't need to be.
382 lines • 14 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.AbandonedPackageStats = exports.ObsoleteCacheHitLogger = exports.HttpCacheStats = exports.HttpStats = exports.DatasourceCacheStats = exports.PackageCacheStats = exports.LookupStats = void 0;
exports.makeTimingReport = makeTimingReport;
const tslib_1 = require("tslib");
const logger_1 = require("../logger");
const memCache = tslib_1.__importStar(require("./cache/memory"));
const url_1 = require("./url");
function makeTimingReport(data) {
const count = data.length;
const totalMs = data.reduce((a, c) => a + c, 0);
const avgMs = count ? Math.round(totalMs / count) : 0;
const maxMs = Math.max(0, ...data);
const sorted = data.sort((a, b) => a - b);
const medianMs = count ? sorted[Math.floor(count / 2)] : 0;
return { count, avgMs, medianMs, maxMs, totalMs };
}
class LookupStats {
static write(datasource, duration) {
const data = memCache.get('lookup-stats') ?? {};
data[datasource] ??= [];
data[datasource].push(duration);
memCache.set('lookup-stats', data);
}
static async wrap(datasource, callback) {
const start = Date.now();
const result = await callback();
const duration = Date.now() - start;
LookupStats.write(datasource, duration);
return result;
}
static getReport() {
const report = {};
const data = memCache.get('lookup-stats') ?? {};
for (const [datasource, durations] of Object.entries(data)) {
report[datasource] = makeTimingReport(durations);
}
return report;
}
static report() {
const report = LookupStats.getReport();
logger_1.logger.debug(report, 'Lookup statistics');
}
}
exports.LookupStats = LookupStats;
class PackageCacheStats {
static writeSet(duration) {
const data = memCache.get('package-cache-sets') ?? [];
data.push(duration);
memCache.set('package-cache-sets', data);
}
static async wrapSet(callback) {
const start = Date.now();
const result = await callback();
const duration = Date.now() - start;
PackageCacheStats.writeSet(duration);
return result;
}
static writeGet(duration) {
const data = memCache.get('package-cache-gets') ?? [];
data.push(duration);
memCache.set('package-cache-gets', data);
}
static async wrapGet(callback) {
const start = Date.now();
const result = await callback();
const duration = Date.now() - start;
PackageCacheStats.writeGet(duration);
return result;
}
static getReport() {
const packageCacheGets = memCache.get('package-cache-gets') ?? [];
const get = makeTimingReport(packageCacheGets);
const packageCacheSets = memCache.get('package-cache-sets') ?? [];
const set = makeTimingReport(packageCacheSets);
return { get, set };
}
static report() {
const report = PackageCacheStats.getReport();
logger_1.logger.debug(report, 'Package cache statistics');
}
}
exports.PackageCacheStats = PackageCacheStats;
/* eslint-enable @typescript-eslint/consistent-indexed-object-style */
class DatasourceCacheStats {
static getData() {
return (memCache.get('datasource-cache-stats') ?? []);
}
static setData(data) {
memCache.set('datasource-cache-stats', data);
}
static hit(datasource, registryUrl, packageName) {
const data = this.getData();
data.push({ datasource, registryUrl, packageName, action: 'hit' });
this.setData(data);
}
static miss(datasource, registryUrl, packageName) {
const data = this.getData();
data.push({ datasource, registryUrl, packageName, action: 'miss' });
this.setData(data);
}
static set(datasource, registryUrl, packageName) {
const data = this.getData();
data.push({ datasource, registryUrl, packageName, action: 'set' });
this.setData(data);
}
static skip(datasource, registryUrl, packageName) {
const data = this.getData();
data.push({ datasource, registryUrl, packageName, action: 'skip' });
this.setData(data);
}
static getReport() {
const data = this.getData();
const result = { long: {}, short: {} };
for (const { datasource, registryUrl, packageName, action } of data) {
result.long[datasource] ??= {};
result.long[datasource][registryUrl] ??= {};
result.long[datasource][registryUrl] ??= {};
result.long[datasource][registryUrl][packageName] ??= {};
result.short[datasource] ??= {};
result.short[datasource][registryUrl] ??= {
hit: 0,
miss: 0,
set: 0,
skip: 0,
};
if (action === 'hit') {
result.long[datasource][registryUrl][packageName].read = 'hit';
result.short[datasource][registryUrl].hit += 1;
continue;
}
if (action === 'miss') {
result.long[datasource][registryUrl][packageName].read = 'miss';
result.short[datasource][registryUrl].miss += 1;
continue;
}
if (action === 'set') {
result.long[datasource][registryUrl][packageName].write = 'set';
result.short[datasource][registryUrl].set += 1;
continue;
}
if (action === 'skip') {
result.long[datasource][registryUrl][packageName].write = 'skip';
result.short[datasource][registryUrl].skip += 1;
continue;
}
}
return result;
}
static report() {
const { long, short } = this.getReport();
if (Object.keys(short).length > 0) {
logger_1.logger.debug(short, 'Datasource cache statistics');
}
if (Object.keys(long).length > 0) {
logger_1.logger.trace(long, 'Datasource cache detailed statistics');
}
}
}
exports.DatasourceCacheStats = DatasourceCacheStats;
class HttpStats {
static write(data) {
const httpRequests = memCache.get('http-requests') ?? [];
httpRequests.push(data);
memCache.set('http-requests', httpRequests);
}
static getDataPoints() {
const httpRequests = memCache.get('http-requests') ?? [];
// istanbul ignore next: sorting is hard and not worth testing
httpRequests.sort((a, b) => {
if (a.url < b.url) {
return -1;
}
if (a.url > b.url) {
return 1;
}
return 0;
});
return httpRequests;
}
static getReport() {
const dataPoints = HttpStats.getDataPoints();
const requests = dataPoints.length;
const urls = {};
const rawRequests = [];
const hostRequests = {};
for (const dataPoint of dataPoints) {
const { url, reqMs, queueMs, status } = dataPoint;
const method = dataPoint.method.toUpperCase();
const parsedUrl = (0, url_1.parseUrl)(url);
if (!parsedUrl) {
logger_1.logger.debug({ url }, 'Failed to parse URL during stats reporting');
continue;
}
const { hostname, origin, pathname } = parsedUrl;
const baseUrl = `${origin}${pathname}`;
urls[baseUrl] ??= {};
urls[baseUrl][method] ??= {};
urls[baseUrl][method][status] ??= 0;
urls[baseUrl][method][status] += 1;
rawRequests.push(`${method} ${url} ${status} ${reqMs} ${queueMs}`);
hostRequests[hostname] ??= [];
hostRequests[hostname].push(dataPoint);
}
const hosts = {};
for (const [hostname, dataPoints] of Object.entries(hostRequests)) {
const count = dataPoints.length;
const reqTimes = dataPoints.map((r) => r.reqMs);
const queueTimes = dataPoints.map((r) => r.queueMs);
const reqReport = makeTimingReport(reqTimes);
const queueReport = makeTimingReport(queueTimes);
hosts[hostname] = {
count,
reqAvgMs: reqReport.avgMs,
reqMedianMs: reqReport.medianMs,
reqMaxMs: reqReport.maxMs,
queueAvgMs: queueReport.avgMs,
queueMedianMs: queueReport.medianMs,
queueMaxMs: queueReport.maxMs,
};
}
return {
urls,
rawRequests,
hostRequests,
hosts,
requests,
};
}
static report() {
const { urls, rawRequests, hostRequests, hosts, requests } = HttpStats.getReport();
logger_1.logger.trace({ rawRequests, hostRequests }, 'HTTP full statistics');
logger_1.logger.debug({ hosts, requests }, 'HTTP statistics');
logger_1.logger.trace({ urls }, 'HTTP URL statistics');
}
}
exports.HttpStats = HttpStats;
function sortObject(obj) {
const result = {};
for (const key of Object.keys(obj).sort()) {
result[key] = obj[key];
}
return result;
}
class HttpCacheStats {
static getData() {
return memCache.get('http-cache-stats') ?? {};
}
static read(key) {
return (this.getData()?.[key] ?? {
hit: 0,
miss: 0,
});
}
static write(key, data) {
const stats = memCache.get('http-cache-stats') ?? {};
stats[key] = data;
memCache.set('http-cache-stats', stats);
}
static getBaseUrl(url) {
const parsedUrl = (0, url_1.parseUrl)(url);
if (!parsedUrl) {
logger_1.logger.debug({ url }, 'Failed to parse URL during cache stats');
return null;
}
const { origin, pathname } = parsedUrl;
const baseUrl = `${origin}${pathname}`;
return baseUrl;
}
static incLocalHits(url) {
const baseUrl = HttpCacheStats.getBaseUrl(url);
if (baseUrl) {
const host = baseUrl;
const stats = HttpCacheStats.read(host);
stats.localHit ??= 0;
stats.localHit += 1;
HttpCacheStats.write(host, stats);
}
}
static incLocalMisses(url) {
const baseUrl = HttpCacheStats.getBaseUrl(url);
if (baseUrl) {
const host = baseUrl;
const stats = HttpCacheStats.read(host);
stats.localMiss ??= 0;
stats.localMiss += 1;
HttpCacheStats.write(host, stats);
}
}
static incRemoteHits(url) {
const baseUrl = HttpCacheStats.getBaseUrl(url);
if (baseUrl) {
const host = baseUrl;
const stats = HttpCacheStats.read(host);
stats.hit += 1;
HttpCacheStats.write(host, stats);
}
}
static incRemoteMisses(url) {
const baseUrl = HttpCacheStats.getBaseUrl(url);
if (baseUrl) {
const host = baseUrl;
const stats = HttpCacheStats.read(host);
stats.miss += 1;
HttpCacheStats.write(host, stats);
}
}
static report() {
const data = HttpCacheStats.getData();
let report = {};
for (const [url, stats] of Object.entries(data)) {
const parsedUrl = (0, url_1.parseUrl)(url);
if (parsedUrl) {
const { origin, pathname } = parsedUrl;
report[origin] ??= {};
report[origin][pathname] = stats;
}
}
for (const [host, hostStats] of Object.entries(report)) {
report[host] = sortObject(hostStats);
}
report = sortObject(report);
logger_1.logger.debug(report, 'HTTP cache statistics');
}
}
exports.HttpCacheStats = HttpCacheStats;
/* v8 ignore start: temporary code */
class ObsoleteCacheHitLogger {
static getData() {
return memCache.get('obsolete-cache-stats') ?? {};
}
static write(url) {
const data = this.getData();
if (!data[url]) {
data[url] = { count: 0 };
}
data[url].count++;
memCache.set('obsolete-cache-stats', data);
}
static report() {
const hits = this.getData();
logger_1.logger.debug({ count: Object.keys(hits).length, hits }, 'Cache fallback URLs');
}
}
exports.ObsoleteCacheHitLogger = ObsoleteCacheHitLogger;
class AbandonedPackageStats {
static getData() {
return memCache.get('abandonment-stats') ?? [];
}
static setData(data) {
memCache.set('abandonment-stats', data);
}
static write(datasource, packageName, mostRecentTimestamp) {
const data = this.getData();
data.push({ datasource, packageName, mostRecentTimestamp });
this.setData(data);
}
static getReport() {
const data = this.getData();
const result = {};
for (const { datasource, packageName, mostRecentTimestamp } of data) {
result[datasource] ??= {};
result[datasource][packageName] = mostRecentTimestamp;
}
const sortedResult = {};
for (const datasource of Object.keys(result).sort()) {
sortedResult[datasource] = {};
for (const packageName of Object.keys(result[datasource]).sort()) {
sortedResult[datasource][packageName] = result[datasource][packageName];
}
}
return sortedResult;
}
static report() {
const report = this.getReport();
if (Object.keys(report).length > 0) {
logger_1.logger.debug(report, 'Abandoned package statistics');
}
}
}
exports.AbandonedPackageStats = AbandonedPackageStats;
//# sourceMappingURL=stats.js.map