n8n
Version:
n8n Workflow Automation Tool
221 lines • 10 kB
JavaScript
"use strict";
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
return c > 3 && r && Object.defineProperty(target, key, r), r;
};
var __metadata = (this && this.__metadata) || function (k, v) {
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
};
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.PrometheusMetricsService = void 0;
const constants_1 = require("../constants");
const express_prom_bundle_1 = __importDefault(require("express-prom-bundle"));
const prom_client_1 = __importDefault(require("prom-client"));
const parse_1 = __importDefault(require("semver/functions/parse"));
const typedi_1 = require("typedi");
const cache_service_1 = require("../services/cache/cache.service");
const MessageEventBus_1 = require("../eventbus/MessageEventBus/MessageEventBus");
const config_1 = require("@n8n/config");
let PrometheusMetricsService = class PrometheusMetricsService {
constructor(cacheService, eventBus, globalConfig) {
this.cacheService = cacheService;
this.eventBus = eventBus;
this.globalConfig = globalConfig;
this.counters = {};
this.prefix = this.globalConfig.endpoints.metrics.prefix;
this.includes = {
metrics: {
default: this.globalConfig.endpoints.metrics.includeDefaultMetrics,
routes: this.globalConfig.endpoints.metrics.includeApiEndpoints,
cache: this.globalConfig.endpoints.metrics.includeCacheMetrics,
logs: this.globalConfig.endpoints.metrics.includeMessageEventBusMetrics,
},
labels: {
credentialsType: this.globalConfig.endpoints.metrics.includeCredentialTypeLabel,
nodeType: this.globalConfig.endpoints.metrics.includeNodeTypeLabel,
workflowId: this.globalConfig.endpoints.metrics.includeWorkflowIdLabel,
apiPath: this.globalConfig.endpoints.metrics.includeApiPathLabel,
apiMethod: this.globalConfig.endpoints.metrics.includeApiMethodLabel,
apiStatusCode: this.globalConfig.endpoints.metrics.includeApiStatusCodeLabel,
},
};
}
async init(app) {
prom_client_1.default.register.clear();
this.initDefaultMetrics();
this.initN8nVersionMetric();
this.initCacheMetrics();
this.initEventBusMetrics();
this.initRouteMetrics(app);
this.mountMetricsEndpoint(app);
}
enableMetric(metric) {
this.includes.metrics[metric] = true;
}
disableMetric(metric) {
this.includes.metrics[metric] = false;
}
disableAllMetrics() {
for (const metric in this.includes.metrics) {
this.includes.metrics[metric] = false;
}
}
enableLabels(labels) {
for (const label of labels) {
this.includes.labels[label] = true;
}
}
disableAllLabels() {
for (const label in this.includes.labels) {
this.includes.labels[label] = false;
}
}
initN8nVersionMetric() {
const n8nVersion = (0, parse_1.default)(constants_1.N8N_VERSION !== null && constants_1.N8N_VERSION !== void 0 ? constants_1.N8N_VERSION : '0.0.0');
if (!n8nVersion)
return;
const versionGauge = new prom_client_1.default.Gauge({
name: this.prefix + 'version_info',
help: 'n8n version info.',
labelNames: ['version', 'major', 'minor', 'patch'],
});
const { version, major, minor, patch } = n8nVersion;
versionGauge.set({ version: 'v' + version, major, minor, patch }, 1);
}
initDefaultMetrics() {
if (!this.includes.metrics.default)
return;
prom_client_1.default.collectDefaultMetrics();
}
initRouteMetrics(app) {
if (!this.includes.metrics.routes)
return;
const metricsMiddleware = (0, express_prom_bundle_1.default)({
autoregister: false,
includeUp: false,
includePath: this.includes.labels.apiPath,
includeMethod: this.includes.labels.apiMethod,
includeStatusCode: this.includes.labels.apiStatusCode,
});
app.use([
'/rest/',
'/api/',
'/webhook/',
'/webhook-waiting/',
'/webhook-test/',
'/form/',
'/form-waiting/',
'/form-test/',
], metricsMiddleware);
}
mountMetricsEndpoint(app) {
app.get('/metrics', async (_req, res) => {
const metrics = await prom_client_1.default.register.metrics();
const prefixedMetrics = this.addPrefixToMetrics(metrics);
res.setHeader('Content-Type', prom_client_1.default.register.contentType);
res.send(prefixedMetrics).end();
});
}
addPrefixToMetrics(metrics) {
return metrics
.split('\n')
.map((rawLine) => {
const line = rawLine.trim();
if (!line || line.startsWith('#') || line.startsWith(this.prefix))
return rawLine;
return this.prefix + line;
})
.join('\n');
}
initCacheMetrics() {
if (!this.includes.metrics.cache)
return;
const [hitsConfig, missesConfig, updatesConfig] = ['hits', 'misses', 'updates'].map((kind) => ({
name: this.prefix + 'cache_' + kind + '_total',
help: `Total number of cache ${kind}.`,
labelNames: ['cache'],
}));
this.counters.cacheHitsTotal = new prom_client_1.default.Counter(hitsConfig);
this.counters.cacheHitsTotal.inc(0);
this.cacheService.on('metrics.cache.hit', () => { var _a; return (_a = this.counters.cacheHitsTotal) === null || _a === void 0 ? void 0 : _a.inc(1); });
this.counters.cacheMissesTotal = new prom_client_1.default.Counter(missesConfig);
this.counters.cacheMissesTotal.inc(0);
this.cacheService.on('metrics.cache.miss', () => { var _a; return (_a = this.counters.cacheMissesTotal) === null || _a === void 0 ? void 0 : _a.inc(1); });
this.counters.cacheUpdatesTotal = new prom_client_1.default.Counter(updatesConfig);
this.counters.cacheUpdatesTotal.inc(0);
this.cacheService.on('metrics.cache.update', () => { var _a; return (_a = this.counters.cacheUpdatesTotal) === null || _a === void 0 ? void 0 : _a.inc(1); });
}
toCounter(event) {
const { eventName } = event;
if (!this.counters[eventName]) {
const metricName = this.prefix + eventName.replace('n8n.', '').replace(/\./g, '_') + '_total';
if (!prom_client_1.default.validateMetricName(metricName)) {
this.counters[eventName] = null;
return null;
}
const labels = this.toLabels(event);
const counter = new prom_client_1.default.Counter({
name: metricName,
help: `Total number of ${eventName} events.`,
labelNames: Object.keys(labels),
});
counter.labels(labels).inc(0);
this.counters[eventName] = counter;
}
return this.counters[eventName];
}
initEventBusMetrics() {
if (!this.includes.metrics.logs)
return;
this.eventBus.on('metrics.eventBus.event', (event) => {
const counter = this.toCounter(event);
if (!counter)
return;
counter.inc(1);
});
}
toLabels(event) {
var _a, _b, _c, _d;
const { __type, eventName, payload } = event;
switch (__type) {
case "$$EventMessageAudit":
if (eventName.startsWith('n8n.audit.user.credentials')) {
return this.includes.labels.credentialsType
? { credential_type: ((_a = event.payload.credentialType) !== null && _a !== void 0 ? _a : 'unknown').replace(/\./g, '_') }
: {};
}
if (eventName.startsWith('n8n.audit.workflow')) {
return this.includes.labels.workflowId
? { workflow_id: (_b = payload.workflowId) !== null && _b !== void 0 ? _b : 'unknown' }
: {};
}
break;
case "$$EventMessageNode":
return this.includes.labels.nodeType
? {
node_type: ((_c = payload.nodeType) !== null && _c !== void 0 ? _c : 'unknown')
.replace('n8n-nodes-', '')
.replace(/\./g, '_'),
}
: {};
case "$$EventMessageWorkflow":
return this.includes.labels.workflowId
? { workflow_id: (_d = payload.workflowId) !== null && _d !== void 0 ? _d : 'unknown' }
: {};
}
return {};
}
};
exports.PrometheusMetricsService = PrometheusMetricsService;
exports.PrometheusMetricsService = PrometheusMetricsService = __decorate([
(0, typedi_1.Service)(),
__metadata("design:paramtypes", [cache_service_1.CacheService,
MessageEventBus_1.MessageEventBus,
config_1.GlobalConfig])
], PrometheusMetricsService);
//# sourceMappingURL=prometheus-metrics.service.js.map