From d6a90ea6caa6c5c8e2084393477c9d92072331e4 Mon Sep 17 00:00:00 2001 From: Heiko Rothe Date: Sun, 10 Jan 2021 14:07:02 +0100 Subject: [PATCH] feat(prometheus): add metrics --- package-lock.json | 26 +++++++++++++++++++ package.json | 2 ++ src/app.module.ts | 2 ++ .../bluetooth/bluetooth.module.ts | 11 +++++++- .../bluetooth/bluetooth.service.spec.ts | 11 +++++++- .../bluetooth/bluetooth.service.ts | 7 ++++- 6 files changed, 56 insertions(+), 3 deletions(-) diff --git a/package-lock.json b/package-lock.json index bce0f5f..21f33a0 100644 --- a/package-lock.json +++ b/package-lock.json @@ -4272,6 +4272,11 @@ "@xtuc/long": "4.2.2" } }, + "@willsoto/nestjs-prometheus": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@willsoto/nestjs-prometheus/-/nestjs-prometheus-3.0.0.tgz", + "integrity": "sha512-qOt+rSyYoP2ExoY0HfGd2z1NveGFpULIrZi4sof+NCf0hGT3ETCrpDgyOvqFkSCl3+hcNwW7Gd70zQCnGaM4CA==" + }, "@xtuc/ieee754": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/@xtuc/ieee754/-/ieee754-1.2.0.tgz", @@ -5111,6 +5116,11 @@ "file-uri-to-path": "1.0.0" } }, + "bintrees": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/bintrees/-/bintrees-1.0.1.tgz", + "integrity": "sha1-DmVcm5wkNeqraL9AJyJtK1WjRSQ=" + }, "bl": { "version": "4.0.3", "resolved": "https://registry.npmjs.org/bl/-/bl-4.0.3.tgz", @@ -15312,6 +15322,14 @@ "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==", "dev": true }, + "prom-client": { + "version": "13.0.0", + "resolved": "https://registry.npmjs.org/prom-client/-/prom-client-13.0.0.tgz", + "integrity": "sha512-M7ZNjIO6x+2R/vjSD13yjJPjpoZA8eEwH2Bp2Re0/PvzozD7azikv+SaBtZes4Q1ca/xHjZ4RSCuTag3YZLg1A==", + "requires": { + "tdigest": "^0.1.1" + } + }, "promise-inflight": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/promise-inflight/-/promise-inflight-1.0.1.tgz", @@ -17994,6 +18012,14 @@ } } }, + "tdigest": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/tdigest/-/tdigest-0.1.1.tgz", + "integrity": "sha1-Ljyyw56kSeVdHmzZEReszKRYgCE=", + "requires": { + "bintrees": "1.0.1" + } + }, "term-size": { "version": "2.2.1", "resolved": "https://registry.npmjs.org/term-size/-/term-size-2.2.1.tgz", diff --git a/package.json b/package.json index b304c40..bd9cc17 100644 --- a/package.json +++ b/package.json @@ -50,6 +50,7 @@ "@nestjs/schedule": "^0.4.1", "@nestjs/swagger": "^4.7.9", "@nestjs/terminus": "^7.0.1", + "@willsoto/nestjs-prometheus": "^3.0.0", "async-mqtt": "^2.6.1", "chalk": "^4.1.0", "class-transformer": "^0.3.1", @@ -65,6 +66,7 @@ "mathjs": "^8.1.1", "nest-emitter": "^1.1.1", "nest-winston": "^1.4.0", + "prom-client": "^13.0.0", "pureimage": "^0.2.5", "reflect-metadata": "^0.1.13", "rxjs": "^6.6.3", diff --git a/src/app.module.ts b/src/app.module.ts index 61ae746..9480a43 100644 --- a/src/app.module.ts +++ b/src/app.module.ts @@ -10,6 +10,7 @@ import { NestEmitterModule } from 'nest-emitter'; import { EventEmitter } from 'events'; import { WINSTON_LOGGER } from './logger'; import { StatusModule } from './status/status.module'; +import { PrometheusModule } from '@willsoto/nestjs-prometheus'; // eslint-disable-next-line @typescript-eslint/no-var-requires export const VERSION = require('../package.json').version; @@ -26,6 +27,7 @@ export const CONFIGURED_INTEGRATIONS = c StatusModule, ScheduleModule.forRoot(), NestEmitterModule.forRoot(new EventEmitter()), + PrometheusModule.register(), IntegrationsModule.register(CONFIGURED_INTEGRATIONS, WINSTON_LOGGER), ], }) diff --git a/src/integrations/bluetooth/bluetooth.module.ts b/src/integrations/bluetooth/bluetooth.module.ts index 6ed6ad6..fc0cf04 100644 --- a/src/integrations/bluetooth/bluetooth.module.ts +++ b/src/integrations/bluetooth/bluetooth.module.ts @@ -4,10 +4,19 @@ import { BluetoothHealthIndicator } from './bluetooth.health'; import { ConfigModule } from '../../config/config.module'; import { StatusModule } from '../../status/status.module'; import { ScheduleModule } from '@nestjs/schedule'; +import { makeCounterProvider } from '@willsoto/nestjs-prometheus'; @Module({ imports: [ConfigModule, StatusModule, ScheduleModule.forRoot()], - providers: [BluetoothService, BluetoothHealthIndicator], + providers: [ + BluetoothService, + BluetoothHealthIndicator, + makeCounterProvider({ + name: 'bluetooth_le_advertisements_received_count', + help: + 'Number of Bluetooth Low Energy advertisements that were detected by this device', + }), + ], exports: [BluetoothService], }) export class BluetoothModule {} diff --git a/src/integrations/bluetooth/bluetooth.service.spec.ts b/src/integrations/bluetooth/bluetooth.service.spec.ts index 20b6265..da123b8 100644 --- a/src/integrations/bluetooth/bluetooth.service.spec.ts +++ b/src/integrations/bluetooth/bluetooth.service.spec.ts @@ -1,3 +1,5 @@ +import { makeCounterProvider } from '@willsoto/nestjs-prometheus'; + const mockExec = jest.fn(); const mockNoble = { state: 'poweredOn', @@ -40,7 +42,14 @@ describe('BluetoothService', () => { const module: TestingModule = await Test.createTestingModule({ imports: [ConfigModule], - providers: [BluetoothService, BluetoothHealthIndicator], + providers: [ + BluetoothService, + BluetoothHealthIndicator, + makeCounterProvider({ + name: 'bluetooth_le_advertisements_received_count', + help: '', + }), + ], }) .overrideProvider(BluetoothHealthIndicator) .useValue(healthIndicator) diff --git a/src/integrations/bluetooth/bluetooth.service.ts b/src/integrations/bluetooth/bluetooth.service.ts index 95058f5..ca3a67b 100644 --- a/src/integrations/bluetooth/bluetooth.service.ts +++ b/src/integrations/bluetooth/bluetooth.service.ts @@ -9,6 +9,8 @@ import { Device } from '../bluetooth-classic/device'; import { promiseWithTimeout, sleep } from '../../util/promises'; import { Interval } from '@nestjs/schedule'; import _ from 'lodash'; +import { Counter } from 'prom-client'; +import { InjectMetric } from '@willsoto/nestjs-prometheus'; const RSSI_REGEX = new RegExp(/-?[0-9]+/); const INQUIRY_LOCK_TIMEOUT = 30 * 1000; @@ -44,7 +46,9 @@ export class BluetoothService { constructor( private readonly configService: ConfigService, - private readonly healthIndicator: BluetoothHealthIndicator + private readonly healthIndicator: BluetoothHealthIndicator, + @InjectMetric('bluetooth_le_advertisements_received_count') + private readonly advertisementReceivedCounter: Counter ) { this.classicConfig = this.configService.get('bluetoothClassic'); } @@ -393,6 +397,7 @@ export class BluetoothService { noble.on('stateChange', this.handleAdapterStateChange.bind(this)); noble.on('discover', () => { this.lastLowEnergyDiscovery = new Date(); + this.advertisementReceivedCounter.inc(); if (this.adapters.getState(this.lowEnergyAdapterId) === 'inactive') { this.adapters.setState(this.lowEnergyAdapterId, 'scan'); }