Skip to content

Commit 069f0f7

Browse files
committed
feat: support histogram and summary
1 parent b81ba38 commit 069f0f7

File tree

6 files changed

+396
-114
lines changed

6 files changed

+396
-114
lines changed

src/interfaces.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
export interface MetricsConfig {
2-
defaultLabels?: Record<string, string>;
3-
defaultMetricsEnabled?: boolean;
2+
defaultLabels?: Record<string, string>;
3+
defaultMetricsEnabled?: boolean;
44
}

src/metrics/metrics.controller.ts

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,15 @@
11
import { Controller, Get } from '@nestjs/common';
22
import { Registry } from 'prom-client';
3-
import { ApiTags } from '@nestjs/swagger';
3+
import { ApiOperation, ApiTags } from '@nestjs/swagger';
44

55
@ApiTags( 'Metrics' )
66
@Controller( 'metrics' )
77
export class MetricsController {
8-
constructor( private readonly registry: Registry ) {
9-
}
10-
11-
@Get()
12-
async getMetrics() {
8+
constructor( private readonly registry: Registry ) {}
9+
10+
@Get()
11+
@ApiOperation( { summary: 'Get Prometheus metrics' } )
12+
async getMetrics(): Promise<string> {
1313
return await this.registry.metrics();
1414
}
1515
}

src/metrics/metrics.service.ts

Lines changed: 43 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,15 @@
11
import { Inject, Injectable } from '@nestjs/common';
2-
import { Counter, Gauge, Registry } from 'prom-client';
2+
import { Counter, Gauge, Histogram, Registry, Summary } from 'prom-client';
33

44
@Injectable()
55
export class MetricsService {
66
private readonly counter: { [ key: string ]: Counter<string> } = {};
77
private readonly gauge: { [ key: string ]: Gauge<string> } = {};
8-
9-
constructor( @Inject( Registry ) private readonly registry: Registry ) {
10-
}
11-
8+
private readonly histogram: { [ key: string ]: Histogram<string> } = {};
9+
private readonly summary: { [ key: string ]: Summary<string> } = {};
10+
11+
constructor( @Inject( Registry ) private readonly registry: Registry ) {}
12+
1213
public incCounter( key: string, labels?: Record<string, string | number> ): void {
1314
if ( ! this.counter[ key ] ) {
1415
this.counter[ key ] = new Counter( {
@@ -20,7 +21,7 @@ export class MetricsService {
2021
}
2122
this.counter[ key ].inc( labels || {} );
2223
}
23-
24+
2425
public setGauge( key: string, value: number, labels?: Record<string, string | number> ): void {
2526
if ( ! this.gauge[ key ] ) {
2627
this.gauge[ key ] = new Gauge( {
@@ -32,4 +33,40 @@ export class MetricsService {
3233
}
3334
this.gauge[ key ].set( labels || {}, value );
3435
}
36+
37+
public observeHistogram(
38+
key: string,
39+
value: number,
40+
labels?: Record<string, string | number>,
41+
buckets?: number[]
42+
): void {
43+
if ( ! this.histogram[ key ] ) {
44+
this.histogram[ key ] = new Histogram( {
45+
name: key,
46+
help: `Histogram for ${ key }`,
47+
labelNames: labels ? Object.keys( labels ) : [],
48+
buckets: buckets || [ 0.1, 0.5, 1, 2, 5 ],
49+
registers: [ this.registry ],
50+
} );
51+
}
52+
this.histogram[ key ].observe( labels || {}, value );
53+
}
54+
55+
public observeSummary(
56+
key: string,
57+
value: number,
58+
labels?: Record<string, string | number>,
59+
percentiles?: number[]
60+
): void {
61+
if ( ! this.summary[ key ] ) {
62+
this.summary[ key ] = new Summary( {
63+
name: key,
64+
help: `Summary for ${ key }`,
65+
labelNames: labels ? Object.keys( labels ) : [],
66+
percentiles: percentiles || [ 0.01, 0.05, 0.5, 0.9, 0.95, 0.99 ],
67+
registers: [ this.registry ],
68+
} );
69+
}
70+
this.summary[ key ].observe( labels || {}, value );
71+
}
3572
}

src/reporter/reporter.service.ts

Lines changed: 46 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -4,34 +4,71 @@ import { MetricsService } from '../metrics/metrics.service';
44
export class ReporterService {
55
private static readonly logger = new Logger( ReporterService.name );
66
private static metricsService: MetricsService;
7-
7+
88
static init( metricsService: MetricsService ): void {
99
ReporterService.metricsService = metricsService;
1010
}
11-
12-
static counter( key: string, labels?: Record<string, string | number> ): void {
11+
12+
static counter(
13+
key: string,
14+
labels?: Record<string, string | number>
15+
): void {
1316
this.validateMetricsService();
14-
17+
1518
try {
1619
ReporterService.metricsService.incCounter( key, labels );
1720
} catch ( error ) {
1821
this.logger.error( `Error while incrementing counter - ${ key }`, error );
1922
}
2023
}
21-
22-
static gauge( key: string, value: number, labels?: Record<string, string | number> ): void {
24+
25+
static gauge(
26+
key: string,
27+
value: number,
28+
labels?: Record<string, string | number>
29+
): void {
2330
this.validateMetricsService();
24-
31+
2532
try {
2633
ReporterService.metricsService.setGauge( key, value, labels );
2734
} catch ( error ) {
2835
this.logger.error( `Error while setting gauge - ${ key }, ${ value }`, error );
2936
}
3037
}
3138

39+
static histogram(
40+
key: string,
41+
value: number,
42+
labels?: Record<string, string | number>,
43+
buckets?: number[]
44+
): void {
45+
this.validateMetricsService();
46+
47+
try {
48+
ReporterService.metricsService.observeHistogram( key, value, labels, buckets );
49+
} catch ( error ) {
50+
this.logger.error( `Error while observing histogram - ${ key }, ${ value }`, error );
51+
}
52+
}
53+
54+
static summary(
55+
key: string,
56+
value: number,
57+
labels?: Record<string, string | number>,
58+
percentiles?: number[]
59+
): void {
60+
this.validateMetricsService();
61+
62+
try {
63+
ReporterService.metricsService.observeSummary( key, value, labels, percentiles );
64+
} catch ( error ) {
65+
this.logger.error( `Error while observing summary - ${ key }, ${ value }`, error );
66+
}
67+
}
68+
3269
private static validateMetricsService(): void {
33-
if (!ReporterService.metricsService) {
34-
throw new Error('MetricsService is not initialized.');
70+
if ( ! ReporterService.metricsService ) {
71+
throw new Error( 'MetricsService is not initialized.' );
3572
}
3673
}
3774
}

0 commit comments

Comments
 (0)