From 331027c89628181f770c6e9f85f2d9991c7662a0 Mon Sep 17 00:00:00 2001 From: Rick van Drongelen Date: Mon, 19 May 2025 12:11:16 +0200 Subject: [PATCH 01/12] feat #680: Add tags to prometheus labels From ed1b696d5bd15150dc2aa93b0b43f2d9e1c3755f Mon Sep 17 00:00:00 2001 From: Rick van Drongelen Date: Mon, 19 May 2025 12:34:30 +0200 Subject: [PATCH 02/12] Added monitor_tags to the prometheus metrics. --- server/model/monitor.js | 2 +- server/prometheus.js | 40 +++++++++++++++++++++++++++++++++++++--- 2 files changed, 38 insertions(+), 4 deletions(-) diff --git a/server/model/monitor.js b/server/model/monitor.js index 85293bbdc..1a066d162 100644 --- a/server/model/monitor.js +++ b/server/model/monitor.js @@ -328,7 +328,7 @@ class Monitor extends BeanModel { let previousBeat = null; let retries = 0; - this.prometheus = new Prometheus(this); + this.prometheus = new Prometheus(this, await this.getTags()); const beat = async () => { diff --git a/server/prometheus.js b/server/prometheus.js index f26125d2c..ad93bd634 100644 --- a/server/prometheus.js +++ b/server/prometheus.js @@ -7,6 +7,7 @@ const commonLabels = [ "monitor_url", "monitor_hostname", "monitor_port", + "monitor_tags" ]; const monitorCertDaysRemaining = new PrometheusClient.Gauge({ @@ -37,17 +38,51 @@ class Prometheus { /** * @param {object} monitor Monitor object to monitor + * @param {Array} tags Tags to add to the monitor */ - constructor(monitor) { + constructor(monitor, tags) { + let sanitizedTags = this.sanitizeTags(tags); + + if (sanitizedTags.length <= 0) { + sanitizedTags = "null"; + } + this.monitorLabelValues = { monitor_name: monitor.name, monitor_type: monitor.type, monitor_url: monitor.url, monitor_hostname: monitor.hostname, - monitor_port: monitor.port + monitor_port: monitor.port, + monitor_tags: sanitizedTags }; } + /** + * Sanitize tags to remove non-ASCII characters + * See https://github.com/louislam/uptime-kuma/pull/4704#issuecomment-2366524692 + * @param {Array} tags The tags to sanitize + * @returns {*[]} The sanitized tags + */ + sanitizeTags(tags) { + const nonAsciiRegex = /[^\x00-\x7F]/g; + const sanitizedTags = []; + tags.forEach((tag) => { + if (tag.name.match(nonAsciiRegex) || tag.value.match(nonAsciiRegex)) { + // If the tag name or value contains non-ASCII characters, skip it + return; + } + + if (tag.value !== "") { + sanitizedTags.push(tag.name + ":" + tag.value); + return; + } + + sanitizedTags.push(tag.name); + }); + + return sanitizedTags; + } + /** * Update the metrics page * @param {object} heartbeat Heartbeat details @@ -55,7 +90,6 @@ class Prometheus { * @returns {void} */ update(heartbeat, tlsInfo) { - if (typeof tlsInfo !== "undefined") { try { let isValid; From 536621234786940acd5195940943b98a91c84295 Mon Sep 17 00:00:00 2001 From: Rick van Drongelen Date: Wed, 21 May 2025 12:43:47 +0200 Subject: [PATCH 03/12] Reworked non-ascii tag filtering for prometheus metrics --- server/prometheus.js | 42 ++++++++++++++++++------------------------ 1 file changed, 18 insertions(+), 24 deletions(-) diff --git a/server/prometheus.js b/server/prometheus.js index ad93bd634..34646d6c7 100644 --- a/server/prometheus.js +++ b/server/prometheus.js @@ -41,10 +41,10 @@ class Prometheus { * @param {Array} tags Tags to add to the monitor */ constructor(monitor, tags) { - let sanitizedTags = this.sanitizeTags(tags); + let filteredValidAsciiTags = this.filterValidAsciiTags(tags); - if (sanitizedTags.length <= 0) { - sanitizedTags = "null"; + if (filteredValidAsciiTags.length <= 0) { + filteredValidAsciiTags = "null"; } this.monitorLabelValues = { @@ -53,34 +53,28 @@ class Prometheus { monitor_url: monitor.url, monitor_hostname: monitor.hostname, monitor_port: monitor.port, - monitor_tags: sanitizedTags + monitor_tags: filteredValidAsciiTags }; } /** - * Sanitize tags to remove non-ASCII characters + * Filter tags to remove the ones that contain non-ASCII characters * See https://github.com/louislam/uptime-kuma/pull/4704#issuecomment-2366524692 - * @param {Array} tags The tags to sanitize - * @returns {*[]} The sanitized tags + * @param {Array<{name: string, value:string}>} tags The tags to filter + * @returns {string[]} The filtered tags */ - sanitizeTags(tags) { - const nonAsciiRegex = /[^\x00-\x7F]/g; - const sanitizedTags = []; - tags.forEach((tag) => { - if (tag.name.match(nonAsciiRegex) || tag.value.match(nonAsciiRegex)) { - // If the tag name or value contains non-ASCII characters, skip it - return; + filterValidAsciiTags(tags) { + const asciiRegex = /^[a-zA-Z_][a-zA-Z0-9_]*$/; + return tags.reduce((filteredTags, tag) => { + if (asciiRegex.test(tag.name)) { + if (tag.value !== "" && asciiRegex.test(tag.value)) { + filteredTags.push(`${tag.name}:${tag.value}`); + } else { + filteredTags.push(tag.name); + } } - - if (tag.value !== "") { - sanitizedTags.push(tag.name + ":" + tag.value); - return; - } - - sanitizedTags.push(tag.name); - }); - - return sanitizedTags; + return filteredTags; + }, []); } /** From 4a5fe2145c9170c63c28e5277b17596422451cf6 Mon Sep 17 00:00:00 2001 From: Rick van Drongelen Date: Wed, 21 May 2025 13:09:02 +0200 Subject: [PATCH 04/12] Fixed jsdoc type --- server/prometheus.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/server/prometheus.js b/server/prometheus.js index 34646d6c7..d81e5d0ab 100644 --- a/server/prometheus.js +++ b/server/prometheus.js @@ -38,7 +38,7 @@ class Prometheus { /** * @param {object} monitor Monitor object to monitor - * @param {Array} tags Tags to add to the monitor + * @param {Array<{name:string,value:?string}>} tags Tags to add to the monitor */ constructor(monitor, tags) { let filteredValidAsciiTags = this.filterValidAsciiTags(tags); @@ -60,7 +60,7 @@ class Prometheus { /** * Filter tags to remove the ones that contain non-ASCII characters * See https://github.com/louislam/uptime-kuma/pull/4704#issuecomment-2366524692 - * @param {Array<{name: string, value:string}>} tags The tags to filter + * @param {Array<{name: string, value:?string}>} tags The tags to filter * @returns {string[]} The filtered tags */ filterValidAsciiTags(tags) { From e61ba524d75bda419f4f1745b6735013cc872b95 Mon Sep 17 00:00:00 2001 From: Rick van Drongelen Date: Wed, 4 Jun 2025 16:17:18 +0200 Subject: [PATCH 05/12] Remove unsupported characters in prometheus metrics. --- server/prometheus.js | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/server/prometheus.js b/server/prometheus.js index d81e5d0ab..9a5273be4 100644 --- a/server/prometheus.js +++ b/server/prometheus.js @@ -41,10 +41,10 @@ class Prometheus { * @param {Array<{name:string,value:?string}>} tags Tags to add to the monitor */ constructor(monitor, tags) { - let filteredValidAsciiTags = this.filterValidAsciiTags(tags); + let sanitizedTags = this.sanitizeTags(tags); - if (filteredValidAsciiTags.length <= 0) { - filteredValidAsciiTags = "null"; + if (sanitizedTags.length <= 0) { + sanitizedTags = "null"; } this.monitorLabelValues = { @@ -53,27 +53,27 @@ class Prometheus { monitor_url: monitor.url, monitor_hostname: monitor.hostname, monitor_port: monitor.port, - monitor_tags: filteredValidAsciiTags + monitor_tags: sanitizedTags }; } /** - * Filter tags to remove the ones that contain non-ASCII characters + * Sanitize tags to ensure they can be processed by Prometheus. * See https://github.com/louislam/uptime-kuma/pull/4704#issuecomment-2366524692 - * @param {Array<{name: string, value:?string}>} tags The tags to filter - * @returns {string[]} The filtered tags + * @param {Array<{name: string, value:?string}>} tags The tags to sanitize + * @returns {string[]} The sanitized tags */ - filterValidAsciiTags(tags) { - const asciiRegex = /^[a-zA-Z_][a-zA-Z0-9_]*$/; - return tags.reduce((filteredTags, tag) => { - if (asciiRegex.test(tag.name)) { - if (tag.value !== "" && asciiRegex.test(tag.value)) { - filteredTags.push(`${tag.name}:${tag.value}`); - } else { - filteredTags.push(tag.name); - } + sanitizeTags(tags) { + return tags.reduce((sanitizedTags, tag) => { + let tagText = tag.name; + tagText = tagText.replace(/[^a-zA-Z0-9_]/g, "") + tagText = tagText.replace(/^[^a-zA-Z_]+/, "") + + if (tagText !== "") { + sanitizedTags.push(tagText); } - return filteredTags; + + return sanitizedTags; }, []); } From cfde1a7ed2e364b353d91472148f5350771a615e Mon Sep 17 00:00:00 2001 From: Rick van Drongelen Date: Wed, 4 Jun 2025 16:29:23 +0200 Subject: [PATCH 06/12] lint fix --- server/prometheus.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/server/prometheus.js b/server/prometheus.js index 9a5273be4..78d2950f2 100644 --- a/server/prometheus.js +++ b/server/prometheus.js @@ -66,8 +66,8 @@ class Prometheus { sanitizeTags(tags) { return tags.reduce((sanitizedTags, tag) => { let tagText = tag.name; - tagText = tagText.replace(/[^a-zA-Z0-9_]/g, "") - tagText = tagText.replace(/^[^a-zA-Z_]+/, "") + tagText = tagText.replace(/[^a-zA-Z0-9_]/g, ""); + tagText = tagText.replace(/^[^a-zA-Z_]+/, ""); if (tagText !== "") { sanitizedTags.push(tagText); From fc734e7af4b1c3401631c2bc38346bd8eb14121a Mon Sep 17 00:00:00 2001 From: Frank Elsinga Date: Tue, 24 Jun 2025 17:11:50 +0200 Subject: [PATCH 07/12] Apply suggestions from code review --- server/prometheus.js | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/server/prometheus.js b/server/prometheus.js index 78d2950f2..3d382883d 100644 --- a/server/prometheus.js +++ b/server/prometheus.js @@ -41,20 +41,17 @@ class Prometheus { * @param {Array<{name:string,value:?string}>} tags Tags to add to the monitor */ constructor(monitor, tags) { - let sanitizedTags = this.sanitizeTags(tags); - - if (sanitizedTags.length <= 0) { - sanitizedTags = "null"; - } - this.monitorLabelValues = { monitor_name: monitor.name, monitor_type: monitor.type, monitor_url: monitor.url, monitor_hostname: monitor.hostname, monitor_port: monitor.port, - monitor_tags: sanitizedTags }; + let sanitizedTags = this.sanitizeTags(tags); + if (sanitizedTags.length) { + this.monitorLabelValues.monitor_tags = sanitizedTags + } } /** @@ -65,7 +62,7 @@ class Prometheus { */ sanitizeTags(tags) { return tags.reduce((sanitizedTags, tag) => { - let tagText = tag.name; + let tagText = tag.value ? `${tag.name}_${tag.value}` : tag.name; tagText = tagText.replace(/[^a-zA-Z0-9_]/g, ""); tagText = tagText.replace(/^[^a-zA-Z_]+/, ""); From 073b12da51d3a19d77760df8622e7bf87a3eea6e Mon Sep 17 00:00:00 2001 From: Frank Elsinga Date: Tue, 24 Jun 2025 17:34:05 +0200 Subject: [PATCH 08/12] fix linting mistake --- server/prometheus.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server/prometheus.js b/server/prometheus.js index 775743cb5..2396368dc 100644 --- a/server/prometheus.js +++ b/server/prometheus.js @@ -52,7 +52,7 @@ class Prometheus { }; let sanitizedTags = this.sanitizeTags(tags); if (sanitizedTags.length) { - this.monitorLabelValues.monitor_tags = sanitizedTags + this.monitorLabelValues.monitor_tags = sanitizedTags; } } From fe8c8392377f56bd62fd4c62ac62aa8228dd5688 Mon Sep 17 00:00:00 2001 From: Rick van Drongelen Date: Thu, 26 Jun 2025 14:56:44 +0200 Subject: [PATCH 09/12] Adding monitor tags as individual prometheus labels instead of comma separating them into one label --- server/prometheus.js | 135 +++++++++++++++++++++++++++---------------- server/server.js | 5 ++ 2 files changed, 91 insertions(+), 49 deletions(-) diff --git a/server/prometheus.js b/server/prometheus.js index 2396368dc..5b3fac768 100644 --- a/server/prometheus.js +++ b/server/prometheus.js @@ -1,38 +1,11 @@ const PrometheusClient = require("prom-client"); const { log } = require("../src/util"); +const { R } = require("redbean-node"); -const commonLabels = [ - "monitor_id", - "monitor_name", - "monitor_type", - "monitor_url", - "monitor_hostname", - "monitor_port", - "monitor_tags" -]; - -const monitorCertDaysRemaining = new PrometheusClient.Gauge({ - name: "monitor_cert_days_remaining", - help: "The number of days remaining until the certificate expires", - labelNames: commonLabels -}); - -const monitorCertIsValid = new PrometheusClient.Gauge({ - name: "monitor_cert_is_valid", - help: "Is the certificate still valid? (1 = Yes, 0= No)", - labelNames: commonLabels -}); -const monitorResponseTime = new PrometheusClient.Gauge({ - name: "monitor_response_time", - help: "Monitor Response Time (ms)", - labelNames: commonLabels -}); - -const monitorStatus = new PrometheusClient.Gauge({ - name: "monitor_status", - help: "Monitor Status (1 = UP, 0= DOWN, 2= PENDING, 3= MAINTENANCE)", - labelNames: commonLabels -}); +let monitorCertDaysRemaining = null; +let monitorCertIsValid = null; +let monitorResponseTime = null; +let monitorStatus = null; class Prometheus { monitorLabelValues = {}; @@ -49,31 +22,95 @@ class Prometheus { monitor_url: monitor.url, monitor_hostname: monitor.hostname, monitor_port: monitor.port, + ...this.mapTagsToLabels(tags) }; - let sanitizedTags = this.sanitizeTags(tags); - if (sanitizedTags.length) { - this.monitorLabelValues.monitor_tags = sanitizedTags; - } } /** - * Sanitize tags to ensure they can be processed by Prometheus. - * See https://github.com/louislam/uptime-kuma/pull/4704#issuecomment-2366524692 - * @param {Array<{name: string, value:?string}>} tags The tags to sanitize - * @returns {string[]} The sanitized tags + * Initialize Prometheus metrics, and add all available tags as possible labels. + * This should be called once at the start of the application. + * New tags will NOT be added dynamically, a restart is sadly required to add new tags to the metrics. + * Existing tags added to monitors will be updated automatically. + * @returns {Promise} */ - sanitizeTags(tags) { - return tags.reduce((sanitizedTags, tag) => { - let tagText = tag.value ? `${tag.name}_${tag.value}` : tag.name; - tagText = tagText.replace(/[^a-zA-Z0-9_]/g, ""); - tagText = tagText.replace(/^[^a-zA-Z_]+/, ""); + static async init() { + const tags = (await R.findAll("tag")).map((tag) => { + return Prometheus.sanitizeForPrometheus(tag.name); + }).filter((tagName) => { + return tagName !== ""; + }); - if (tagText !== "") { - sanitizedTags.push(tagText); + const commonLabels = [ + "monitor_id", + "monitor_name", + "monitor_type", + "monitor_url", + "monitor_hostname", + "monitor_port", + ...tags // Add all available tags as possible labels + ]; + + monitorCertDaysRemaining = new PrometheusClient.Gauge({ + name: "monitor_cert_days_remaining", + help: "The number of days remaining until the certificate expires", + labelNames: commonLabels + }); + + monitorCertIsValid = new PrometheusClient.Gauge({ + name: "monitor_cert_is_valid", + help: "Is the certificate still valid? (1 = Yes, 0= No)", + labelNames: commonLabels + }); + + monitorResponseTime = new PrometheusClient.Gauge({ + name: "monitor_response_time", + help: "Monitor Response Time (ms)", + labelNames: commonLabels + }); + + monitorStatus = new PrometheusClient.Gauge({ + name: "monitor_status", + help: "Monitor Status (1 = UP, 0= DOWN, 2= PENDING, 3= MAINTENANCE)", + labelNames: commonLabels + }); + } + + /** + * Sanitize a string to ensure it can be used as a Prometheus label or value. + * See https://github.com/louislam/uptime-kuma/pull/4704#issuecomment-2366524692 + * @param {string} text The text to sanitize + * @returns {string} The sanitized text + */ + static sanitizeForPrometheus(text) { + text = text.replace(/[^a-zA-Z0-9_]/g, ""); + text = text.replace(/^[^a-zA-Z_]+/, ""); + return text; + } + + /** + * Map the tags value to valid labels used in Prometheus. Sanitize them in the process. + * @param {Array<{name: string, value:?string}>} tags The tags to map + * @returns {Array} The mapped tags, usable as labels + */ + mapTagsToLabels(tags) { + let mappedTags = {}; + tags.forEach((tag) => { + let sanitizedTag = Prometheus.sanitizeForPrometheus(tag.name); + if (sanitizedTag === "") { + return; // Skip empty tag names } - return sanitizedTags; - }, []); + if (mappedTags[sanitizedTag] === undefined) { + mappedTags[sanitizedTag] = "null"; + } + + let tagValue = Prometheus.sanitizeForPrometheus(tag.value); + if (tagValue !== "") { + mappedTags[sanitizedTag] = mappedTags[sanitizedTag] !== "null" ? mappedTags[sanitizedTag] + `,${tagValue}` : tagValue; + } + }); + + return mappedTags; } /** diff --git a/server/server.js b/server/server.js index 5b2f41a2e..852f05614 100644 --- a/server/server.js +++ b/server/server.js @@ -108,6 +108,8 @@ const { apiAuth } = require("./auth"); const { login } = require("./auth"); const passwordHash = require("./password-hash"); +const { Prometheus } = require("./prometheus"); + const hostname = config.hostname; if (hostname) { @@ -192,6 +194,9 @@ let needSetup = false; server.entryPage = await Settings.get("entryPage"); await StatusPage.loadDomainMappingList(); + log.debug("server", "Initializing Prometheus"); + await Prometheus.init(); + log.debug("server", "Adding route"); // *************************** From 2e597c76973fbee827edefded2cbc9356d37f92b Mon Sep 17 00:00:00 2001 From: Rick van Drongelen Date: Tue, 1 Jul 2025 12:03:50 +0200 Subject: [PATCH 10/12] Added ordering to tags and values, set tags as first in metrics to prevent overwriting very much needed metric labels. --- server/prometheus.js | 28 ++++++++++++++++++---------- 1 file changed, 18 insertions(+), 10 deletions(-) diff --git a/server/prometheus.js b/server/prometheus.js index 5b3fac768..271901b9c 100644 --- a/server/prometheus.js +++ b/server/prometheus.js @@ -16,13 +16,13 @@ class Prometheus { */ constructor(monitor, tags) { this.monitorLabelValues = { + ...this.mapTagsToLabels(tags), monitor_id: monitor.id, monitor_name: monitor.name, monitor_type: monitor.type, monitor_url: monitor.url, monitor_hostname: monitor.hostname, - monitor_port: monitor.port, - ...this.mapTagsToLabels(tags) + monitor_port: monitor.port }; } @@ -34,20 +34,22 @@ class Prometheus { * @returns {Promise} */ static async init() { - const tags = (await R.findAll("tag")).map((tag) => { + // Add all available tags as possible labels, + // and use Set to remove possible duplicates (for when multiple tags contain non-ascii characters, and thus are sanitized to the same label) + const tags = new Set((await R.findAll("tag")).map((tag) => { return Prometheus.sanitizeForPrometheus(tag.name); }).filter((tagName) => { return tagName !== ""; - }); + })); const commonLabels = [ + ...tags, "monitor_id", "monitor_name", "monitor_type", "monitor_url", "monitor_hostname", "monitor_port", - ...tags // Add all available tags as possible labels ]; monitorCertDaysRemaining = new PrometheusClient.Gauge({ @@ -84,13 +86,13 @@ class Prometheus { static sanitizeForPrometheus(text) { text = text.replace(/[^a-zA-Z0-9_]/g, ""); text = text.replace(/^[^a-zA-Z_]+/, ""); - return text; + return text.toLowerCase(); } /** * Map the tags value to valid labels used in Prometheus. Sanitize them in the process. * @param {Array<{name: string, value:?string}>} tags The tags to map - * @returns {Array} The mapped tags, usable as labels + * @returns {object} The mapped tags, usable as labels */ mapTagsToLabels(tags) { let mappedTags = {}; @@ -101,16 +103,22 @@ class Prometheus { } if (mappedTags[sanitizedTag] === undefined) { - mappedTags[sanitizedTag] = "null"; + mappedTags[sanitizedTag] = []; } let tagValue = Prometheus.sanitizeForPrometheus(tag.value); if (tagValue !== "") { - mappedTags[sanitizedTag] = mappedTags[sanitizedTag] !== "null" ? mappedTags[sanitizedTag] + `,${tagValue}` : tagValue; + mappedTags[sanitizedTag].push(tagValue); } + + mappedTags[sanitizedTag] = mappedTags[sanitizedTag].sort(); }); - return mappedTags; + // Order the tags alphabetically + return Object.keys(mappedTags).sort().reduce((obj, key) => { + obj[key] = mappedTags[key]; + return obj; + }, {}); } /** From 9e4d6f1b7081ee64bb333bbe07a2aba9374aaedb Mon Sep 17 00:00:00 2001 From: Rick van Drongelen Date: Thu, 3 Jul 2025 15:27:48 +0200 Subject: [PATCH 11/12] Added sorting to label definition --- server/prometheus.js | 29 +++++++++++++++++++++++++---- 1 file changed, 25 insertions(+), 4 deletions(-) diff --git a/server/prometheus.js b/server/prometheus.js index 271901b9c..a9723f155 100644 --- a/server/prometheus.js +++ b/server/prometheus.js @@ -40,7 +40,7 @@ class Prometheus { return Prometheus.sanitizeForPrometheus(tag.name); }).filter((tagName) => { return tagName !== ""; - })); + }).sort(this.sortTags)); const commonLabels = [ ...tags, @@ -86,7 +86,7 @@ class Prometheus { static sanitizeForPrometheus(text) { text = text.replace(/[^a-zA-Z0-9_]/g, ""); text = text.replace(/^[^a-zA-Z_]+/, ""); - return text.toLowerCase(); + return text; } /** @@ -106,7 +106,7 @@ class Prometheus { mappedTags[sanitizedTag] = []; } - let tagValue = Prometheus.sanitizeForPrometheus(tag.value); + let tagValue = Prometheus.sanitizeForPrometheus(tag.value || ""); if (tagValue !== "") { mappedTags[sanitizedTag].push(tagValue); } @@ -115,7 +115,7 @@ class Prometheus { }); // Order the tags alphabetically - return Object.keys(mappedTags).sort().reduce((obj, key) => { + return Object.keys(mappedTags).sort(this.sortTags).reduce((obj, key) => { obj[key] = mappedTags[key]; return obj; }, {}); @@ -188,6 +188,27 @@ class Prometheus { console.error(e); } } + + /** + * Sort the tags alphabetically, case-insensitive. + * @param a {string} + * @param b {string} + * @returns {number} + */ + sortTags(a, b) { + const aLowerCase = a.toLowerCase(); + const bLowerCase = b.toLowerCase(); + + if (aLowerCase < bLowerCase) { + return -1; + } + + if (aLowerCase > bLowerCase) { + return 1; + } + + return 0; + } } module.exports = { From 87cb7542cd1e93ddf12baa2f3a859763a1ca584e Mon Sep 17 00:00:00 2001 From: Rick van Drongelen Date: Thu, 3 Jul 2025 16:29:23 +0200 Subject: [PATCH 12/12] lint fix --- server/prometheus.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/server/prometheus.js b/server/prometheus.js index a9723f155..70daf8ce7 100644 --- a/server/prometheus.js +++ b/server/prometheus.js @@ -191,9 +191,9 @@ class Prometheus { /** * Sort the tags alphabetically, case-insensitive. - * @param a {string} - * @param b {string} - * @returns {number} + * @param {string} a The first tag to compare + * @param {string} b The second tag to compare + * @returns {number} The alphabetical order number */ sortTags(a, b) { const aLowerCase = a.toLowerCase();