From a359a06575bcd78a4e351272d8b1b36241624d6d Mon Sep 17 00:00:00 2001 From: Adry Date: Sun, 20 Mar 2022 18:18:53 +0100 Subject: [PATCH] feat: improve init If any metric already exists, get existing one --- README.md | 1 + src/index.ts | 33 +++++++++++++++++---------------- src/utils.ts | 50 ++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 68 insertions(+), 16 deletions(-) create mode 100644 src/utils.ts diff --git a/README.md b/README.md index a4846ac..8ca66e8 100644 --- a/README.md +++ b/README.md @@ -68,6 +68,7 @@ Returns a queue metrics object which includes the following methods: * **@robbiet480** * **@TotallyNotElite** * **@ejhayes** +* **@aagregorio** ## License MIT © [Pawel Badenski](https://github.com/pbadenski) diff --git a/src/index.ts b/src/index.ts index d1bfa0b..549d6de 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,5 +1,6 @@ import client = require('prom-client'); import * as bull from 'bull'; +import { getOrCreateMetric, Metrics } from './utils'; export interface Options { promClient?: typeof client; @@ -28,59 +29,59 @@ export function init(opts: Options) { const waitingDurationMetricName = 'jobs_waiting_duration_milliseconds'; const attemptsMadeMetricName = 'jobs_attempts'; - const completedMetric = new promClient.Gauge({ + const completedMetric = getOrCreateMetric(Metrics.Gauge, { name: completedMetricName, help: 'Number of completed jobs', labelNames: [QUEUE_NAME_LABEL, QUEUE_PREFIX_LABEL], - }); + }) as client.Gauge; - const failedMetric = new promClient.Gauge({ + const failedMetric = getOrCreateMetric(Metrics.Gauge, { name: failedMetricName, help: 'Number of failed jobs', labelNames: [QUEUE_NAME_LABEL, QUEUE_PREFIX_LABEL], - }); + }) as client.Gauge; - const delayedMetric = new promClient.Gauge({ + const delayedMetric = getOrCreateMetric(Metrics.Gauge, { name: delayedMetricName, help: 'Number of delayed jobs', labelNames: [QUEUE_NAME_LABEL, QUEUE_PREFIX_LABEL], - }); + }) as client.Gauge; - const activeMetric = new promClient.Gauge({ + const activeMetric = getOrCreateMetric(Metrics.Gauge, { name: activeMetricName, help: 'Number of active jobs', labelNames: [QUEUE_NAME_LABEL, QUEUE_PREFIX_LABEL], - }); + }) as client.Gauge; - const waitingMetric = new promClient.Gauge({ + const waitingMetric = getOrCreateMetric(Metrics.Gauge, { name: waitingMetricName, help: 'Number of waiting jobs', labelNames: [QUEUE_NAME_LABEL, QUEUE_PREFIX_LABEL], - }); + })as client.Gauge; - const durationMetric = new promClient.Summary({ + const durationMetric = getOrCreateMetric(Metrics.Summary, { name: durationMetricName, help: 'Time to complete jobs', labelNames: [QUEUE_NAME_LABEL, QUEUE_PREFIX_LABEL, STATUS_LABEL], maxAgeSeconds: 300, ageBuckets: 13, - }); + }) as client.Summary; - const waitingDurationMetric = new promClient.Summary({ + const waitingDurationMetric = getOrCreateMetric(Metrics.Summary, { name: waitingDurationMetricName, help: 'Time spent waiting for a job to run', labelNames: [QUEUE_NAME_LABEL, QUEUE_PREFIX_LABEL, STATUS_LABEL], maxAgeSeconds: 300, ageBuckets: 13 - }); + }) as client.Summary; - const attemptsMadeMetric = new promClient.Summary({ + const attemptsMadeMetric = getOrCreateMetric(Metrics.Summary, { name: attemptsMadeMetricName, help: 'Job attempts made', labelNames: [QUEUE_NAME_LABEL, QUEUE_PREFIX_LABEL, STATUS_LABEL], maxAgeSeconds: 300, ageBuckets: 13 - }); + }) as client.Summary; function recordJobMetrics(labels: {[key: string]: string}, status: JobStatus, job: bull.Job) { if (!job.finishedOn) { diff --git a/src/utils.ts b/src/utils.ts new file mode 100644 index 0000000..7d06c28 --- /dev/null +++ b/src/utils.ts @@ -0,0 +1,50 @@ +import * as client from "prom-client"; + +/** + * @internal + */ +export enum Metrics { + Gauge = "Gauge", + Summary = "Summary", + Histogram = "Histogram", + Counter = "Counter" +}; + +/** + * @internal + */ +export type Options = + | client.GaugeConfiguration + | client.SummaryConfiguration + | client.CounterConfiguration + | client.HistogramConfiguration; + +/** + * @internal + */ +export function getOrCreateMetric( + type: Metrics, + options: Options, +): client.Metric { + const existingMetric = client.register.getSingleMetric(options.name); + + if (existingMetric) { + return existingMetric; + } + + switch (type) { + case "Gauge": + return new client.Gauge(options as client.GaugeConfiguration); + case "Counter": + return new client.Counter(options as client.CounterConfiguration); + case "Histogram": + return new client.Histogram( + options as client.HistogramConfiguration, + ); + case "Summary": + return new client.Summary(options as client.SummaryConfiguration); + default: + // eslint-disable-next-line @typescript-eslint/restrict-template-expressions + throw new Error(`Unknown type: ${type}`); + } +} \ No newline at end of file