Commit ff79222d authored by Cwhite's avatar Cwhite Committed by Petr Pchelko
Browse files

Normalize Prometheus metric name and label keys and values.

Add env variable toggle to selectively disable service label.

Bug: T247820
parent 65e4df39
......@@ -56,7 +56,7 @@ class HeapWatch {
prometheus: {
name: `nodejs_gc_${gcType}_duration_seconds`,
help: 'garbage collection pause duration seconds',
staticLabels: { service: this.metrics.getServiceName() },
staticLabels: this.metrics.getServiceLabel(),
buckets: [5e-4, 1e-3, 5e-3, 10e-3, 15e-3, 30e-3, 50e-3]
}
}).observe(totalGCTime * 1e-9); // nanoseconds to seconds
......@@ -78,7 +78,7 @@ class HeapWatch {
prometheus: {
name: 'nodejs_process_heap_rss_bytes',
help: 'process heap usage',
staticLabels: { service: this.metrics.getServiceName() }
staticLabels: this.metrics.getServiceLabel()
}
}).set(usage.rss);
this.metrics.makeMetric({
......@@ -87,7 +87,7 @@ class HeapWatch {
prometheus: {
name: 'nodejs_process_heap_used_bytes',
help: 'process heap usage',
staticLabels: { service: this.metrics.getServiceName() }
staticLabels: this.metrics.getServiceLabel()
}
}).set(usage.heapUsed);
this.metrics.makeMetric({
......@@ -96,7 +96,7 @@ class HeapWatch {
prometheus: {
name: 'nodejs_process_heap_total_bytes',
help: 'process heap usage',
staticLabels: { service: this.metrics.getServiceName() }
staticLabels: this.metrics.getServiceLabel()
}
}).set(usage.heapTotal);
if (usage.heapUsed > this.limit) {
......
......@@ -53,6 +53,16 @@ class Metrics {
return this.serviceName;
}
// T247820: Selectively disable service label based on environment variable.
// Intended for production use case where the service label will be set
// by the Prometheus server.
getServiceLabel() {
if (process.env.METRICS_SERVICE_LABEL_ENABLED === 'false') {
return {};
}
return { service: this.serviceName };
}
fetchClient(name) {
return this.clients.find((client) => {
return client.constructor.name === name;
......
......@@ -17,6 +17,9 @@ class PrometheusMetric {
});
}
}
options.prometheus.name = this._normalize(options.prometheus.name);
options.prometheus.labelNames = options.prometheus.labelNames || [];
options.prometheus.labelNames = options.prometheus.labelNames.map(this._normalize);
this.metric = new this.client[options.type]({
name: options.prometheus.name,
help: options.prometheus.help,
......@@ -34,23 +37,33 @@ class PrometheusMetric {
}
}
_normalize(str) {
return String(str).replace( /\W/g, '_' ) // replace non-alphanumerics
.replace( /_+/g, '_' ) // dedupe underscores
.replace( /(^_+|_+$)/g, '' ); // trim leading and trailing underscores
}
increment(amount, labels) {
this._handleStaticLabels(labels);
labels = labels.map(this._normalize);
this.metric.labels.apply(this.metric, labels).inc(amount);
}
decrement(amount, labels) {
this._handleStaticLabels(labels);
labels = labels.map(this._normalize);
this.metric.labels.apply(this.metric, labels).dec(amount);
}
observe(value, labels) {
this._handleStaticLabels(labels);
labels = labels.map(this._normalize);
this.metric.labels.apply(this.metric, labels).observe(value);
}
gauge(amount, labels) {
this._handleStaticLabels(labels);
labels = labels.map(this._normalize);
if (amount < 0) {
this.metric.labels.apply(this.metric, labels).dec(Math.abs(amount));
} else {
......@@ -60,14 +73,19 @@ class PrometheusMetric {
set(value, labels) {
this._handleStaticLabels(labels);
labels = labels.map(this._normalize);
this.metric.labels.apply(this.metric, labels).set(value);
}
timing(value, labels) {
this._handleStaticLabels(labels);
labels = labels.map(this._normalize);
this.set(value, labels);
}
endTiming(startTime, labels) {
this._handleStaticLabels(labels);
labels = labels.map(this._normalize);
this.timing(Date.now() - startTime, labels);
}
}
......
......@@ -21,7 +21,7 @@ module.exports = (options) => {
type: 'Counter',
name: 'simple_server.hitcount.total',
prometheus: {
name: 'hitcount_total',
name: 'hitcount total',
help: 'a hit counter'
}
}).increment();
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment