mirror of
https://github.com/n8n-io/n8n.git
synced 2025-03-05 20:50:17 -08:00
fix(core): Fix Sentry error reporting on task runners (#12495)
Some checks failed
Test Master / install-and-build (push) Waiting to run
Test Master / Unit tests (18.x) (push) Blocked by required conditions
Test Master / Unit tests (20.x) (push) Blocked by required conditions
Test Master / Unit tests (22.4) (push) Blocked by required conditions
Test Master / Lint (push) Blocked by required conditions
Test Master / Notify Slack on failure (push) Blocked by required conditions
Benchmark Docker Image CI / build (push) Has been cancelled
Some checks failed
Test Master / install-and-build (push) Waiting to run
Test Master / Unit tests (18.x) (push) Blocked by required conditions
Test Master / Unit tests (20.x) (push) Blocked by required conditions
Test Master / Unit tests (22.4) (push) Blocked by required conditions
Test Master / Lint (push) Blocked by required conditions
Test Master / Notify Slack on failure (push) Blocked by required conditions
Benchmark Docker Image CI / build (push) Has been cancelled
This commit is contained in:
parent
dd36bb28bf
commit
88c0838dd7
|
@ -2,11 +2,35 @@ import { Config, Env } from '../decorators';
|
||||||
|
|
||||||
@Config
|
@Config
|
||||||
export class SentryConfig {
|
export class SentryConfig {
|
||||||
/** Sentry DSN for the backend. */
|
/** Sentry DSN (data source name) for the backend. */
|
||||||
@Env('N8N_SENTRY_DSN')
|
@Env('N8N_SENTRY_DSN')
|
||||||
backendDsn: string = '';
|
backendDsn: string = '';
|
||||||
|
|
||||||
/** Sentry DSN for the frontend . */
|
/** Sentry DSN (data source name) for the frontend. */
|
||||||
@Env('N8N_FRONTEND_SENTRY_DSN')
|
@Env('N8N_FRONTEND_SENTRY_DSN')
|
||||||
frontendDsn: string = '';
|
frontendDsn: string = '';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Version of the n8n instance
|
||||||
|
*
|
||||||
|
* @example '1.73.0'
|
||||||
|
*/
|
||||||
|
@Env('N8N_VERSION')
|
||||||
|
n8nVersion: string = '';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Environment of the n8n instance.
|
||||||
|
*
|
||||||
|
* @example 'production'
|
||||||
|
*/
|
||||||
|
@Env('ENVIRONMENT')
|
||||||
|
environment: string = '';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Name of the deployment, e.g. cloud account name.
|
||||||
|
*
|
||||||
|
* @example 'janober'
|
||||||
|
*/
|
||||||
|
@Env('DEPLOYMENT_NAME')
|
||||||
|
deploymentName: string = '';
|
||||||
}
|
}
|
||||||
|
|
|
@ -236,6 +236,9 @@ describe('GlobalConfig', () => {
|
||||||
sentry: {
|
sentry: {
|
||||||
backendDsn: '',
|
backendDsn: '',
|
||||||
frontendDsn: '',
|
frontendDsn: '',
|
||||||
|
n8nVersion: '',
|
||||||
|
environment: '',
|
||||||
|
deploymentName: '',
|
||||||
},
|
},
|
||||||
logging: {
|
logging: {
|
||||||
level: 'info',
|
level: 'info',
|
||||||
|
|
|
@ -2,9 +2,9 @@ import { Config, Env } from '@n8n/config';
|
||||||
|
|
||||||
@Config
|
@Config
|
||||||
export class SentryConfig {
|
export class SentryConfig {
|
||||||
/** Sentry DSN */
|
/** Sentry DSN (data source name) */
|
||||||
@Env('N8N_SENTRY_DSN')
|
@Env('N8N_SENTRY_DSN')
|
||||||
sentryDsn: string = '';
|
dsn: string = '';
|
||||||
|
|
||||||
//#region Metadata about the environment
|
//#region Metadata about the environment
|
||||||
|
|
||||||
|
|
|
@ -50,7 +50,7 @@ describe('JsTaskRunner', () => {
|
||||||
...jsRunnerOpts,
|
...jsRunnerOpts,
|
||||||
},
|
},
|
||||||
sentryConfig: {
|
sentryConfig: {
|
||||||
sentryDsn: '',
|
dsn: '',
|
||||||
deploymentName: '',
|
deploymentName: '',
|
||||||
environment: '',
|
environment: '',
|
||||||
n8nVersion: '',
|
n8nVersion: '',
|
||||||
|
|
|
@ -54,10 +54,19 @@ void (async function start() {
|
||||||
defaultTimezone: config.baseRunnerConfig.timezone,
|
defaultTimezone: config.baseRunnerConfig.timezone,
|
||||||
});
|
});
|
||||||
|
|
||||||
if (config.sentryConfig.sentryDsn) {
|
const { dsn } = config.sentryConfig;
|
||||||
|
|
||||||
|
if (dsn) {
|
||||||
const { ErrorReporter } = await import('n8n-core');
|
const { ErrorReporter } = await import('n8n-core');
|
||||||
errorReporter = Container.get(ErrorReporter);
|
errorReporter = Container.get(ErrorReporter);
|
||||||
await errorReporter.init('task_runner', config.sentryConfig.sentryDsn);
|
const { deploymentName, environment, n8nVersion } = config.sentryConfig;
|
||||||
|
await errorReporter.init({
|
||||||
|
serverType: 'task_runner',
|
||||||
|
dsn,
|
||||||
|
serverName: deploymentName,
|
||||||
|
environment,
|
||||||
|
release: n8nVersion,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
runner = new JsTaskRunner(config);
|
runner = new JsTaskRunner(config);
|
||||||
|
|
|
@ -61,10 +61,15 @@ export abstract class BaseCommand extends Command {
|
||||||
|
|
||||||
async init(): Promise<void> {
|
async init(): Promise<void> {
|
||||||
this.errorReporter = Container.get(ErrorReporter);
|
this.errorReporter = Container.get(ErrorReporter);
|
||||||
await this.errorReporter.init(
|
|
||||||
this.instanceSettings.instanceType,
|
const { backendDsn, n8nVersion, environment, deploymentName } = this.globalConfig.sentry;
|
||||||
this.globalConfig.sentry.backendDsn,
|
await this.errorReporter.init({
|
||||||
);
|
serverType: this.instanceSettings.instanceType,
|
||||||
|
dsn: backendDsn,
|
||||||
|
environment,
|
||||||
|
release: n8nVersion,
|
||||||
|
serverName: deploymentName,
|
||||||
|
});
|
||||||
initExpressionEvaluator();
|
initExpressionEvaluator();
|
||||||
|
|
||||||
process.once('SIGTERM', this.onTerminationSignal('SIGTERM'));
|
process.once('SIGTERM', this.onTerminationSignal('SIGTERM'));
|
||||||
|
|
|
@ -9,6 +9,14 @@ import { createHash } from 'node:crypto';
|
||||||
import type { InstanceType } from './InstanceSettings';
|
import type { InstanceType } from './InstanceSettings';
|
||||||
import { Logger } from './logging/logger';
|
import { Logger } from './logging/logger';
|
||||||
|
|
||||||
|
type ErrorReporterInitOptions = {
|
||||||
|
serverType: InstanceType | 'task_runner';
|
||||||
|
dsn: string;
|
||||||
|
release: string;
|
||||||
|
environment: string;
|
||||||
|
serverName: string;
|
||||||
|
};
|
||||||
|
|
||||||
@Service()
|
@Service()
|
||||||
export class ErrorReporter {
|
export class ErrorReporter {
|
||||||
/** Hashes of error stack traces, to deduplicate error reports. */
|
/** Hashes of error stack traces, to deduplicate error reports. */
|
||||||
|
@ -44,7 +52,7 @@ export class ErrorReporter {
|
||||||
await close(timeoutInMs);
|
await close(timeoutInMs);
|
||||||
}
|
}
|
||||||
|
|
||||||
async init(instanceType: InstanceType | 'task_runner', dsn: string) {
|
async init({ dsn, serverType, release, environment, serverName }: ErrorReporterInitOptions) {
|
||||||
process.on('uncaughtException', (error) => {
|
process.on('uncaughtException', (error) => {
|
||||||
this.error(error);
|
this.error(error);
|
||||||
});
|
});
|
||||||
|
@ -54,12 +62,6 @@ export class ErrorReporter {
|
||||||
// Collect longer stacktraces
|
// Collect longer stacktraces
|
||||||
Error.stackTraceLimit = 50;
|
Error.stackTraceLimit = 50;
|
||||||
|
|
||||||
const {
|
|
||||||
N8N_VERSION: release,
|
|
||||||
ENVIRONMENT: environment,
|
|
||||||
DEPLOYMENT_NAME: serverName,
|
|
||||||
} = process.env;
|
|
||||||
|
|
||||||
const { init, captureException, setTag } = await import('@sentry/node');
|
const { init, captureException, setTag } = await import('@sentry/node');
|
||||||
const { requestDataIntegration, rewriteFramesIntegration } = await import('@sentry/node');
|
const { requestDataIntegration, rewriteFramesIntegration } = await import('@sentry/node');
|
||||||
|
|
||||||
|
@ -95,7 +97,7 @@ export class ErrorReporter {
|
||||||
],
|
],
|
||||||
});
|
});
|
||||||
|
|
||||||
setTag('server_type', instanceType);
|
setTag('server_type', serverType);
|
||||||
|
|
||||||
this.report = (error, options) => captureException(error, options);
|
this.report = (error, options) => captureException(error, options);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue