mirror of
https://github.com/n8n-io/n8n.git
synced 2024-12-24 04:04:06 -08:00
test(core): Add tests for Prometheus metrics service (no-changelog) (#10050)
This commit is contained in:
parent
cd24c71a9e
commit
b42f652f1b
|
@ -168,8 +168,8 @@ export class Server extends AbstractServer {
|
|||
|
||||
async configure(): Promise<void> {
|
||||
if (config.getEnv('endpoints.metrics.enable')) {
|
||||
const { MetricsService } = await import('@/services/metrics.service');
|
||||
await Container.get(MetricsService).configureMetrics(this.app);
|
||||
const { PrometheusMetricsService } = await import('@/metrics/prometheus-metrics.service');
|
||||
await Container.get(PrometheusMetricsService).configureMetrics(this.app);
|
||||
}
|
||||
|
||||
const { frontendService } = this;
|
||||
|
|
|
@ -0,0 +1,123 @@
|
|||
import config from '@/config';
|
||||
import promClient from 'prom-client';
|
||||
import promBundle from 'express-prom-bundle';
|
||||
import { mock } from 'jest-mock-extended';
|
||||
import { PrometheusMetricsService } from '../prometheus-metrics.service';
|
||||
import type express from 'express';
|
||||
import type { MessageEventBus } from '@/eventbus/MessageEventBus/MessageEventBus';
|
||||
|
||||
const mockMiddleware = (
|
||||
_req: express.Request,
|
||||
_res: express.Response,
|
||||
next: express.NextFunction,
|
||||
) => next();
|
||||
|
||||
jest.mock('prom-client');
|
||||
jest.mock('express-prom-bundle', () => jest.fn(() => mockMiddleware));
|
||||
|
||||
describe('PrometheusMetricsService', () => {
|
||||
beforeEach(() => {
|
||||
config.load(config.default);
|
||||
});
|
||||
|
||||
describe('configureMetrics', () => {
|
||||
it('should set up `n8n_version_info`', async () => {
|
||||
const service = new PrometheusMetricsService(mock(), mock(), mock());
|
||||
|
||||
await service.configureMetrics(mock<express.Application>());
|
||||
|
||||
expect(promClient.Gauge).toHaveBeenCalledWith({
|
||||
name: 'n8n_version_info',
|
||||
help: 'n8n version info.',
|
||||
labelNames: ['version', 'major', 'minor', 'patch'],
|
||||
});
|
||||
});
|
||||
|
||||
it('should set up default metrics collection with `prom-client`', async () => {
|
||||
const service = new PrometheusMetricsService(mock(), mock(), mock());
|
||||
|
||||
await service.configureMetrics(mock<express.Application>());
|
||||
|
||||
expect(promClient.collectDefaultMetrics).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should set up `n8n_cache_hits_total`', async () => {
|
||||
config.set('endpoints.metrics.includeCacheMetrics', true);
|
||||
const service = new PrometheusMetricsService(mock(), mock(), mock());
|
||||
|
||||
await service.configureMetrics(mock<express.Application>());
|
||||
|
||||
expect(promClient.Counter).toHaveBeenCalledWith({
|
||||
name: 'n8n_cache_hits_total',
|
||||
help: 'Total number of cache hits.',
|
||||
labelNames: ['cache'],
|
||||
});
|
||||
expect(service.counters.cacheHitsTotal?.inc).toHaveBeenCalledWith(0);
|
||||
});
|
||||
|
||||
it('should set up `n8n_cache_misses_total`', async () => {
|
||||
config.set('endpoints.metrics.includeCacheMetrics', true);
|
||||
const service = new PrometheusMetricsService(mock(), mock(), mock());
|
||||
|
||||
await service.configureMetrics(mock<express.Application>());
|
||||
|
||||
expect(promClient.Counter).toHaveBeenCalledWith({
|
||||
name: 'n8n_cache_misses_total',
|
||||
help: 'Total number of cache misses.',
|
||||
labelNames: ['cache'],
|
||||
});
|
||||
expect(service.counters.cacheMissesTotal?.inc).toHaveBeenCalledWith(0);
|
||||
});
|
||||
|
||||
it('should set up `n8n_cache_updates_total`', async () => {
|
||||
config.set('endpoints.metrics.includeCacheMetrics', true);
|
||||
const service = new PrometheusMetricsService(mock(), mock(), mock());
|
||||
|
||||
await service.configureMetrics(mock<express.Application>());
|
||||
|
||||
expect(promClient.Counter).toHaveBeenCalledWith({
|
||||
name: 'n8n_cache_updates_total',
|
||||
help: 'Total number of cache updates.',
|
||||
labelNames: ['cache'],
|
||||
});
|
||||
expect(service.counters.cacheUpdatesTotal?.inc).toHaveBeenCalledWith(0);
|
||||
});
|
||||
|
||||
it('should set up API metrics with `express-prom-bundle`', async () => {
|
||||
config.set('endpoints.metrics.includeApiEndpoints', true);
|
||||
config.set('endpoints.metrics.includeApiPathLabel', true);
|
||||
config.set('endpoints.metrics.includeApiMethodLabel', true);
|
||||
config.set('endpoints.metrics.includeApiStatusCodeLabel', true);
|
||||
const service = new PrometheusMetricsService(mock(), mock(), mock());
|
||||
|
||||
const app = mock<express.Application>();
|
||||
|
||||
await service.configureMetrics(app);
|
||||
|
||||
expect(promBundle).toHaveBeenCalledWith({
|
||||
autoregister: false,
|
||||
includeUp: false,
|
||||
includePath: true,
|
||||
includeMethod: true,
|
||||
includeStatusCode: true,
|
||||
});
|
||||
|
||||
expect(app.use).toHaveBeenCalledWith(
|
||||
['/rest/', '/webhook/', 'webhook-test/', '/api/'],
|
||||
expect.any(Function),
|
||||
);
|
||||
});
|
||||
|
||||
it('should set up event bus metrics', async () => {
|
||||
const eventBus = mock<MessageEventBus>();
|
||||
const service = new PrometheusMetricsService(mock(), mock(), eventBus);
|
||||
|
||||
await service.configureMetrics(mock<express.Application>());
|
||||
|
||||
expect(eventBus.on).toHaveBeenCalledWith(
|
||||
'metrics.messageEventBus.Event',
|
||||
expect.any(Function),
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
|
@ -14,7 +14,7 @@ import { Logger } from '@/Logger';
|
|||
import { EventMessageTypeNames } from 'n8n-workflow';
|
||||
|
||||
@Service()
|
||||
export class MetricsService extends EventEmitter {
|
||||
export class PrometheusMetricsService extends EventEmitter {
|
||||
constructor(
|
||||
private readonly logger: Logger,
|
||||
private readonly cacheService: CacheService,
|
|
@ -4,7 +4,7 @@ import request from 'supertest';
|
|||
|
||||
import config from '@/config';
|
||||
import { N8N_VERSION } from '@/constants';
|
||||
import { MetricsService } from '@/services/metrics.service';
|
||||
import { PrometheusMetricsService } from '@/metrics/prometheus-metrics.service';
|
||||
import { ExecutionRecoveryService } from '@/executions/execution-recovery.service';
|
||||
|
||||
import { setupTestServer } from './shared/utils';
|
||||
|
@ -42,7 +42,7 @@ describe('Metrics', () => {
|
|||
|
||||
it('should return cache metrics when enabled', async () => {
|
||||
config.set('endpoints.metrics.includeCacheMetrics', true);
|
||||
await Container.get(MetricsService).configureMetrics(testServer.app);
|
||||
await Container.get(PrometheusMetricsService).configureMetrics(testServer.app);
|
||||
const lines = await getMetricsResponseAsLines();
|
||||
expect(lines).toContain('n8n_test_cache_hits_total 0');
|
||||
expect(lines).toContain('n8n_test_cache_misses_total 0');
|
||||
|
@ -67,7 +67,7 @@ describe('Metrics', () => {
|
|||
|
||||
it('should return default metrics', async () => {
|
||||
config.set('endpoints.metrics.includeDefaultMetrics', true);
|
||||
await Container.get(MetricsService).configureMetrics(testServer.app);
|
||||
await Container.get(PrometheusMetricsService).configureMetrics(testServer.app);
|
||||
const lines = await getMetricsResponseAsLines();
|
||||
expect(lines).toContain('nodejs_heap_space_size_total_bytes{space="read_only"} 0');
|
||||
config.set('endpoints.metrics.includeDefaultMetrics', false);
|
||||
|
@ -75,7 +75,7 @@ describe('Metrics', () => {
|
|||
|
||||
it('should not return default metrics only when disabled', async () => {
|
||||
config.set('endpoints.metrics.includeDefaultMetrics', false);
|
||||
await Container.get(MetricsService).configureMetrics(testServer.app);
|
||||
await Container.get(PrometheusMetricsService).configureMetrics(testServer.app);
|
||||
const lines = await getMetricsResponseAsLines();
|
||||
expect(lines).not.toContain('nodejs_heap_space_size_total_bytes{space="read_only"} 0');
|
||||
config.set('endpoints.metrics.includeDefaultMetrics', true);
|
||||
|
|
|
@ -145,8 +145,10 @@ export const setupTestServer = ({
|
|||
break;
|
||||
|
||||
case 'metrics':
|
||||
const { MetricsService } = await import('@/services/metrics.service');
|
||||
await Container.get(MetricsService).configureMetrics(app);
|
||||
const { PrometheusMetricsService } = await import(
|
||||
'@/metrics/prometheus-metrics.service'
|
||||
);
|
||||
await Container.get(PrometheusMetricsService).configureMetrics(app);
|
||||
break;
|
||||
|
||||
case 'eventBus':
|
||||
|
|
Loading…
Reference in a new issue