From 88c0838dd72f11646bdb3586223d6c16631cccab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Iv=C3=A1n=20Ovejero?= Date: Wed, 8 Jan 2025 17:47:40 +0100 Subject: [PATCH] fix(core): Fix Sentry error reporting on task runners (#12495) --- .../@n8n/config/src/configs/sentry.config.ts | 28 +++++++++++++++++-- packages/@n8n/config/test/config.test.ts | 3 ++ .../task-runner/src/config/sentry-config.ts | 4 +-- .../__tests__/js-task-runner.test.ts | 2 +- packages/@n8n/task-runner/src/start.ts | 13 +++++++-- packages/cli/src/commands/base-command.ts | 13 ++++++--- packages/core/src/error-reporter.ts | 18 ++++++------ 7 files changed, 62 insertions(+), 19 deletions(-) diff --git a/packages/@n8n/config/src/configs/sentry.config.ts b/packages/@n8n/config/src/configs/sentry.config.ts index d1067f9984..97e34edeea 100644 --- a/packages/@n8n/config/src/configs/sentry.config.ts +++ b/packages/@n8n/config/src/configs/sentry.config.ts @@ -2,11 +2,35 @@ import { Config, Env } from '../decorators'; @Config export class SentryConfig { - /** Sentry DSN for the backend. */ + /** Sentry DSN (data source name) for the backend. */ @Env('N8N_SENTRY_DSN') backendDsn: string = ''; - /** Sentry DSN for the frontend . */ + /** Sentry DSN (data source name) for the frontend. */ @Env('N8N_FRONTEND_SENTRY_DSN') 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 = ''; } diff --git a/packages/@n8n/config/test/config.test.ts b/packages/@n8n/config/test/config.test.ts index ed386fee6b..2e63b8d10f 100644 --- a/packages/@n8n/config/test/config.test.ts +++ b/packages/@n8n/config/test/config.test.ts @@ -236,6 +236,9 @@ describe('GlobalConfig', () => { sentry: { backendDsn: '', frontendDsn: '', + n8nVersion: '', + environment: '', + deploymentName: '', }, logging: { level: 'info', diff --git a/packages/@n8n/task-runner/src/config/sentry-config.ts b/packages/@n8n/task-runner/src/config/sentry-config.ts index 691f64244f..ae24221a5e 100644 --- a/packages/@n8n/task-runner/src/config/sentry-config.ts +++ b/packages/@n8n/task-runner/src/config/sentry-config.ts @@ -2,9 +2,9 @@ import { Config, Env } from '@n8n/config'; @Config export class SentryConfig { - /** Sentry DSN */ + /** Sentry DSN (data source name) */ @Env('N8N_SENTRY_DSN') - sentryDsn: string = ''; + dsn: string = ''; //#region Metadata about the environment diff --git a/packages/@n8n/task-runner/src/js-task-runner/__tests__/js-task-runner.test.ts b/packages/@n8n/task-runner/src/js-task-runner/__tests__/js-task-runner.test.ts index 5ebd965e87..39b6ba7f45 100644 --- a/packages/@n8n/task-runner/src/js-task-runner/__tests__/js-task-runner.test.ts +++ b/packages/@n8n/task-runner/src/js-task-runner/__tests__/js-task-runner.test.ts @@ -50,7 +50,7 @@ describe('JsTaskRunner', () => { ...jsRunnerOpts, }, sentryConfig: { - sentryDsn: '', + dsn: '', deploymentName: '', environment: '', n8nVersion: '', diff --git a/packages/@n8n/task-runner/src/start.ts b/packages/@n8n/task-runner/src/start.ts index 536b550d17..cbc381c2fd 100644 --- a/packages/@n8n/task-runner/src/start.ts +++ b/packages/@n8n/task-runner/src/start.ts @@ -54,10 +54,19 @@ void (async function start() { defaultTimezone: config.baseRunnerConfig.timezone, }); - if (config.sentryConfig.sentryDsn) { + const { dsn } = config.sentryConfig; + + if (dsn) { const { ErrorReporter } = await import('n8n-core'); 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); diff --git a/packages/cli/src/commands/base-command.ts b/packages/cli/src/commands/base-command.ts index 56799c5089..9bfd992b3d 100644 --- a/packages/cli/src/commands/base-command.ts +++ b/packages/cli/src/commands/base-command.ts @@ -61,10 +61,15 @@ export abstract class BaseCommand extends Command { async init(): Promise { this.errorReporter = Container.get(ErrorReporter); - await this.errorReporter.init( - this.instanceSettings.instanceType, - this.globalConfig.sentry.backendDsn, - ); + + const { backendDsn, n8nVersion, environment, deploymentName } = this.globalConfig.sentry; + await this.errorReporter.init({ + serverType: this.instanceSettings.instanceType, + dsn: backendDsn, + environment, + release: n8nVersion, + serverName: deploymentName, + }); initExpressionEvaluator(); process.once('SIGTERM', this.onTerminationSignal('SIGTERM')); diff --git a/packages/core/src/error-reporter.ts b/packages/core/src/error-reporter.ts index 0bc0f6058e..84f67a0395 100644 --- a/packages/core/src/error-reporter.ts +++ b/packages/core/src/error-reporter.ts @@ -9,6 +9,14 @@ import { createHash } from 'node:crypto'; import type { InstanceType } from './InstanceSettings'; import { Logger } from './logging/logger'; +type ErrorReporterInitOptions = { + serverType: InstanceType | 'task_runner'; + dsn: string; + release: string; + environment: string; + serverName: string; +}; + @Service() export class ErrorReporter { /** Hashes of error stack traces, to deduplicate error reports. */ @@ -44,7 +52,7 @@ export class ErrorReporter { await close(timeoutInMs); } - async init(instanceType: InstanceType | 'task_runner', dsn: string) { + async init({ dsn, serverType, release, environment, serverName }: ErrorReporterInitOptions) { process.on('uncaughtException', (error) => { this.error(error); }); @@ -54,12 +62,6 @@ export class ErrorReporter { // Collect longer stacktraces Error.stackTraceLimit = 50; - const { - N8N_VERSION: release, - ENVIRONMENT: environment, - DEPLOYMENT_NAME: serverName, - } = process.env; - const { init, captureException, setTag } = 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); }