2024-07-15 03:16:27 -07:00
|
|
|
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';
|
2024-07-31 08:45:11 -07:00
|
|
|
import { mockInstance } from '@test/mocking';
|
|
|
|
import { GlobalConfig } from '@n8n/config';
|
2024-07-15 03:16:27 -07:00
|
|
|
|
|
|
|
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', () => {
|
2024-07-31 08:45:11 -07:00
|
|
|
const globalConfig = mockInstance(GlobalConfig, {
|
|
|
|
endpoints: {
|
|
|
|
metrics: {
|
|
|
|
prefix: 'n8n_',
|
|
|
|
includeDefaultMetrics: true,
|
|
|
|
includeApiEndpoints: true,
|
|
|
|
includeCacheMetrics: true,
|
|
|
|
includeMessageEventBusMetrics: true,
|
|
|
|
includeCredentialTypeLabel: false,
|
|
|
|
includeNodeTypeLabel: false,
|
|
|
|
includeWorkflowIdLabel: false,
|
|
|
|
includeApiPathLabel: true,
|
|
|
|
includeApiMethodLabel: true,
|
|
|
|
includeApiStatusCodeLabel: true,
|
|
|
|
},
|
|
|
|
},
|
2024-07-15 03:16:27 -07:00
|
|
|
});
|
|
|
|
|
2024-07-18 01:27:35 -07:00
|
|
|
describe('init', () => {
|
2024-07-15 03:16:27 -07:00
|
|
|
it('should set up `n8n_version_info`', async () => {
|
2024-07-31 08:45:11 -07:00
|
|
|
const service = new PrometheusMetricsService(mock(), mock(), globalConfig);
|
2024-07-15 03:16:27 -07:00
|
|
|
|
2024-07-18 01:27:35 -07:00
|
|
|
await service.init(mock<express.Application>());
|
2024-07-15 03:16:27 -07:00
|
|
|
|
|
|
|
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 () => {
|
2024-07-31 08:45:11 -07:00
|
|
|
const service = new PrometheusMetricsService(mock(), mock(), globalConfig);
|
2024-07-15 03:16:27 -07:00
|
|
|
|
2024-07-18 01:27:35 -07:00
|
|
|
await service.init(mock<express.Application>());
|
2024-07-15 03:16:27 -07:00
|
|
|
|
|
|
|
expect(promClient.collectDefaultMetrics).toHaveBeenCalled();
|
|
|
|
});
|
|
|
|
|
|
|
|
it('should set up `n8n_cache_hits_total`', async () => {
|
|
|
|
config.set('endpoints.metrics.includeCacheMetrics', true);
|
2024-07-31 08:45:11 -07:00
|
|
|
const service = new PrometheusMetricsService(mock(), mock(), globalConfig);
|
2024-07-15 03:16:27 -07:00
|
|
|
|
2024-07-18 01:27:35 -07:00
|
|
|
await service.init(mock<express.Application>());
|
2024-07-15 03:16:27 -07:00
|
|
|
|
|
|
|
expect(promClient.Counter).toHaveBeenCalledWith({
|
|
|
|
name: 'n8n_cache_hits_total',
|
|
|
|
help: 'Total number of cache hits.',
|
|
|
|
labelNames: ['cache'],
|
|
|
|
});
|
2024-07-18 01:27:35 -07:00
|
|
|
// @ts-expect-error private field
|
2024-07-15 03:16:27 -07:00
|
|
|
expect(service.counters.cacheHitsTotal?.inc).toHaveBeenCalledWith(0);
|
|
|
|
});
|
|
|
|
|
|
|
|
it('should set up `n8n_cache_misses_total`', async () => {
|
|
|
|
config.set('endpoints.metrics.includeCacheMetrics', true);
|
2024-07-31 08:45:11 -07:00
|
|
|
const service = new PrometheusMetricsService(mock(), mock(), globalConfig);
|
2024-07-15 03:16:27 -07:00
|
|
|
|
2024-07-18 01:27:35 -07:00
|
|
|
await service.init(mock<express.Application>());
|
2024-07-15 03:16:27 -07:00
|
|
|
|
|
|
|
expect(promClient.Counter).toHaveBeenCalledWith({
|
|
|
|
name: 'n8n_cache_misses_total',
|
|
|
|
help: 'Total number of cache misses.',
|
|
|
|
labelNames: ['cache'],
|
|
|
|
});
|
2024-07-18 01:27:35 -07:00
|
|
|
// @ts-expect-error private field
|
2024-07-15 03:16:27 -07:00
|
|
|
expect(service.counters.cacheMissesTotal?.inc).toHaveBeenCalledWith(0);
|
|
|
|
});
|
|
|
|
|
|
|
|
it('should set up `n8n_cache_updates_total`', async () => {
|
|
|
|
config.set('endpoints.metrics.includeCacheMetrics', true);
|
2024-07-31 08:45:11 -07:00
|
|
|
const service = new PrometheusMetricsService(mock(), mock(), globalConfig);
|
2024-07-15 03:16:27 -07:00
|
|
|
|
2024-07-18 01:27:35 -07:00
|
|
|
await service.init(mock<express.Application>());
|
2024-07-15 03:16:27 -07:00
|
|
|
|
|
|
|
expect(promClient.Counter).toHaveBeenCalledWith({
|
|
|
|
name: 'n8n_cache_updates_total',
|
|
|
|
help: 'Total number of cache updates.',
|
|
|
|
labelNames: ['cache'],
|
|
|
|
});
|
2024-07-18 01:27:35 -07:00
|
|
|
// @ts-expect-error private field
|
2024-07-15 03:16:27 -07:00
|
|
|
expect(service.counters.cacheUpdatesTotal?.inc).toHaveBeenCalledWith(0);
|
|
|
|
});
|
|
|
|
|
2024-07-22 03:01:44 -07:00
|
|
|
it('should set up route metrics with `express-prom-bundle`', async () => {
|
2024-07-15 03:16:27 -07:00
|
|
|
config.set('endpoints.metrics.includeApiEndpoints', true);
|
|
|
|
config.set('endpoints.metrics.includeApiPathLabel', true);
|
|
|
|
config.set('endpoints.metrics.includeApiMethodLabel', true);
|
|
|
|
config.set('endpoints.metrics.includeApiStatusCodeLabel', true);
|
2024-07-31 08:45:11 -07:00
|
|
|
const service = new PrometheusMetricsService(mock(), mock(), globalConfig);
|
2024-07-15 03:16:27 -07:00
|
|
|
|
|
|
|
const app = mock<express.Application>();
|
|
|
|
|
2024-07-18 01:27:35 -07:00
|
|
|
await service.init(app);
|
2024-07-15 03:16:27 -07:00
|
|
|
|
|
|
|
expect(promBundle).toHaveBeenCalledWith({
|
|
|
|
autoregister: false,
|
|
|
|
includeUp: false,
|
|
|
|
includePath: true,
|
|
|
|
includeMethod: true,
|
|
|
|
includeStatusCode: true,
|
|
|
|
});
|
|
|
|
|
|
|
|
expect(app.use).toHaveBeenCalledWith(
|
2024-07-19 04:27:08 -07:00
|
|
|
[
|
|
|
|
'/rest/',
|
|
|
|
'/api/',
|
|
|
|
'/webhook/',
|
|
|
|
'/webhook-waiting/',
|
|
|
|
'/webhook-test/',
|
|
|
|
'/form/',
|
|
|
|
'/form-waiting/',
|
|
|
|
'/form-test/',
|
|
|
|
],
|
2024-07-15 03:16:27 -07:00
|
|
|
expect.any(Function),
|
|
|
|
);
|
|
|
|
});
|
|
|
|
|
|
|
|
it('should set up event bus metrics', async () => {
|
|
|
|
const eventBus = mock<MessageEventBus>();
|
2024-07-31 08:45:11 -07:00
|
|
|
const service = new PrometheusMetricsService(mock(), eventBus, globalConfig);
|
2024-07-15 03:16:27 -07:00
|
|
|
|
2024-07-18 01:27:35 -07:00
|
|
|
await service.init(mock<express.Application>());
|
2024-07-15 03:16:27 -07:00
|
|
|
|
2024-07-18 01:27:35 -07:00
|
|
|
expect(eventBus.on).toHaveBeenCalledWith('metrics.eventBus.event', expect.any(Function));
|
2024-07-15 03:16:27 -07:00
|
|
|
});
|
|
|
|
});
|
|
|
|
});
|