mirror of
https://github.com/n8n-io/n8n.git
synced 2024-12-24 04:04:06 -08:00
✨ Add metrics endpoint (#1515)
This commit adds the new package prom-client in order to expose metrics to prometheus as well as the endpoint and the configuration to do so.
This commit is contained in:
parent
8d2371917f
commit
b0b172a362
|
@ -446,6 +446,20 @@ const config = convict({
|
||||||
},
|
},
|
||||||
|
|
||||||
endpoints: {
|
endpoints: {
|
||||||
|
metrics: {
|
||||||
|
enable: {
|
||||||
|
format: 'Boolean',
|
||||||
|
default: false,
|
||||||
|
env: 'N8N_ENABLE_METRICS',
|
||||||
|
doc: 'Enable metrics endpoint',
|
||||||
|
},
|
||||||
|
prefix: {
|
||||||
|
format: String,
|
||||||
|
default: 'n8n_',
|
||||||
|
env: 'N8N_METRICS_PREFIX',
|
||||||
|
doc: 'An optional prefix for metric names. Default: n8n_',
|
||||||
|
},
|
||||||
|
},
|
||||||
rest: {
|
rest: {
|
||||||
format: String,
|
format: String,
|
||||||
default: 'rest',
|
default: 'rest',
|
||||||
|
@ -471,7 +485,7 @@ const config = convict({
|
||||||
doc: 'Disable production webhooks from main process. This helps ensures no http traffic load to main process when using webhook-specific processes.',
|
doc: 'Disable production webhooks from main process. This helps ensures no http traffic load to main process when using webhook-specific processes.',
|
||||||
},
|
},
|
||||||
skipWebhoooksDeregistrationOnShutdown: {
|
skipWebhoooksDeregistrationOnShutdown: {
|
||||||
/**
|
/**
|
||||||
* Longer explanation: n8n deregisters webhooks on shutdown / deactivation
|
* Longer explanation: n8n deregisters webhooks on shutdown / deactivation
|
||||||
* and registers on startup / activation. If we skip
|
* and registers on startup / activation. If we skip
|
||||||
* deactivation on shutdown, webhooks will remain active on 3rd party services.
|
* deactivation on shutdown, webhooks will remain active on 3rd party services.
|
||||||
|
|
|
@ -111,6 +111,7 @@
|
||||||
"oauth-1.0a": "^2.2.6",
|
"oauth-1.0a": "^2.2.6",
|
||||||
"open": "^7.0.0",
|
"open": "^7.0.0",
|
||||||
"pg": "^8.3.0",
|
"pg": "^8.3.0",
|
||||||
|
"prom-client": "^13.1.0",
|
||||||
"request-promise-native": "^1.0.7",
|
"request-promise-native": "^1.0.7",
|
||||||
"sqlite3": "^5.0.1",
|
"sqlite3": "^5.0.1",
|
||||||
"sse-channel": "^3.1.1",
|
"sse-channel": "^3.1.1",
|
||||||
|
|
|
@ -23,6 +23,7 @@ import * as csrf from 'csrf';
|
||||||
import * as requestPromise from 'request-promise-native';
|
import * as requestPromise from 'request-promise-native';
|
||||||
import { createHmac } from 'crypto';
|
import { createHmac } from 'crypto';
|
||||||
import { compare } from 'bcryptjs';
|
import { compare } from 'bcryptjs';
|
||||||
|
import * as promClient from 'prom-client';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
ActiveExecutions,
|
ActiveExecutions,
|
||||||
|
@ -108,6 +109,7 @@ import * as parseUrl from 'parseurl';
|
||||||
import * as querystring from 'querystring';
|
import * as querystring from 'querystring';
|
||||||
import * as Queue from '../src/Queue';
|
import * as Queue from '../src/Queue';
|
||||||
import { OptionsWithUrl } from 'request-promise-native';
|
import { OptionsWithUrl } from 'request-promise-native';
|
||||||
|
import { Registry } from 'prom-client';
|
||||||
|
|
||||||
class App {
|
class App {
|
||||||
|
|
||||||
|
@ -197,6 +199,16 @@ class App {
|
||||||
|
|
||||||
async config(): Promise<void> {
|
async config(): Promise<void> {
|
||||||
|
|
||||||
|
const enableMetrics = config.get('endpoints.metrics.enable') as boolean;
|
||||||
|
let register: Registry;
|
||||||
|
|
||||||
|
if (enableMetrics === true) {
|
||||||
|
const prefix = config.get('endpoints.metrics.prefix') as string;
|
||||||
|
register = new promClient.Registry();
|
||||||
|
register.setDefaultLabels({ prefix });
|
||||||
|
promClient.collectDefaultMetrics({ register });
|
||||||
|
}
|
||||||
|
|
||||||
this.versions = await GenericHelpers.getVersions();
|
this.versions = await GenericHelpers.getVersions();
|
||||||
this.frontendSettings.versionCli = this.versions.cli;
|
this.frontendSettings.versionCli = this.versions.cli;
|
||||||
|
|
||||||
|
@ -204,7 +216,7 @@ class App {
|
||||||
|
|
||||||
const excludeEndpoints = config.get('security.excludeEndpoints') as string;
|
const excludeEndpoints = config.get('security.excludeEndpoints') as string;
|
||||||
|
|
||||||
const ignoredEndpoints = ['healthz', this.endpointWebhook, this.endpointWebhookTest, this.endpointPresetCredentials];
|
const ignoredEndpoints = ['healthz', 'metrics', this.endpointWebhook, this.endpointWebhookTest, this.endpointPresetCredentials];
|
||||||
ignoredEndpoints.push.apply(ignoredEndpoints, excludeEndpoints.split(':'));
|
ignoredEndpoints.push.apply(ignoredEndpoints, excludeEndpoints.split(':'));
|
||||||
|
|
||||||
const authIgnoreRegex = new RegExp(`^\/(${_(ignoredEndpoints).compact().join('|')})\/?.*$`);
|
const authIgnoreRegex = new RegExp(`^\/(${_(ignoredEndpoints).compact().join('|')})\/?.*$`);
|
||||||
|
@ -386,7 +398,7 @@ class App {
|
||||||
this.app.use(history({
|
this.app.use(history({
|
||||||
rewrites: [
|
rewrites: [
|
||||||
{
|
{
|
||||||
from: new RegExp(`^\/(${this.restEndpoint}|healthz|css|js|${this.endpointWebhook}|${this.endpointWebhookTest})\/?.*$`),
|
from: new RegExp(`^\/(${this.restEndpoint}|healthz|metrics|css|js|${this.endpointWebhook}|${this.endpointWebhookTest})\/?.*$`),
|
||||||
to: (context) => {
|
to: (context) => {
|
||||||
return context.parsedUrl!.pathname!.toString();
|
return context.parsedUrl!.pathname!.toString();
|
||||||
},
|
},
|
||||||
|
@ -454,7 +466,16 @@ class App {
|
||||||
ResponseHelper.sendSuccessResponse(res, responseData, true, 200);
|
ResponseHelper.sendSuccessResponse(res, responseData, true, 200);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// ----------------------------------------
|
||||||
|
// Metrics
|
||||||
|
// ----------------------------------------
|
||||||
|
if (enableMetrics === true) {
|
||||||
|
this.app.get('/metrics', async (req: express.Request, res: express.Response) => {
|
||||||
|
const response = await register.metrics();
|
||||||
|
res.setHeader('Content-Type', register.contentType);
|
||||||
|
ResponseHelper.sendSuccessResponse(res, response, true, 200);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
// ----------------------------------------
|
// ----------------------------------------
|
||||||
// Workflow
|
// Workflow
|
||||||
|
@ -1728,7 +1749,7 @@ class App {
|
||||||
stoppedAt: result.stoppedAt ? new Date(result.stoppedAt) : undefined,
|
stoppedAt: result.stoppedAt ? new Date(result.stoppedAt) : undefined,
|
||||||
finished: result.finished,
|
finished: result.finished,
|
||||||
};
|
};
|
||||||
|
|
||||||
return returnData;
|
return returnData;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue