UNPKG

n8n

Version:

n8n Workflow Automation Tool

221 lines 10 kB
"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