UNPKG

renovate

Version:

Automated dependency updates. Flexible so you don't need to be.

382 lines • 14 kB
"use strict"; 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