diff --git a/README.md b/README.md index 36a4029..d36a72d 100644 --- a/README.md +++ b/README.md @@ -244,6 +244,9 @@ You have the following decorators: * `@OtelCounter()` * `@OtelUpDownCounter()` * `@OtelHistogram()` +* `@OtelObservableGauge()` +* `@OtelObservableCounter()` +* `@OtelObservableUpDownCounter()` Example of usage: @@ -258,7 +261,7 @@ export class AppController { home( @OtelCounter('app_counter_1_inc', { description: 'counter 1 description' }) counter1: Counter, ) { - counter1.inc(1); + counter1.add(1); } } diff --git a/src/metrics/decorators/common.ts b/src/metrics/decorators/common.ts index 247969a..84e669d 100644 --- a/src/metrics/decorators/common.ts +++ b/src/metrics/decorators/common.ts @@ -1,5 +1,5 @@ import { Counter, MetricOptions } from '@opentelemetry/api-metrics'; -import { getOrCreateCounter, MetricType } from '../metric-data'; +import { getOrCreateCounter } from '../metric-data'; /** * Create and increment a counter when a new instance is created @@ -16,7 +16,7 @@ export const OtelInstanceCounter = ( return class extends ctor { constructor(...args) { if (!counterMetric) { - counterMetric = getOrCreateCounter(name, MetricType.Counter, { description, ...options }); + counterMetric = getOrCreateCounter(name, { description, ...options }); } counterMetric.add(1); @@ -44,7 +44,7 @@ export const OtelMethodCounter = ( // eslint-disable-next-line no-param-reassign, func-names descriptor.value = function (...args: any[]) { if (!counterMetric) { - counterMetric = getOrCreateCounter(name, MetricType.Counter, { description, ...options }); + counterMetric = getOrCreateCounter(name, { description, ...options }); } counterMetric.add(1); return methodFunc.apply(this, args); diff --git a/src/metrics/decorators/counter.ts b/src/metrics/decorators/counter.ts index 37b7e31..9f22326 100644 --- a/src/metrics/decorators/counter.ts +++ b/src/metrics/decorators/counter.ts @@ -6,12 +6,12 @@ export const OtelCounter = createParamDecorator((name: string, options?: MetricO if (!name || name.length === 0) { throw new Error('OtelCounter need a name argument'); } - return getOrCreateCounter(name, MetricType.Counter, options); + return getOrCreateCounter(name, options); }); export const OtelUpDownCounter = createParamDecorator((name: string, options?: MetricOptions) => { if (!name || name.length === 0) { throw new Error('OtelUpDownCounter need a name argument'); } - return getOrCreateCounter(name, MetricType.UpDownCounter, options); + return getOrCreateCounter(name, options); }); diff --git a/src/metrics/decorators/histogram.ts b/src/metrics/decorators/histogram.ts index aaf9ec3..6b0140d 100644 --- a/src/metrics/decorators/histogram.ts +++ b/src/metrics/decorators/histogram.ts @@ -1,10 +1,10 @@ import { createParamDecorator } from '@nestjs/common'; import { MetricOptions } from '@opentelemetry/api-metrics'; -import { getOrCreateHistogram, MetricType } from '../metric-data'; +import { getOrCreateHistogram } from '../metric-data'; export const OtelHistogram = createParamDecorator((name: string, options?: MetricOptions) => { if (!name || name.length === 0) { throw new Error('OtelHistogram need a name argument'); } - return getOrCreateHistogram(name, MetricType.Histogram, options); + return getOrCreateHistogram(name, options); }); diff --git a/src/metrics/decorators/index.ts b/src/metrics/decorators/index.ts index e458232..7c5961e 100644 --- a/src/metrics/decorators/index.ts +++ b/src/metrics/decorators/index.ts @@ -1,3 +1,4 @@ export * from './common'; export * from './counter'; export * from './histogram'; +export * from './observable'; diff --git a/src/metrics/decorators/observable.ts b/src/metrics/decorators/observable.ts new file mode 100644 index 0000000..21d3153 --- /dev/null +++ b/src/metrics/decorators/observable.ts @@ -0,0 +1,28 @@ +import { createParamDecorator } from '@nestjs/common'; +import { MetricOptions } from '@opentelemetry/api-metrics'; +import { getOrCreateObservableCounter, getOrCreateObservableGauge, getOrCreateObservableUpDownCounter } from '../metric-data'; + +export const OtelObservableGauge = createParamDecorator((name: string, options?: MetricOptions) => { + if (!name || name.length === 0) { + throw new Error('OtelObservableGauge need a name argument'); + } + return getOrCreateObservableGauge(name, options); +}); + +export const OtelObservableCounter = createParamDecorator( + (name: string, options?: MetricOptions) => { + if (!name || name.length === 0) { + throw new Error('OtelObservableCounter need a name argument'); + } + return getOrCreateObservableCounter(name, options); + }, +); + +export const OtelObservableUpDownCounter = createParamDecorator( + (name: string, options?: MetricOptions) => { + if (!name || name.length === 0) { + throw new Error('OtelObservableUpDownCounter need a name argument'); + } + return getOrCreateObservableUpDownCounter(name, options); + }, +); diff --git a/src/metrics/metric-data.ts b/src/metrics/metric-data.ts index d0a64f9..ad3e037 100644 --- a/src/metrics/metric-data.ts +++ b/src/metrics/metric-data.ts @@ -1,21 +1,30 @@ import { - Counter, MetricOptions, metrics, UpDownCounter, Histogram, + Counter, MetricOptions, metrics, UpDownCounter, + Histogram, ObservableGauge, ObservableCounter, ObservableUpDownCounter, } from '@opentelemetry/api-metrics'; import { OTEL_METER_NAME } from '../opentelemetry.constants'; -export type GenericMetric = Counter | UpDownCounter | Histogram; +export type GenericMetric = + Counter | + UpDownCounter | + Histogram | + ObservableGauge | + ObservableCounter | + ObservableUpDownCounter; export enum MetricType { 'Counter' = 'Counter', 'UpDownCounter' = 'UpDownCounter', 'Histogram' = 'Histogram', + 'ObservableGauge' = 'ObservableGauge', + 'ObservableCounter' = 'ObservableCounter', + 'ObservableUpDownCounter' = 'ObservableUpDownCounter', } export const meterData: Map = new Map(); export function getOrCreateHistogram( name: string, - type: MetricType, options: MetricOptions, ): Histogram { if (meterData.has(name)) { @@ -23,38 +32,82 @@ export function getOrCreateHistogram( } const meter = metrics.getMeterProvider().getMeter(OTEL_METER_NAME); + const histogram = meter.createHistogram(name, options); + meterData.set(name, histogram); + return histogram; +} - switch (type) { - case MetricType.Histogram: - const histogram = meter.createHistogram(name, options); - meterData.set(name, histogram); - return histogram; - default: - throw new Error(`Unknown type: ${type}`); +export function getOrCreateCounter( + name: string, + options: MetricOptions, +): Counter { + if (meterData.has(name)) { + return meterData.get(name) as Counter; } + + const meter = metrics.getMeterProvider().getMeter(OTEL_METER_NAME); + + const counter = meter.createCounter(name, options); + meterData.set(name, counter); + return counter; } -export function getOrCreateCounter( +export function getOrCreateUpDownCounter( name: string, - type: MetricType, options: MetricOptions, -): Counter | UpDownCounter { +): UpDownCounter { if (meterData.has(name)) { - return meterData.get(name) as Counter | UpDownCounter; + return meterData.get(name) as UpDownCounter; } const meter = metrics.getMeterProvider().getMeter(OTEL_METER_NAME); - switch (type) { - case MetricType.Counter: - const counter = meter.createCounter(name, options); - meterData.set(name, counter); - return counter; - case MetricType.UpDownCounter: - const upDownCounter = meter.createUpDownCounter(name, options); - meterData.set(name, upDownCounter); - return upDownCounter; - default: - throw new Error(`Unknown type: ${type}`); + const upDownCounter = meter.createUpDownCounter(name, options); + meterData.set(name, upDownCounter); + return upDownCounter; +} + +export function getOrCreateObservableGauge( + name: string, + options: MetricOptions, +): ObservableGauge { + if (meterData.has(name)) { + return meterData.get(name) as ObservableGauge; } + + const meter = metrics.getMeterProvider().getMeter(OTEL_METER_NAME); + + const observableGauge = meter.createObservableGauge(name, options); + meterData.set(name, observableGauge); + return observableGauge; +} + +export function getOrCreateObservableCounter( + name: string, + options: MetricOptions, +): ObservableCounter { + if (meterData.has(name)) { + return meterData.get(name) as ObservableCounter; + } + + const meter = metrics.getMeterProvider().getMeter(OTEL_METER_NAME); + + const observableCounter = meter.createObservableCounter(name, options); + meterData.set(name, observableCounter); + return observableCounter; +} + +export function getOrCreateObservableUpDownCounter( + name: string, + options: MetricOptions, +): ObservableUpDownCounter { + if (meterData.has(name)) { + return meterData.get(name) as ObservableUpDownCounter; + } + + const meter = metrics.getMeterProvider().getMeter(OTEL_METER_NAME); + + const observableCounter = meter.createObservableCounter(name, options); + meterData.set(name, observableCounter); + return observableCounter; } diff --git a/src/metrics/metric.service.ts b/src/metrics/metric.service.ts index f203763..33167e6 100644 --- a/src/metrics/metric.service.ts +++ b/src/metrics/metric.service.ts @@ -1,38 +1,36 @@ import { Injectable } from '@nestjs/common'; import { - Counter, UpDownCounter, Histogram, MetricOptions, + MetricOptions, } from '@opentelemetry/api-metrics'; import { - getOrCreateCounter, getOrCreateHistogram, MetricType, + getOrCreateCounter, getOrCreateHistogram, + getOrCreateObservableCounter, getOrCreateObservableGauge, + getOrCreateObservableUpDownCounter, getOrCreateUpDownCounter, MetricType, } from './metric-data'; @Injectable() export class MetricService { getCounter(name: string, options?: MetricOptions) { - return this.getOrCreateCounter(name, MetricType.Counter, options); + return getOrCreateCounter(name, options); } getUpDownCounter(name: string, options?: MetricOptions) { - return this.getOrCreateCounter(name, MetricType.UpDownCounter, options); + return getOrCreateUpDownCounter(name, options); } getHistogram(name: string, options?: MetricOptions) { - return this.getOrCreateHistogram(name, MetricType.Histogram, options); + return getOrCreateHistogram(name, options); } - private getOrCreateHistogram( - name: string, - type: MetricType, - options: MetricOptions, - ): Histogram { - return getOrCreateHistogram(name, type, options); + getObservableCounter(name: string, options?: MetricOptions) { + return getOrCreateObservableCounter(name, options); } - private getOrCreateCounter( - name: string, - type: MetricType, - options: MetricOptions, - ): Counter | UpDownCounter { - return getOrCreateCounter(name, type, options); + getObservableGauge(name: string, options?: MetricOptions) { + return getOrCreateObservableGauge(name, options); + } + + getObservableUpDownCounter(name: string, options?: MetricOptions) { + return getOrCreateObservableUpDownCounter(name, options); } }