mirror of
https://github.com/yu-i-i/overleaf-cep.git
synced 2026-11-14 14:13:43 +01:00
Merge pull request #6927 from overleaf/jpa-split-clsi-metrics
[misc] split clsi metrics into multiple categories GitOrigin-RevId: 964ab57b344b92383a2937beff50139bae273a0e
This commit is contained in:
@@ -131,18 +131,31 @@ function timing(key, timeSpan, sampleRate = 1, opts = {}) {
|
||||
}
|
||||
}
|
||||
|
||||
function histogram(key, value, buckets, opts = {}) {
|
||||
key = buildPromKey('histogram_' + key)
|
||||
promWrapper.metric('histogram', key, buckets).observe(opts, value)
|
||||
if (process.env.DEBUG_METRICS) {
|
||||
console.log('doing histogram', key, buckets, opts)
|
||||
}
|
||||
}
|
||||
|
||||
class Timer {
|
||||
constructor(key, sampleRate = 1, opts = {}) {
|
||||
constructor(key, sampleRate = 1, opts = {}, buckets) {
|
||||
this.start = new Date()
|
||||
key = buildPromKey(key)
|
||||
this.key = key
|
||||
this.sampleRate = sampleRate
|
||||
this.opts = opts
|
||||
this.buckets = buckets
|
||||
}
|
||||
|
||||
done() {
|
||||
const timeSpan = new Date() - this.start
|
||||
timing(this.key, timeSpan, this.sampleRate, this.opts)
|
||||
if (this.buckets) {
|
||||
histogram(this.key, timeSpan, this.buckets, this.opts)
|
||||
} else {
|
||||
timing(this.key, timeSpan, this.sampleRate, this.opts)
|
||||
}
|
||||
return timeSpan
|
||||
}
|
||||
}
|
||||
@@ -181,6 +194,7 @@ module.exports.inc = inc
|
||||
module.exports.count = count
|
||||
module.exports.summary = summary
|
||||
module.exports.timing = timing
|
||||
module.exports.histogram = histogram
|
||||
module.exports.Timer = Timer
|
||||
module.exports.gauge = gauge
|
||||
module.exports.globalGauge = globalGauge
|
||||
|
||||
@@ -29,6 +29,8 @@ const optsKey = function (opts) {
|
||||
}
|
||||
|
||||
const extendOpts = function (opts, labelNames) {
|
||||
// Make a clone in order to be able to re-use opts for other kinds of metrics.
|
||||
opts = Object.assign({}, opts)
|
||||
for (const label of Array.from(labelNames)) {
|
||||
if (!opts[label]) {
|
||||
opts[label] = ''
|
||||
@@ -49,15 +51,15 @@ const PromWrapper = {
|
||||
ttlInMinutes: 0,
|
||||
registry,
|
||||
|
||||
metric(type, name) {
|
||||
return metrics.get(name) || new MetricWrapper(type, name)
|
||||
metric(type, name, buckets) {
|
||||
return metrics.get(name) || new MetricWrapper(type, name, buckets)
|
||||
},
|
||||
|
||||
collectDefaultMetrics: prom.collectDefaultMetrics,
|
||||
}
|
||||
|
||||
class MetricWrapper {
|
||||
constructor(type, name) {
|
||||
constructor(type, name, buckets) {
|
||||
metrics.set(name, this)
|
||||
this.name = name
|
||||
this.instances = new Map()
|
||||
@@ -70,6 +72,19 @@ class MetricWrapper {
|
||||
help: name,
|
||||
labelNames: ['status', 'method', 'path'],
|
||||
})
|
||||
case 'histogram':
|
||||
return new prom.Histogram({
|
||||
name,
|
||||
help: name,
|
||||
labelNames: [
|
||||
'path',
|
||||
'status_code',
|
||||
'method',
|
||||
'collection',
|
||||
'query',
|
||||
],
|
||||
buckets,
|
||||
})
|
||||
case 'summary':
|
||||
return new prom.Summary({
|
||||
name,
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
const { promisify } = require('util')
|
||||
const os = require('os')
|
||||
const http = require('http')
|
||||
const { expect } = require('chai')
|
||||
@@ -5,6 +6,7 @@ const Metrics = require('../..')
|
||||
|
||||
const HOSTNAME = os.hostname()
|
||||
const APP_NAME = 'test-app'
|
||||
const sleep = promisify(setTimeout)
|
||||
|
||||
describe('Metrics module', function () {
|
||||
before(function () {
|
||||
@@ -67,6 +69,60 @@ describe('Metrics module', function () {
|
||||
})
|
||||
})
|
||||
|
||||
describe('histogram()', function () {
|
||||
it('collects in buckets', async function () {
|
||||
const buckets = [10, 100, 1000]
|
||||
Metrics.histogram('distance', 10, buckets)
|
||||
Metrics.histogram('distance', 20, buckets)
|
||||
Metrics.histogram('distance', 100, buckets)
|
||||
Metrics.histogram('distance', 200, buckets)
|
||||
Metrics.histogram('distance', 1000, buckets)
|
||||
Metrics.histogram('distance', 2000, buckets)
|
||||
const sum = await getSummarySum('histogram_distance')
|
||||
expect(sum).to.equal(3330)
|
||||
await checkHistogramValues('histogram_distance', {
|
||||
10: 1,
|
||||
100: 3,
|
||||
1000: 5,
|
||||
'+Inf': 6,
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('Timer', function () {
|
||||
beforeEach('collect timings', async function () {
|
||||
const buckets = [10, 100, 1000]
|
||||
for (const duration of [1, 1, 1, 15, 15, 15, 105, 105, 105]) {
|
||||
const withBuckets = new Metrics.Timer('height', 1, {}, buckets)
|
||||
const withOutBuckets = new Metrics.Timer('depth', 1, {})
|
||||
await sleep(duration)
|
||||
withBuckets.done()
|
||||
withOutBuckets.done()
|
||||
}
|
||||
})
|
||||
|
||||
it('with buckets', async function () {
|
||||
await checkHistogramValues('histogram_height', {
|
||||
10: 3,
|
||||
100: 6,
|
||||
1000: 9,
|
||||
'+Inf': 9,
|
||||
})
|
||||
})
|
||||
|
||||
it('without buckets', async function () {
|
||||
await checkSummaryValues('timer_depth', {
|
||||
0.01: 1,
|
||||
0.05: 1,
|
||||
0.5: 15,
|
||||
0.9: 105,
|
||||
0.95: 105,
|
||||
0.99: 105,
|
||||
0.999: 105,
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('gauge()', function () {
|
||||
it('records values', async function () {
|
||||
Metrics.gauge('water_level', 1.5)
|
||||
@@ -225,6 +281,38 @@ async function getSummarySum(key) {
|
||||
return null
|
||||
}
|
||||
|
||||
async function checkHistogramValues(key, values) {
|
||||
const metric = getMetric(key)
|
||||
const item = await metric.get()
|
||||
const found = {}
|
||||
for (const value of item.values) {
|
||||
const bucket = value.labels.le
|
||||
if (!bucket) continue
|
||||
found[bucket] = value.value
|
||||
}
|
||||
expect(found).to.deep.equal(values)
|
||||
return null
|
||||
}
|
||||
|
||||
async function checkSummaryValues(key, values) {
|
||||
const metric = getMetric(key)
|
||||
const item = await metric.get()
|
||||
const found = {}
|
||||
for (const value of item.values) {
|
||||
const quantile = value.labels.quantile
|
||||
if (!quantile) continue
|
||||
found[quantile] = value.value
|
||||
}
|
||||
for (const quantile of Object.keys(values)) {
|
||||
expect(found[quantile]).to.be.within(
|
||||
values[quantile] - 5,
|
||||
values[quantile] + 5,
|
||||
`quantile: ${quantile}`
|
||||
)
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
async function getMetricValue(key) {
|
||||
const metrics = await Metrics.register.getMetricsAsJSON()
|
||||
const metric = metrics.find(m => m.name === key)
|
||||
|
||||
Reference in New Issue
Block a user