prom-client
Advanced tools
Comparing version 15.0.0 to 15.1.0
@@ -502,2 +502,15 @@ // Type definitions for prom-client | ||
/** | ||
* Start a timer with exemplar. Calling the returned function will observe the duration in | ||
* seconds in the histogram. | ||
* @param labels Object with label keys and values | ||
* @param exemplarLabels Object with label keys and values for exemplars | ||
* @return Function to invoke when timer should be stopped. The value it | ||
* returns is the timed duration. | ||
*/ | ||
startTimer( | ||
labels?: LabelValues<T>, | ||
exemplarLabels?: LabelValues<T>, | ||
): (labels?: LabelValues<T>, exemplarLabels?: LabelValues<T>) => number; | ||
/** | ||
* Reset histogram values | ||
@@ -754,16 +767,13 @@ */ | ||
/** | ||
* Configure default metrics | ||
* @param config Configuration object for default metrics collector | ||
*/ | ||
export function collectDefaultMetrics<T extends RegistryContentType>( | ||
config?: DefaultMetricsCollectorConfiguration<T>, | ||
): void; | ||
export interface defaultMetrics { | ||
export const collectDefaultMetrics: { | ||
/** | ||
* All available default metrics | ||
* Configure default metrics | ||
* @param config Configuration object for default metrics collector | ||
*/ | ||
<T extends RegistryContentType>( | ||
config?: DefaultMetricsCollectorConfiguration<T>, | ||
): void; | ||
/** All available default metrics */ | ||
metricsList: string[]; | ||
} | ||
}; | ||
@@ -770,0 +780,0 @@ /** |
@@ -43,3 +43,3 @@ /** | ||
if (isObject(labels)) { | ||
hash = hashObject(labels); | ||
hash = hashObject(labels, this.sortedLabelNames); | ||
validateLabel(this.labelNames, labels); | ||
@@ -134,3 +134,3 @@ } else { | ||
validateLabel(this.labelNames, labels); | ||
return removeLabels.call(this, this.hashMap, labels); | ||
return removeLabels.call(this, this.hashMap, labels, this.sortedLabelNames); | ||
} | ||
@@ -137,0 +137,0 @@ } |
@@ -123,3 +123,3 @@ /** | ||
_getValue(labels) { | ||
const hash = hashObject(labels || {}); | ||
const hash = hashObject(labels || {}, this.sortedLabelNames); | ||
return this.hashMap[hash] ? this.hashMap[hash].value : 0; | ||
@@ -143,3 +143,3 @@ } | ||
validateLabel(this.labelNames, labels); | ||
removeLabels.call(this, this.hashMap, labels); | ||
removeLabels.call(this, this.hashMap, labels, this.sortedLabelNames); | ||
} | ||
@@ -163,3 +163,3 @@ } | ||
validateLabel(gauge.labelNames, labels); | ||
const hash = hashObject(labels); | ||
const hash = hashObject(labels, gauge.sortedLabelNames); | ||
setValueDelta(gauge.hashMap, delta, labels, hash); | ||
@@ -166,0 +166,0 @@ } |
@@ -27,4 +27,6 @@ /** | ||
this.defaultExemplarLabelSet = {}; | ||
this.enableExemplars = false; | ||
if (config.enableExemplars) { | ||
this.enableExemplars = true; | ||
this.observe = this.observeWithExemplar; | ||
@@ -87,3 +89,3 @@ } else { | ||
updateExemplar(labels, value, exemplarLabels) { | ||
const hash = hashObject(labels); | ||
const hash = hashObject(labels, this.sortedLabelNames); | ||
const bound = findBound(this.upperBounds, value); | ||
@@ -137,3 +139,3 @@ const { bucketExemplars } = this.hashMap[hash]; | ||
zero(labels) { | ||
const hash = hashObject(labels); | ||
const hash = hashObject(labels, this.sortedLabelNames); | ||
this.hashMap[hash] = createBaseValues( | ||
@@ -149,2 +151,3 @@ labels, | ||
* @param {object} labels - Object with labels where key is the label key and value is label value. Can only be one level deep | ||
* @param {object} exemplarLabels - Object with labels for exemplar where key is the label key and value is label value. Can only be one level deep | ||
* @returns {function} - Function to invoke when you want to stop the timer and observe the duration in seconds | ||
@@ -158,4 +161,6 @@ * @example | ||
*/ | ||
startTimer(labels) { | ||
return startTimer.call(this, labels)(); | ||
startTimer(labels, exemplarLabels) { | ||
return this.enableExemplars | ||
? startTimerWithExemplar.call(this, labels, exemplarLabels)() | ||
: startTimer.call(this, labels)(); | ||
} | ||
@@ -175,3 +180,3 @@ | ||
validateLabel(this.labelNames, labels); | ||
removeLabels.call(this, this.hashMap, labels); | ||
removeLabels.call(this, this.hashMap, labels, this.sortedLabelNames); | ||
} | ||
@@ -192,2 +197,22 @@ } | ||
function startTimerWithExemplar(startLabels, startExemplarLabels) { | ||
return () => { | ||
const start = process.hrtime(); | ||
return (endLabels, endExemplarLabels) => { | ||
const delta = process.hrtime(start); | ||
const value = delta[0] + delta[1] / 1e9; | ||
this.observe({ | ||
labels: Object.assign({}, startLabels, endLabels), | ||
value, | ||
exemplarLabels: Object.assign( | ||
{}, | ||
startExemplarLabels, | ||
endExemplarLabels, | ||
), | ||
}); | ||
return value; | ||
}; | ||
}; | ||
} | ||
function setValuePair(labels, value, metricName, exemplar, sharedLabels = {}) { | ||
@@ -224,3 +249,3 @@ return { | ||
const hash = hashObject(labelValuePair.labels); | ||
const hash = hashObject(labelValuePair.labels, this.sortedLabelNames); | ||
let valueFromMap = this.hashMap[hash]; | ||
@@ -263,7 +288,7 @@ if (!valueFromMap) { | ||
value, | ||
} | ||
} | ||
: { | ||
value: labels, | ||
labels: {}, | ||
}; | ||
}; | ||
} | ||
@@ -270,0 +295,0 @@ |
@@ -42,2 +42,3 @@ 'use strict'; | ||
} | ||
if (this.collect && typeof this.collect !== 'function') { | ||
@@ -47,2 +48,8 @@ throw new Error('Optional "collect" parameter must be a function'); | ||
if (this.labelNames) { | ||
this.sortedLabelNames = [...this.labelNames].sort(); | ||
} else { | ||
this.sortedLabelNames = []; | ||
} | ||
this.reset(); | ||
@@ -49,0 +56,0 @@ |
@@ -13,21 +13,20 @@ 'use strict'; | ||
function structureOutput(input) { | ||
const returnValue = {}; | ||
return input.split('\n').reduce((acc, string) => { | ||
if (!values.some(value => string.startsWith(value))) { | ||
return acc; | ||
} | ||
input | ||
.split('\n') | ||
.filter(s => values.some(value => s.indexOf(value) === 0)) | ||
.forEach(string => { | ||
const split = string.split(':'); | ||
const split = string.split(':'); | ||
// Get the value | ||
let value = split[1].trim(); | ||
// Remove trailing ` kb` | ||
value = value.substr(0, value.length - 3); | ||
// Make it into a number in bytes bytes | ||
value = Number(value) * 1024; | ||
// Get the value | ||
let value = split[1].trim(); | ||
// Remove trailing ` kb` | ||
value = value.substr(0, value.length - 3); | ||
// Make it into a number in bytes bytes | ||
value = Number(value) * 1024; | ||
returnValue[split[0]] = value; | ||
}); | ||
acc[split[0]] = value; | ||
return returnValue; | ||
return acc; | ||
}, {}); | ||
} | ||
@@ -34,0 +33,0 @@ |
@@ -16,7 +16,12 @@ 'use strict'; | ||
this.gatewayUrl = gatewayUrl; | ||
this.requestOptions = Object.assign({}, options); | ||
const { requireJobName, ...requestOptions } = { | ||
requireJobName: true, | ||
...options, | ||
}; | ||
this.requireJobName = requireJobName; | ||
this.requestOptions = requestOptions; | ||
} | ||
pushAdd(params) { | ||
if (!params || !params.jobName) { | ||
pushAdd(params = {}) { | ||
if (this.requireJobName && !params.jobName) { | ||
throw new Error('Missing jobName parameter'); | ||
@@ -28,4 +33,4 @@ } | ||
push(params) { | ||
if (!params || !params.jobName) { | ||
push(params = {}) { | ||
if (this.requireJobName && !params.jobName) { | ||
throw new Error('Missing jobName parameter'); | ||
@@ -37,4 +42,4 @@ } | ||
delete(params) { | ||
if (!params || !params.jobName) { | ||
delete(params = {}) { | ||
if (this.requireJobName && !params.jobName) { | ||
throw new Error('Missing jobName parameter'); | ||
@@ -54,5 +59,6 @@ } | ||
: ''; | ||
const path = `${gatewayUrlPath}/metrics/job/${encodeURIComponent( | ||
job, | ||
)}${generateGroupings(groupings)}`; | ||
const jobPath = job | ||
? `/job/${encodeURIComponent(job)}${generateGroupings(groupings)}` | ||
: ''; | ||
const path = `${gatewayUrlPath}/metrics${jobPath}`; | ||
@@ -59,0 +65,0 @@ // eslint-disable-next-line node/no-deprecated-api |
@@ -118,3 +118,3 @@ /** | ||
validateLabel(this.labelNames, labels); | ||
removeLabels.call(this, this.hashMap, labels); | ||
removeLabels.call(this, this.hashMap, labels, this.sortedLabelNames); | ||
} | ||
@@ -174,3 +174,3 @@ } | ||
const hash = hashObject(labelValuePair.labels); | ||
const hash = hashObject(labelValuePair.labels, this.sortedLabelNames); | ||
let summaryOfLabel = this.hashMap[hash]; | ||
@@ -177,0 +177,0 @@ if (!summaryOfLabel) { |
@@ -17,4 +17,8 @@ 'use strict'; | ||
exports.removeLabels = function removeLabels(hashMap, labels) { | ||
const hash = hashObject(labels); | ||
exports.removeLabels = function removeLabels( | ||
hashMap, | ||
labels, | ||
sortedLabelNames, | ||
) { | ||
const hash = hashObject(labels, sortedLabelNames); | ||
delete hashMap[hash]; | ||
@@ -63,28 +67,40 @@ }; | ||
function hashObject(labels) { | ||
// We don't actually need a hash here. We just need a string that | ||
// is unique for each possible labels object and consistent across | ||
// calls with equivalent labels objects. | ||
let keys = Object.keys(labels); | ||
function fastHashObject(keys, labels) { | ||
if (keys.length === 0) { | ||
return ''; | ||
} | ||
// else | ||
if (keys.length > 1) { | ||
keys = keys.sort(); // need consistency across calls | ||
} | ||
let hash = ''; | ||
let i = 0; | ||
const size = keys.length; | ||
for (; i < size - 1; i++) { | ||
hash += `${keys[i]}:${labels[keys[i]]},`; | ||
for (let i = 0; i < keys.length; i++) { | ||
const key = keys[i]; | ||
const value = labels[key]; | ||
if (value === undefined) continue; | ||
hash += `${key}:${value},`; | ||
} | ||
hash += `${keys[i]}:${labels[keys[i]]}`; | ||
return hash; | ||
} | ||
function hashObject(labels, labelNames) { | ||
// We don't actually need a hash here. We just need a string that | ||
// is unique for each possible labels object and consistent across | ||
// calls with equivalent labels objects. | ||
if (labelNames) { | ||
return fastHashObject(labelNames, labels); | ||
} | ||
const keys = Object.keys(labels); | ||
if (keys.length > 1) { | ||
keys.sort(); // need consistency across calls | ||
} | ||
return fastHashObject(keys, labels); | ||
} | ||
exports.hashObject = hashObject; | ||
exports.isObject = function isObject(obj) { | ||
return obj === Object(obj); | ||
return obj !== null && typeof obj === 'object'; | ||
}; | ||
@@ -91,0 +107,0 @@ |
{ | ||
"name": "prom-client", | ||
"version": "15.0.0", | ||
"version": "15.1.0", | ||
"description": "Client for prometheus", | ||
@@ -38,5 +38,5 @@ "main": "index.js", | ||
"eslint": "^8.32.0", | ||
"eslint-config-prettier": "^8.6.0", | ||
"eslint-config-prettier": "^9.1.0", | ||
"eslint-plugin-node": "^11.0.0", | ||
"eslint-plugin-prettier": "^4.2.1", | ||
"eslint-plugin-prettier": "^5.0.1", | ||
"express": "^4.13.3", | ||
@@ -47,3 +47,3 @@ "husky": "^8.0.3", | ||
"nock": "^13.0.5", | ||
"prettier": "2.8.8", | ||
"prettier": "3.1.1", | ||
"typescript": "^5.0.4" | ||
@@ -50,0 +50,0 @@ }, |
@@ -584,2 +584,12 @@ # Prometheus client for node.js [![Actions Status](https://github.com/siimon/prom-client/workflows/Node.js%20CI/badge.svg?branch=master)](https://github.com/siimon/prom-client/actions) | ||
Some gateways such as [Gravel Gateway](https://github.com/sinkingpoint/prometheus-gravel-gateway) do not support grouping by job name, exposing a plain `/metrics` endpoint instead of `/metrics/job/<jobName>`. It's possible to configure a gateway instance to not require a jobName in the options argument. | ||
```js | ||
gravelGateway = new client.Pushgateway('http://127.0.0.1:9091', { | ||
timeout: 5000, | ||
requireJobName: false, | ||
}); | ||
gravelGateway.pushAdd(); | ||
``` | ||
### Bucket Generators | ||
@@ -586,0 +596,0 @@ |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
125327
3132
620