prom-client
Advanced tools
Comparing version 14.2.0 to 15.0.0-0
// Type definitions for prom-client | ||
// Definitions by: Simon Nyberg http://twitter.com/siimon_nyberg | ||
export type Charset = 'utf-8'; | ||
export type PrometheusMIME = 'text/plain'; | ||
export type PrometheusMetricsVersion = '0.0.4'; | ||
export type OpenMetricsMIME = 'application/openmetrics-text'; | ||
export type OpenMetricsVersion = '1.0.0'; | ||
export type PrometheusContentType = | ||
`${OpenMetricsMIME}; version=${OpenMetricsVersion}; charset=${Charset}`; | ||
export type OpenMetricsContentType = | ||
`${PrometheusMIME}; version=${PrometheusMetricsVersion}; charset=${Charset}`; | ||
export type RegistryContentType = | ||
| PrometheusContentType | ||
| OpenMetricsContentType; | ||
/** | ||
* Container for all registered metrics | ||
*/ | ||
export class Registry { | ||
export class Registry<RegistryContentType = PrometheusContentType> { | ||
/** | ||
@@ -67,5 +84,12 @@ * Get string representation for all metrics | ||
*/ | ||
contentType: string; | ||
contentType: RegistryContentType; | ||
/** | ||
* Set the content type of a registry. Used to change between Prometheus and | ||
* OpenMetrics versions. | ||
* @param contentType The type of the registry | ||
*/ | ||
setContentType(contentType: RegistryContentType): void; | ||
/** | ||
* Merge registers | ||
@@ -84,6 +108,17 @@ * @param registers The registers you want to merge together | ||
/** | ||
* The Content-Type of the metrics for use in the response headers. | ||
* HTTP Content-Type for metrics response headers, defaults to Prometheus text | ||
* format. | ||
*/ | ||
export const contentType: string; | ||
export const contentType: RegistryContentType; | ||
/** | ||
* HTTP Prometheus Content-Type for metrics response headers. | ||
*/ | ||
export const prometheusContentType: PrometheusContentType; | ||
/** | ||
* HTTP OpenMetrics Content-Type for metrics response headers. | ||
*/ | ||
export const openMetricsContentType: OpenMetricsContentType; | ||
export class AggregatorRegistry extends Registry { | ||
@@ -169,5 +204,9 @@ /** | ||
labelNames?: T[] | readonly T[]; | ||
registers?: Registry[]; | ||
registers?: ( | ||
| Registry<PrometheusContentType> | ||
| Registry<OpenMetricsContentType> | ||
)[]; | ||
aggregator?: Aggregator; | ||
collect?: CollectFunction<any>; | ||
enableExemplars?: boolean; | ||
} | ||
@@ -180,2 +219,14 @@ | ||
export interface IncreaseDataWithExemplar<T extends string> { | ||
value?: number; | ||
labels?: LabelValues<T>; | ||
exemplarLabels?: LabelValues<T>; | ||
} | ||
export interface ObserveDataWithExemplar<T extends string> { | ||
value: number; | ||
labels?: LabelValues<T>; | ||
exemplarLabels?: LabelValues<T>; | ||
} | ||
/** | ||
@@ -204,2 +255,8 @@ * A counter is a cumulative metric that represents a single numerical value that only ever goes up | ||
/** | ||
* Increment with exemplars | ||
* @param incData Object with labels, value and exemplars for an increase | ||
*/ | ||
inc(incData: IncreaseDataWithExemplar<T>): void; | ||
/** | ||
* Get counter metric object | ||
@@ -419,2 +476,8 @@ */ | ||
/** | ||
* Observe with exemplars | ||
* @param observeData Object with labels, value and exemplars for an observation | ||
*/ | ||
observe(observeData: ObserveDataWithExemplar<T>): void; | ||
/** | ||
* Get histogram metric object | ||
@@ -421,0 +484,0 @@ */ |
@@ -11,2 +11,6 @@ /** | ||
exports.contentType = require('./lib/registry').globalRegistry.contentType; | ||
exports.prometheusContentType = | ||
require('./lib/registry').PROMETHEUS_CONTENT_TYPE; | ||
exports.openMetricsContentType = | ||
require('./lib/registry').OPENMETRICS_CONTENT_TYPE; | ||
exports.validateMetricName = require('./lib/validation').validateMetricName; | ||
@@ -13,0 +17,0 @@ |
@@ -31,4 +31,4 @@ 'use strict'; | ||
class AggregatorRegistry extends Registry { | ||
constructor() { | ||
super(); | ||
constructor(regContentType = Registry.PROMETHEUS_CONTENT_TYPE) { | ||
super(regContentType); | ||
addListeners(); | ||
@@ -88,2 +88,6 @@ } | ||
get contentType() { | ||
return super.contentType; | ||
} | ||
/** | ||
@@ -96,8 +100,15 @@ * Creates a new Registry instance from an array of metrics that were | ||
* `registry.getMetricsAsJSON()`. | ||
* @param {string} registryType content type of the new registry. Defaults | ||
* to PROMETHEUS_CONTENT_TYPE. | ||
* @return {Registry} aggregated registry. | ||
*/ | ||
static aggregate(metricsArr) { | ||
static aggregate( | ||
metricsArr, | ||
registryType = Registry.PROMETHEUS_CONTENT_TYPE, | ||
) { | ||
const aggregatedRegistry = new Registry(); | ||
const metricsByName = new Grouper(); | ||
aggregatedRegistry.setContentType(registryType); | ||
// Gather by name | ||
@@ -104,0 +115,0 @@ metricsArr.forEach(metrics => { |
@@ -7,8 +7,28 @@ /** | ||
const util = require('util'); | ||
const type = 'counter'; | ||
const { hashObject, isObject, getLabels, removeLabels } = require('./util'); | ||
const { | ||
hashObject, | ||
isObject, | ||
getLabels, | ||
removeLabels, | ||
nowTimestamp, | ||
} = require('./util'); | ||
const { validateLabel } = require('./validation'); | ||
const { Metric } = require('./metric'); | ||
const Exemplar = require('./exemplar'); | ||
class Counter extends Metric { | ||
constructor(config) { | ||
super(config); | ||
this.type = 'counter'; | ||
this.defaultLabels = {}; | ||
this.defaultValue = 1; | ||
this.defaultExemplarLabelSet = {}; | ||
if (config.enableExemplars) { | ||
this.enableExemplars = true; | ||
this.inc = this.incWithExemplar; | ||
} else { | ||
this.inc = this.incWithoutExemplar; | ||
} | ||
} | ||
/** | ||
@@ -18,6 +38,7 @@ * Increment counter | ||
* @param {Number} value - Value to increment, if omitted increment with 1 | ||
* @returns {void} | ||
* @returns {object} results - object with information about the inc operation | ||
* @returns {string} results.labelHash - hash representation of the labels | ||
*/ | ||
inc(labels, value) { | ||
let hash; | ||
incWithoutExemplar(labels, value) { | ||
let hash = ''; | ||
if (isObject(labels)) { | ||
@@ -41,5 +62,40 @@ hash = hashObject(labels); | ||
setValue(this.hashMap, value, labels, hash); | ||
return { labelHash: hash }; | ||
} | ||
/** | ||
* Increment counter with exemplar, same as inc but accepts labels for an | ||
* exemplar. | ||
* If no label is provided the current exemplar labels are kept unchanged | ||
* (defaults to empty set). | ||
* | ||
* @param {object} incOpts - Object with options about what metric to increase | ||
* @param {object} incOpts.labels - What label you want to be incremented, | ||
* defaults to null (metric with no labels) | ||
* @param {Number} incOpts.value - Value to increment, defaults to 1 | ||
* @param {object} incOpts.exemplarLabels - Key-value labels for the | ||
* exemplar, defaults to empty set {} | ||
* @returns {void} | ||
*/ | ||
incWithExemplar({ | ||
labels = this.defaultLabels, | ||
value = this.defaultValue, | ||
exemplarLabels = this.defaultExemplarLabelSet, | ||
} = {}) { | ||
const res = this.incWithoutExemplar(labels, value); | ||
this.updateExemplar(exemplarLabels, value, res.labelHash); | ||
} | ||
updateExemplar(exemplarLabels, value, hash) { | ||
if (!isObject(this.hashMap[hash].exemplar)) { | ||
this.hashMap[hash].exemplar = new Exemplar(); | ||
} | ||
this.hashMap[hash].exemplar.validateExemplarLabelSet(exemplarLabels); | ||
this.hashMap[hash].exemplar.labelSet = exemplarLabels; | ||
this.hashMap[hash].exemplar.value = value ? value : 1; | ||
this.hashMap[hash].exemplar.timestamp = nowTimestamp(); | ||
} | ||
/** | ||
* Reset counter | ||
@@ -60,6 +116,7 @@ * @returns {void} | ||
} | ||
return { | ||
help: this.help, | ||
name: this.name, | ||
type, | ||
type: this.type, | ||
values: Object.values(this.hashMap), | ||
@@ -66,0 +123,0 @@ aggregator: this.aggregator, |
@@ -7,3 +7,2 @@ /** | ||
const util = require('util'); | ||
const type = 'gauge'; | ||
@@ -22,2 +21,7 @@ const { | ||
class Gauge extends Metric { | ||
constructor(config) { | ||
super(config); | ||
this.type = 'gauge'; | ||
} | ||
/** | ||
@@ -114,3 +118,3 @@ * Set a gauge to a value | ||
name: this.name, | ||
type, | ||
type: this.type, | ||
values: Object.values(this.hashMap), | ||
@@ -117,0 +121,0 @@ aggregator: this.aggregator, |
@@ -7,6 +7,12 @@ /** | ||
const util = require('util'); | ||
const type = 'histogram'; | ||
const { getLabels, hashObject, isObject, removeLabels } = require('./util'); | ||
const { | ||
getLabels, | ||
hashObject, | ||
isObject, | ||
removeLabels, | ||
nowTimestamp, | ||
} = require('./util'); | ||
const { validateLabel } = require('./validation'); | ||
const { Metric } = require('./metric'); | ||
const Exemplar = require('./exemplar'); | ||
@@ -19,2 +25,12 @@ class Histogram extends Metric { | ||
this.type = 'histogram'; | ||
this.defaultLabels = {}; | ||
this.defaultExemplarLabelSet = {}; | ||
if (config.enableExemplars) { | ||
this.observe = this.observeWithExemplar; | ||
} else { | ||
this.observe = this.observeWithoutExemplar; | ||
} | ||
for (const label of this.labelNames) { | ||
@@ -32,3 +48,9 @@ if (label === 'le') { | ||
this.bucketExemplars = this.upperBounds.reduce((acc, upperBound) => { | ||
acc[upperBound] = null; | ||
return acc; | ||
}, {}); | ||
Object.freeze(this.bucketValues); | ||
Object.freeze(this.bucketExemplars); | ||
Object.freeze(this.upperBounds); | ||
@@ -41,2 +63,3 @@ | ||
Object.assign({}, this.bucketValues), | ||
Object.assign({}, this.bucketExemplars), | ||
), | ||
@@ -53,6 +76,29 @@ }; | ||
*/ | ||
observe(labels, value) { | ||
observeWithoutExemplar(labels, value) { | ||
observe.call(this, labels === 0 ? 0 : labels || {})(value); | ||
} | ||
observeWithExemplar({ | ||
labels = this.defaultLabels, | ||
value, | ||
exemplarLabels = this.defaultExemplarLabelSet, | ||
} = {}) { | ||
observe.call(this, labels === 0 ? 0 : labels || {})(value); | ||
this.updateExemplar(labels, value, exemplarLabels); | ||
} | ||
updateExemplar(labels, value, exemplarLabels) { | ||
const hash = hashObject(labels); | ||
const b = findBound(this.upperBounds, value); | ||
if (!isObject(this.hashMap[hash].bucketExemplars[b])) { | ||
this.hashMap[hash].bucketExemplars[b] = new Exemplar(); | ||
} | ||
this.hashMap[hash].bucketExemplars[b].validateExemplarLabelSet( | ||
exemplarLabels, | ||
); | ||
this.hashMap[hash].bucketExemplars[b].labelSet = exemplarLabels; | ||
this.hashMap[hash].bucketExemplars[b].value = value; | ||
this.hashMap[hash].bucketExemplars[b].timestamp = nowTimestamp(); | ||
} | ||
async get() { | ||
@@ -71,3 +117,3 @@ if (this.collect) { | ||
help: this.help, | ||
type, | ||
type: this.type, | ||
values, | ||
@@ -92,2 +138,3 @@ aggregator: this.aggregator, | ||
Object.assign({}, this.bucketValues), | ||
Object.assign({}, this.bucketExemplars), | ||
); | ||
@@ -139,3 +186,3 @@ } | ||
function setValuePair(labels, value, metricName) { | ||
function setValuePair(labels, value, metricName, exemplar) { | ||
return { | ||
@@ -145,2 +192,3 @@ labels, | ||
metricName, | ||
exemplar, | ||
}; | ||
@@ -176,2 +224,3 @@ } | ||
Object.assign({}, this.bucketValues), | ||
Object.assign({}, this.bucketExemplars), | ||
); | ||
@@ -193,6 +242,7 @@ } | ||
function createBaseValues(labels, bucketValues) { | ||
function createBaseValues(labels, bucketValues, bucketExemplars) { | ||
return { | ||
labels, | ||
bucketValues, | ||
bucketExemplars, | ||
sum: 0, | ||
@@ -227,3 +277,10 @@ count: 0, | ||
} | ||
buckets.push(setValuePair(lbls, acc, `${histogram.name}_bucket`)); | ||
buckets.push( | ||
setValuePair( | ||
lbls, | ||
acc, | ||
`${histogram.name}_bucket`, | ||
bucketData.bucketExemplars[upperBound], | ||
), | ||
); | ||
} | ||
@@ -243,3 +300,8 @@ return { buckets, data: bucketData }; | ||
acc.push( | ||
setValuePair(infLabel, d.data.count, `${histogram.name}_bucket`), | ||
setValuePair( | ||
infLabel, | ||
d.data.count, | ||
`${histogram.name}_bucket`, | ||
d.data.bucketExemplars['-1'], | ||
), | ||
setValuePair(d.data.labels, d.data.sum, `${histogram.name}_sum`), | ||
@@ -246,0 +308,0 @@ setValuePair(d.data.labels, d.data.count, `${histogram.name}_count`), |
'use strict'; | ||
const { globalRegistry } = require('./registry'); | ||
const Registry = require('./registry'); | ||
const { isObject } = require('./util'); | ||
@@ -19,4 +19,5 @@ const { validateMetricName, validateLabelName } = require('./validation'); | ||
labelNames: [], | ||
registers: [globalRegistry], | ||
registers: [Registry.globalRegistry], | ||
aggregator: 'sum', | ||
enableExemplars: false, | ||
}, | ||
@@ -28,3 +29,3 @@ defaults, | ||
// in case config.registers is `undefined` | ||
this.registers = [globalRegistry]; | ||
this.registers = [Registry.globalRegistry]; | ||
} | ||
@@ -50,2 +51,10 @@ if (!this.help) { | ||
for (const register of this.registers) { | ||
if ( | ||
this.enableExemplars && | ||
register.contentType === Registry.PROMETHEUS_CONTENT_TYPE | ||
) { | ||
throw new TypeError( | ||
'Exemplars are supported only on OpenMetrics registries', | ||
); | ||
} | ||
register.registerMetric(this); | ||
@@ -52,0 +61,0 @@ } |
@@ -40,2 +40,3 @@ 'use strict'; | ||
labelNames: ['kind', ...labelNames], | ||
enableExemplars: false, | ||
buckets, | ||
@@ -51,3 +52,2 @@ registers: registry ? [registry] : undefined, | ||
const kind = entry.detail ? kinds[entry.detail.kind] : kinds[entry.kind]; | ||
// Convert duration from milliseconds to seconds | ||
@@ -54,0 +54,0 @@ gcHistogram.observe(Object.assign({ kind }, labels), entry.duration / 1000); |
'use strict'; | ||
const OtelApi = require('@opentelemetry/api'); | ||
const Counter = require('../counter'); | ||
const PROCESS_CPU_USER_SECONDS = 'process_cpu_user_seconds_total'; | ||
@@ -12,2 +14,3 @@ const PROCESS_CPU_SYSTEM_SECONDS = 'process_cpu_system_seconds_total'; | ||
const labels = config.labels ? config.labels : {}; | ||
const exemplars = config.enableExemplars ? config.enableExemplars : false; | ||
const labelNames = Object.keys(labels); | ||
@@ -20,2 +23,3 @@ | ||
help: 'Total user CPU time spent in seconds.', | ||
enableExemplars: exemplars, | ||
registers, | ||
@@ -32,5 +36,34 @@ labelNames, | ||
cpuUserUsageCounter.inc(labels, userUsageMicros / 1e6); | ||
cpuSystemUsageCounter.inc(labels, systemUsageMicros / 1e6); | ||
cpuUsageCounter.inc(labels, (userUsageMicros + systemUsageMicros) / 1e6); | ||
if (this.enableExemplars) { | ||
let exemplarLabels = {}; | ||
const currentSpan = OtelApi.trace.getSpan(OtelApi.context.active()); | ||
if (currentSpan) { | ||
exemplarLabels = { | ||
traceId: currentSpan.spanContext().traceId, | ||
spanId: currentSpan.spanContext().spanId, | ||
}; | ||
} | ||
cpuUserUsageCounter.inc({ | ||
labels, | ||
value: userUsageMicros / 1e6, | ||
exemplarLabels, | ||
}); | ||
cpuSystemUsageCounter.inc({ | ||
labels, | ||
value: systemUsageMicros / 1e6, | ||
exemplarLabels, | ||
}); | ||
cpuUsageCounter.inc({ | ||
labels, | ||
value: (userUsageMicros + systemUsageMicros) / 1e6, | ||
exemplarLabels, | ||
}); | ||
} else { | ||
cpuUserUsageCounter.inc(labels, userUsageMicros / 1e6); | ||
cpuSystemUsageCounter.inc(labels, systemUsageMicros / 1e6); | ||
cpuUsageCounter.inc( | ||
labels, | ||
(userUsageMicros + systemUsageMicros) / 1e6, | ||
); | ||
} | ||
}, | ||
@@ -41,2 +74,3 @@ }); | ||
help: 'Total system CPU time spent in seconds.', | ||
enableExemplars: exemplars, | ||
registers, | ||
@@ -48,2 +82,3 @@ labelNames, | ||
help: 'Total user and system CPU time spent in seconds.', | ||
enableExemplars: exemplars, | ||
registers, | ||
@@ -50,0 +85,0 @@ labelNames, |
'use strict'; | ||
const { getValueAsString } = require('./util'); | ||
function escapeString(str) { | ||
return str.replace(/\n/g, '\\n').replace(/\\(?!n)/g, '\\\\'); | ||
} | ||
function escapeLabelValue(str) { | ||
if (typeof str !== 'string') { | ||
return str; | ||
class Registry { | ||
static get PROMETHEUS_CONTENT_TYPE() { | ||
return 'text/plain; version=0.0.4; charset=utf-8'; | ||
} | ||
return escapeString(str).replace(/"/g, '\\"'); | ||
} | ||
class Registry { | ||
constructor() { | ||
static get OPENMETRICS_CONTENT_TYPE() { | ||
return 'application/openmetrics-text; version=1.0.0; charset=utf-8'; | ||
} | ||
constructor(regContentType = Registry.PROMETHEUS_CONTENT_TYPE) { | ||
this._metrics = {}; | ||
this._collectors = []; | ||
this._defaultLabels = {}; | ||
if ( | ||
regContentType !== Registry.PROMETHEUS_CONTENT_TYPE && | ||
regContentType !== Registry.OPENMETRICS_CONTENT_TYPE | ||
) { | ||
throw new TypeError(`Content type ${regContentType} is unsupported`); | ||
} | ||
this._contentType = regContentType; | ||
} | ||
@@ -25,20 +31,27 @@ | ||
async getMetricAsPrometheusString(metric) { | ||
const item = await metric.get(); | ||
const name = escapeString(item.name); | ||
const help = `# HELP ${name} ${escapeString(item.help)}`; | ||
const type = `# TYPE ${name} ${item.type}`; | ||
async getMetricsAsString(metrics) { | ||
const metric = await metrics.get(); | ||
const name = escapeString(metric.name); | ||
const help = `# HELP ${name} ${escapeString(metric.help)}`; | ||
const type = `# TYPE ${name} ${metric.type}`; | ||
const values = [help, type]; | ||
const defaultLabels = | ||
Object.keys(this._defaultLabels).length > 0 ? this._defaultLabels : null; | ||
const values = [help, type]; | ||
for (const { metricName = item.name, value, labels = {} } of item.values || | ||
[]) { | ||
const labelsWithDefaults = defaultLabels | ||
? { ...labels, ...defaultLabels, ...labels } | ||
: labels; | ||
for (const val of metric.values || []) { | ||
let { metricName = name, labels = {} } = val; | ||
if ( | ||
this.contentType === Registry.OPENMETRICS_CONTENT_TYPE && | ||
metric.type === 'counter' | ||
) { | ||
metricName = `${metricName}_total`; | ||
} | ||
const formattedLabels = Object.entries(labelsWithDefaults).map( | ||
([n, v]) => `${n}="${escapeLabelValue(v)}"`, | ||
); | ||
if (defaultLabels) { | ||
labels = { ...labels, ...defaultLabels, ...labels }; | ||
} | ||
const formattedLabels = formatLabels(labels); | ||
const labelsString = formattedLabels.length | ||
@@ -48,3 +61,15 @@ ? `{${formattedLabels.join(',')}}` | ||
values.push(`${metricName}${labelsString} ${getValueAsString(value)}`); | ||
values.push( | ||
`${metricName}${labelsString} ${getValueAsString(val.value)}`, | ||
); | ||
const { exemplar } = val; | ||
if (exemplar && this.contentType === Registry.OPENMETRICS_CONTENT_TYPE) { | ||
const formattedExemplars = formatLabels(exemplar.labelSet); | ||
values.push( | ||
` # {${formattedExemplars.join(',')}} ${getValueAsString( | ||
exemplar.value, | ||
)} ${exemplar.timestamp}`, | ||
); | ||
} | ||
} | ||
@@ -59,3 +84,9 @@ | ||
for (const metric of this.getMetricsAsArray()) { | ||
promises.push(this.getMetricAsPrometheusString(metric)); | ||
if ( | ||
this.contentType === Registry.OPENMETRICS_CONTENT_TYPE && | ||
metric.type === 'counter' | ||
) { | ||
metric.name = standardizeCounterName(metric.name); | ||
} | ||
promises.push(this.getMetricsAsString(metric)); | ||
} | ||
@@ -65,3 +96,7 @@ | ||
return `${resolves.join('\n\n')}\n`; | ||
if (this.contentType === Registry.OPENMETRICS_CONTENT_TYPE) { | ||
return `${resolves.join('\n')}\n# EOF\n`; | ||
} else { | ||
return `${resolves.join('\n\n')}\n`; | ||
} | ||
} | ||
@@ -120,3 +155,3 @@ | ||
getSingleMetricAsString(name) { | ||
return this.getMetricAsPrometheusString(this._metrics[name]); | ||
return this.getMetricsAsString(this._metrics[name]); | ||
} | ||
@@ -139,7 +174,26 @@ | ||
get contentType() { | ||
return 'text/plain; version=0.0.4; charset=utf-8'; | ||
return this._contentType; | ||
} | ||
setContentType(metricsContentType) { | ||
if ( | ||
metricsContentType === Registry.OPENMETRICS_CONTENT_TYPE || | ||
metricsContentType === Registry.PROMETHEUS_CONTENT_TYPE | ||
) { | ||
this._contentType = metricsContentType; | ||
} else { | ||
throw new Error(`Content type ${metricsContentType} is unsupported`); | ||
} | ||
} | ||
static merge(registers) { | ||
const mergedRegistry = new Registry(); | ||
const regType = registers[0].contentType; | ||
for (const reg of registers) { | ||
if (reg.contentType !== regType) { | ||
throw new Error( | ||
'Registers can only be merged if they have the same content type', | ||
); | ||
} | ||
} | ||
const mergedRegistry = new Registry(regType); | ||
@@ -156,3 +210,22 @@ const metricsToMerge = registers.reduce( | ||
function formatLabels(labels) { | ||
return Object.entries(labels).map( | ||
([n, v]) => `${n}="${escapeLabelValue(v)}"`, | ||
); | ||
} | ||
function escapeLabelValue(str) { | ||
if (typeof str !== 'string') { | ||
return str; | ||
} | ||
return escapeString(str).replace(/"/g, '\\"'); | ||
} | ||
function escapeString(str) { | ||
return str.replace(/\\/g, '\\\\').replace(/\n/g, '\\n'); | ||
} | ||
function standardizeCounterName(name) { | ||
return name.replace(/_total$/, ''); | ||
} | ||
module.exports = Registry; | ||
module.exports.globalRegistry = new Registry(); |
@@ -7,3 +7,2 @@ /** | ||
const util = require('util'); | ||
const type = 'summary'; | ||
const { getLabels, hashObject, removeLabels } = require('./util'); | ||
@@ -24,2 +23,4 @@ const { validateLabel } = require('./validation'); | ||
this.type = 'summary'; | ||
for (const label of this.labelNames) { | ||
@@ -78,3 +79,3 @@ if (label === 'quantile') | ||
help: this.help, | ||
type, | ||
type: this.type, | ||
values, | ||
@@ -81,0 +82,0 @@ aggregator: this.aggregator, |
@@ -90,2 +90,6 @@ 'use strict'; | ||
exports.nowTimestamp = function nowTimestamp() { | ||
return Date.now() / 1000; | ||
}; | ||
class Grouper extends Map { | ||
@@ -92,0 +96,0 @@ /** |
{ | ||
"name": "prom-client", | ||
"version": "14.2.0", | ||
"version": "15.0.0-0", | ||
"description": "Client for prometheus", | ||
@@ -12,3 +12,3 @@ "main": "index.js", | ||
"engines": { | ||
"node": ">=10" | ||
"node": ">=14" | ||
}, | ||
@@ -38,15 +38,16 @@ "scripts": { | ||
"@clevernature/benchmark-regression": "^1.0.0", | ||
"eslint": "^7.7.0", | ||
"eslint-config-prettier": "^6.10.0", | ||
"eslint": "^8.32.0", | ||
"eslint-config-prettier": "^8.6.0", | ||
"eslint-plugin-node": "^11.0.0", | ||
"eslint-plugin-prettier": "^3.0.1", | ||
"eslint-plugin-prettier": "^4.2.1", | ||
"express": "^4.13.3", | ||
"husky": "^4.2.1", | ||
"jest": "^26.0.1", | ||
"lint-staged": "^10.0.4", | ||
"husky": "^8.0.3", | ||
"jest": "^29.3.1", | ||
"lint-staged": "^13.1.0", | ||
"nock": "^13.0.5", | ||
"prettier": "2.7.1", | ||
"prettier": "2.8.3", | ||
"typescript": "^4.0.2" | ||
}, | ||
"dependencies": { | ||
"@opentelemetry/api": "^1.4.0", | ||
"tdigest": "^0.1.1" | ||
@@ -84,8 +85,3 @@ }, | ||
] | ||
}, | ||
"husky": { | ||
"hooks": { | ||
"pre-commit": "lint-staged" | ||
} | ||
} | ||
} |
@@ -396,2 +396,43 @@ # 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) | ||
### Exemplars | ||
The exemplars defined in the OpenMetrics specification can be enabled on Counter | ||
and Histogram metric types. The default metrics have support for OpenTelemetry, | ||
they will populate the exemplars with the labels `{traceId, spanId}` and their | ||
corresponding values. | ||
The format for `inc()` and `observe()` calls are different if exemplars are | ||
enabled. They get a single object with the format | ||
`{labels, value, exemplarLabels}`. | ||
When using exemplars, the registry used for metrics should be set to OpenMetrics | ||
type (including the global or default registry if no registries are specified). | ||
### Registy type | ||
The library supports both the old Prometheus format and the OpenMetrics format. | ||
The format can be set per registry. For default metrics: | ||
```js | ||
const Prometheus = require('prom-client'); | ||
Prometheus.register.setContentType( | ||
Prometheus.Registry.OPENMETRICS_CONTENT_TYPE, | ||
); | ||
``` | ||
Currently available registry types are defined by the content types: | ||
**PROMETHEUS_CONTENT_TYPE** - version 0.0.4 of the original Prometheus metrics, | ||
this is currently the default registry type. | ||
**OPENMETRICS_CONTENT_TYPE** - defaults to version 1.0.0 of the | ||
[OpenMetrics standard](https://github.com/OpenObservability/OpenMetrics/blob/d99b705f611b75fec8f450b05e344e02eea6921d/specification/OpenMetrics.md). | ||
The HTTP Content-Type string for each registry type is exposed both at module | ||
level (`prometheusContentType` and `openMetricsContentType`) and as static | ||
properties on the `Registry` object. | ||
The `contentType` constant exposed by the module returns the default content | ||
type when creating a new registry, currently defaults to Prometheus type. | ||
### Multiple registries | ||
@@ -411,2 +452,5 @@ | ||
Merging registries of different types is undefined. The user needs to make sure | ||
all used registries have the same type (Prometheus or OpenMetrics versions). | ||
```js | ||
@@ -455,3 +499,3 @@ const client = require('prom-client'); | ||
If you need to get a reference to a previously registered metric, you can use | ||
`await register.getSingleMetric(*name of metric*)`. | ||
`register.getSingleMetric(*name of metric*)`. | ||
@@ -563,5 +607,2 @@ #### Removing metrics | ||
The content-type prometheus expects is also exported as a constant, both on the | ||
`register` and from the main file of this project, called `contentType`. | ||
### Garbage Collection Metrics | ||
@@ -568,0 +609,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
No v1
QualityPackage is not semver >=1. This means it is not stable and does not support ^ ranges.
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
121107
36
3019
610
2
1
+ Added@opentelemetry/api@^1.4.0
+ Added@opentelemetry/api@1.9.0(transitive)