UNPKG

@cocalc/hub

Version:
85 lines 3.24 kB
"use strict"; /* Express middleware for recording metrics about response time to requests. */ var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.initMetricsEndpoint = exports.setupInstrumentation = void 0; const path_1 = require("path"); const { get, new_histogram } = require("@cocalc/hub/metrics-recorder"); const path_2 = require("path"); const base_path_1 = __importDefault(require("@cocalc/backend/base-path")); const pool_1 = __importDefault(require("@cocalc/database/pool")); const logger_1 = require("@cocalc/hub/logger"); const log = (0, logger_1.getLogger)("metrics"); // initialize metrics const responseTimeHistogram = new_histogram("http_histogram", "http server", { buckets: [0.01, 0.1, 1, 2, 5, 10, 20], labels: ["path", "method", "code"], }); // response time metrics function metrics(req, res, next) { const resFinished = responseTimeHistogram.startTimer(); const originalEnd = res.end; res.end = (...args) => { originalEnd.apply(res, args); if (!req.path) { return; } const pathSplit = req.path.split("/"); // for API paths, we want to have data for each endpoint const path_tail = pathSplit.slice(pathSplit.length - 3); const is_api = path_tail[0] === "api" && path_tail[1] === "v1"; let path; if (is_api) { path = path_tail.join("/"); } else { // for regular paths, we ignore the file path = (0, path_1.dirname)(req.path).split("/").slice(0, 2).join("/"); } resFinished({ path, method: req.method, code: res.statusCode, }); }; next(); } function setupInstrumentation(router) { router.use(metrics); } exports.setupInstrumentation = setupInstrumentation; async function isEnabled(pool) { const { rows } = await pool.query("SELECT value FROM server_settings WHERE name='prometheus_metrics'"); const enabled = rows.length > 0 && rows[0].value == "yes"; log.info("isEnabled", enabled); return enabled; } function initMetricsEndpoint(router) { const endpoint = (0, path_2.join)(base_path_1.default, "metrics"); log.info("initMetricsEndpoint at ", endpoint); // long cache so we can easily check before each response and it is still fast. const pool = (0, pool_1.default)("long"); router.get(endpoint, async (_req, res) => { res.header("Content-Type", "text/plain"); res.header("Cache-Control", "no-cache, no-store"); if (!(await isEnabled(pool))) { res.json({ error: "Sharing of metrics at /metrics is disabled. Metrics can be enabled in the site administration page.", }); return; } const metricsRecorder = get(); if (metricsRecorder != null) { res.send(await metricsRecorder.metrics()); } else { res.json({ error: "Metrics recorder not initialized." }); } }); } exports.initMetricsEndpoint = initMetricsEndpoint; //# sourceMappingURL=metrics.js.map