From aa38e6af4fd637708371c22a123681bb1a008488 Mon Sep 17 00:00:00 2001
From: Rhys Arkins <rhys@arkins.net>
Date: Sun, 26 May 2019 09:33:09 +0200
Subject: [PATCH] feat: host stats (#3812)

Collects latency stats for hosts and dumps them at the end of each run.
---
 lib/util/got/cache-get.js   |  4 ++++
 lib/util/got/index.js       |  9 ++++++++-
 lib/util/got/stats.js       | 40 +++++++++++++++++++++++++++++++++++++
 lib/workers/global/index.js |  2 ++
 4 files changed, 54 insertions(+), 1 deletion(-)
 create mode 100644 lib/util/got/stats.js

diff --git a/lib/util/got/cache-get.js b/lib/util/got/cache-get.js
index b5e3855263..f830ab02e7 100644
--- a/lib/util/got/cache-get.js
+++ b/lib/util/got/cache-get.js
@@ -9,6 +9,10 @@ const clone = input => JSON.parse(JSON.stringify(input));
 module.exports = got.create({
   options: {},
   handler: (options, next) => {
+    // istanbul ignore if
+    if (!global.repoCache) {
+      return next(options);
+    }
     if (options.method === 'GET') {
       const cacheKey = crypto
         .createHash('md5')
diff --git a/lib/util/got/index.js b/lib/util/got/index.js
index 4c45f911d2..92e03756d0 100644
--- a/lib/util/got/index.js
+++ b/lib/util/got/index.js
@@ -3,6 +3,7 @@ const cacheGet = require('./cache-get');
 const renovateAgent = require('./renovate-agent');
 const hostRules = require('./host-rules');
 const auth = require('./auth');
+const stats = require('./stats');
 
 /*
  * This is the default got instance for Renovate.
@@ -12,4 +13,10 @@ const auth = require('./auth');
  * Important: always put the renovateAgent one last, to make sure the correct user agent is used
  */
 
-module.exports = got.mergeInstances(cacheGet, renovateAgent, hostRules, auth);
+module.exports = got.mergeInstances(
+  cacheGet,
+  renovateAgent,
+  hostRules,
+  auth,
+  stats.instance
+);
diff --git a/lib/util/got/stats.js b/lib/util/got/stats.js
new file mode 100644
index 0000000000..c64b73b7cd
--- /dev/null
+++ b/lib/util/got/stats.js
@@ -0,0 +1,40 @@
+const got = require('got');
+
+let stats = {};
+
+// istanbul ignore next
+module.exports.resetStats = () => {
+  stats = {};
+};
+
+// istanbul ignore next
+module.exports.printStats = () => {
+  logger.trace({ stats }, 'Host transfer stats (milliseconds)');
+  const hostStats = {};
+  for (const [hostname, entries] of Object.entries(stats)) {
+    const res = {};
+    res.requests = entries.length;
+    res.sum = 0;
+    entries.forEach(entry => {
+      res.sum += entry;
+    });
+    res.average = Math.round(res.sum / res.requests);
+    res.median = entries[Math.floor(entries.length / 2)];
+    hostStats[hostname] = res;
+  }
+  logger.debug({ hostStats }, 'Host request stats (milliseconds)');
+};
+
+module.exports.instance = got.create({
+  options: {},
+  handler: (options, next) => {
+    const start = new Date();
+    const nextPromise = next(options);
+    nextPromise.on('response', () => {
+      const elapsed = new Date() - start;
+      stats[options.hostname] = stats[options.hostname] || [];
+      stats[options.hostname].push(elapsed);
+    });
+    return nextPromise;
+  },
+});
diff --git a/lib/workers/global/index.js b/lib/workers/global/index.js
index 19595b85d1..b691550d93 100644
--- a/lib/workers/global/index.js
+++ b/lib/workers/global/index.js
@@ -10,6 +10,7 @@ const { appName } = require('../../config/app-strings');
 const { autodiscoverRepositories } = require('./autodiscover');
 const { initPlatform } = require('../../platform');
 const hostRules = require('../../util/host-rules');
+const { printStats } = require('../../util/got/stats');
 
 module.exports = {
   start,
@@ -68,6 +69,7 @@ async function start() {
       await repositoryWorker.renovateRepository(repoConfig);
     }
     logger.setMeta({});
+    printStats();
     logger.info(`${appName} finished`);
   } catch (err) /* istanbul ignore next */ {
     if (err.message.startsWith('Init: ')) {
-- 
GitLab