Replace endpointHitCounter

Track summary statistic of total HTTP response durations using a
middleware that applies for all requests instead of having every request
needing to update the hit counter manually.  Deprecates
endpointHitCounter.
This commit is contained in:
Hornwitser committed 2023-02-15 20:31:02 +01:00
1 parent 98dc0174d6
commit 5ad89f072f
7 files changed
+23 -24

No files matched your search

+14 -5
View File
@@ -6,7 +6,7 @@ const fs = require("fs-extra");
const http = require("http");
const https = require("https");
const path = require("path");
const stream = require("stream");
const libConfig = require("@clusterio/lib/config");
const libData = require("@clusterio/lib/data");
@@ -26,9 +26,10 @@ const UserManager = require("./UserManager");
const WsServer = require("./WsServer");
const hitCounter = new libPrometheus.Counter(
"clusterio_master_http_hits_total",
"How many HTTP requests in total have been received"
const endpointDurationSummary = new libPrometheus.Summary(
"clusterio_master_http_endpoint_duration_seconds",
"Time it took to respond to a an HTTP request",
{ labels: ["route"] }
);
/**
@@ -487,7 +488,15 @@ class Master {
static addAppRoutes(app, pluginInfos) {
app.use((req, res, next) => {
hitCounter.inc();
let start = process.hrtime.bigint();
stream.finished(res, () => {
let routePath = "static";
if (req.route && req.route.path) {
routePath = req.route.path;
}
let end = process.hrtime.bigint();
endpointDurationSummary.labels(routePath).observe(Number(end - start) / 1e9);
});
next();
});
app.use(compression());
+6 -1
View File
@@ -1,9 +1,14 @@
// Shared metrics
"use strict";
const libPrometheus = require("@clusterio/lib/prometheus");
const util = require("util");
exports.endpointHitCounter = new libPrometheus.Counter(
"clusterio_master_http_endpoint_hits_total",
"How many requests a particular HTTP endpoint has gotten",
{ labels: ["route"] }
{ labels: ["route"], register: false }
);
exports.endpointHitCounter.labels = util.deprecate(
exports.endpointHitCounter.labels, "incrementing endpointHitCounter is no longer needed and has no effect"
);
-7
View File
@@ -19,8 +19,6 @@ const libPlugin = require("@clusterio/lib/plugin");
const libPrometheus = require("@clusterio/lib/prometheus");
const { logger } = require("@clusterio/lib/logging");
const { endpointHitCounter } = require("./metrics");
const finished = util.promisify(nodeStream.finished);
@@ -41,8 +39,6 @@ function mergeSamples(destinationResult, sourceResult) {
// Prometheus polling endpoint
async function getMetrics(req, res, next) {
endpointHitCounter.labels(req.route.path).inc();
let results = [];
let pluginResults = await libPlugin.invokeHook(req.app.locals.master.plugins, "onMetrics");
for (let metricIterator of pluginResults) {
@@ -181,7 +177,6 @@ function validateUserToken(req, res, next) {
// Handle an uploaded export package.
async function uploadExport(req, res) {
endpointHitCounter.labels(req.route.path).inc();
if (req.get("Content-Type") !== "application/zip") {
res.sendStatus(415);
return;
@@ -340,7 +335,6 @@ async function uploadSave(req, res) {
res.status(403).json({ request_errors: [err.message] });
return;
}
endpointHitCounter.labels(req.route.path).inc();
let contentType = req.get("Content-Type");
let match = contentTypeRegExp.exec(contentType);
@@ -479,7 +473,6 @@ async function uploadMod(req, res) {
res.status(403).json({ request_errors: [err.message] });
return;
}
endpointHitCounter.labels(req.route.path).inc();
let contentType = req.get("Content-Type");
let match = contentTypeRegExp.exec(contentType);
-4
View File
@@ -44,8 +44,6 @@ class MasterPlugin extends libPlugin.BaseMasterPlugin {
}, 60e3).unref();
this.master.app.get("/api/player_auth/servers", (req, res) => {
this.metrics.endpointHitCounter.labels(req.route.path).inc();
let servers = [];
for (let instance of this.master.instances.values()) {
if (instance.status === "running" && instance.config.get("player_auth.load_plugin")) {
@@ -56,12 +54,10 @@ class MasterPlugin extends libPlugin.BaseMasterPlugin {
});
this.master.app.post("/api/player_auth/player_code", express.json(), (req, res, next) => {
this.metrics.endpointHitCounter.labels(req.route.path).inc();
this.handlePlayerCode(req, res).catch(next);
});
this.master.app.post("/api/player_auth/verify", express.json(), (req, res, next) => {
this.metrics.endpointHitCounter.labels(req.route.path).inc();
this.handleVerify(req, res).catch(next);
});
}
+1 -1
View File
@@ -86,7 +86,7 @@ class MasterPlugin extends libPlugin.BaseMasterPlugin {
this.subscribedControlLinks = new Set();
routes.addApiRoutes(this.master.app, this.items, this.metrics.endpointHitCounter);
routes.addApiRoutes(this.master.app, this.items);
}
updateStorage() {
+1 -3
View File
@@ -1,5 +1,5 @@
"use strict";
function addApiRoutes(app, items, endpointHitCounter) {
function addApiRoutes(app, items) {
/**
* GET endpoint to read the masters current inventory of items.
@@ -10,7 +10,6 @@ function addApiRoutes(app, items, endpointHitCounter) {
* @returns {object[]} JSON [{name:"iron-plate", count:100},{name:"copper-plate",count:5}]
*/
app.get("/api/inventory", (req, res) => {
endpointHitCounter.labels(req.route.path).inc();
res.header("Access-Control-Allow-Origin", "*");
res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
// Check it and send it
@@ -31,7 +30,6 @@ function addApiRoutes(app, items, endpointHitCounter) {
* @returns {object} JSON {"iron-plate":100, "copper-plate":5}
*/
app.get("/api/inventoryAsObject", (req, res) => {
endpointHitCounter.labels(req.route.path).inc();
res.header("Access-Control-Allow-Origin", "*");
res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
// Check it and send it
+1 -3
View File
@@ -219,9 +219,7 @@ class MockMaster {
async function createMasterPlugin(MasterPluginClass, info) {
let master = new MockMaster();
let metrics = {
endpointHitCounter: new libPrometheus.Counter("hit_counter", "Hit Counter", { labels: ["route"] }),
};
let metrics = {};
let logger = new MockLogger();
let plugin = new MasterPluginClass(info, master, metrics, logger);
await plugin.init();