Created
August 24, 2022 19:20
-
-
Save stokito/1b1b19c344d3614a3208dc81e44bfd97 to your computer and use it in GitHub Desktop.
parse Prometheus metrics from JavaScript
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
class Metric { | |
/** | |
* @param {string} help | |
* @param {string} value | |
* @param {string[]} values | |
* @param {string[]} labels | |
*/ | |
constructor(help, value, values, labels) { | |
this.help = help | |
this.value = value | |
this.values = values | |
this.labels = labels | |
} | |
} | |
/** | |
* @param {string} metricsText | |
* @returns {Map<string, Metric>} | |
*/ | |
function parsePrometheusMetrics(metricsText) { | |
let metricsLines = metricsText.split("\n") | |
let metrics = new Map() | |
for (let metricsLinesKey in metricsLines) { | |
let metricsLine = metricsLines[metricsLinesKey] | |
if (metricsLine === "") { | |
continue | |
} | |
if (metricsLine.startsWith("# HELP ")) { | |
let metricNameEndPos = metricsLine.substr(7).indexOf(" ") | |
let metricsName = metricsLine.substr(7, metricNameEndPos) | |
let metricsHelp = metricsLine.substr(7 + metricNameEndPos + 1) | |
metrics[metricsName] = new Metric(metricsHelp, "", null, null) | |
} else if (metricsLine.startsWith("# TYPE ")) { | |
// not interesting | |
} else { | |
// name with labels | |
let metricNameFqEndPos = metricsLine.lastIndexOf(" ") | |
let metricsValue = metricsLine.substr(metricNameFqEndPos + 1) | |
// "go_threads" or "agw_req{SSP="ssp1",result="accepted"}" | |
let metricsNameFq = metricsLine.substr(0, metricNameFqEndPos) | |
let metricsName | |
let labelsStart = metricsNameFq.indexOf("{") | |
if (labelsStart < 0) { | |
metricsName = metricsNameFq | |
let metric = metrics[metricsName]; | |
if (!metric) { | |
metric = new Metric(null, null, null, null) | |
metrics[metricsName] = metric | |
} | |
metric.value = metricsValue | |
} else { | |
metricsName = metricsNameFq.substr(0, labelsStart) | |
let metricsLabels = metricsNameFq.substr(labelsStart + 1, metricsNameFq.length - 2) | |
let metric = metrics[metricsName]; | |
if (!metric) { | |
metric = new Metric(null, null, null, null) | |
metrics[metricsName] = metric | |
} | |
metric.labels ||= [] | |
metric.labels.push(metricsLabels) | |
metric.values ||= [] | |
metric.values.push(metricsValue) | |
} | |
} | |
} | |
return metrics | |
} | |
/** | |
* @param metrics {Map<string, Metric>} | |
* @param metricName {string} | |
* @param labelKey {string} | |
* @param labelVal {string} | |
* @return string | |
*/ | |
function getMetricVal(metrics, metricName, labelKey, labelVal) { | |
let metric = metrics[metricName] | |
if (!metric || !metric.labels) return null | |
let needle = `"${labelKey}"="${labelVal}"` | |
for (let i = 0; i < metric.labels.length; i++) { | |
let labelStr = metric.labels[i] | |
if (labelStr.includes(needle)) { | |
return metric.values[i] | |
} | |
} | |
return null | |
} | |
/** | |
* @param metric {Metric} | |
* @param labelNeedles {string} | |
* @return {string} | |
*/ | |
function getMetricValByLabel(metric, ...labelNeedles) { | |
for (let i = 0; i < metric.labels.length; i++) { | |
let labelStr = metric.labels[i] | |
if (labelsMatched(labelNeedles, labelStr)) { | |
return metric.values[i] | |
} | |
} | |
return null | |
} | |
/** | |
* @param metric {Metric} | |
* @param labelNeedles {string} | |
* @return {string[]} | |
*/ | |
function filterMetricValByLabel(metric, ...labelNeedles) { | |
let matchedValues = [] | |
for (let i = 0; i < metric.labels.length; i++) { | |
let labelStr = metric.labels[i] | |
if (labelsMatched(labelNeedles, labelStr)) { | |
matchedValues.push(metric.values[i]) | |
} | |
} | |
return matchedValues | |
} | |
function labelsMatched(labelNeedles, labelStr) { | |
let allMatched = true | |
for (let j = 0; j < labelNeedles.length; j++) { | |
let labelNeedle = labelNeedles[j] | |
if (!labelStr.includes(labelNeedle)) { | |
allMatched = false | |
break | |
} | |
} | |
return allMatched | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment