From 2ff35b780325544a9a6e8e5b15f2028d9f946236 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uro=C5=A1=20Marolt?= Date: Tue, 7 Apr 2026 10:37:44 +0200 Subject: [PATCH 1/4] fix: removed the detail section because it's not helpful MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Uroš Marolt --- .../src/jobs/integrationResultsReporting.job.ts | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/services/apps/cron_service/src/jobs/integrationResultsReporting.job.ts b/services/apps/cron_service/src/jobs/integrationResultsReporting.job.ts index f95542526e..374273868b 100644 --- a/services/apps/cron_service/src/jobs/integrationResultsReporting.job.ts +++ b/services/apps/cron_service/src/jobs/integrationResultsReporting.job.ts @@ -20,7 +20,6 @@ interface IResultStateCount { interface IErrorGroup { errorMessage: string location: string - message: string count: number avgRetries: number maxRetries: number @@ -69,7 +68,6 @@ const job: IJobDefinition = { SELECT COALESCE(r.error->>'errorMessage', '[no errorMessage]') AS "errorMessage", COALESCE(r.error->>'location', '[no location]') AS location, - COALESCE(r.error->>'message', '[no message]') AS message, count(*)::int AS count, round(avg(r.retries), 1)::float AS "avgRetries", max(r.retries)::int AS "maxRetries", @@ -81,8 +79,7 @@ const job: IJobDefinition = { WHERE r.state = 'error' GROUP BY r.error->>'errorMessage', - r.error->>'location', - r.error->>'message' + r.error->>'location' ORDER BY count DESC LIMIT 20 `, @@ -125,7 +122,6 @@ const job: IJobDefinition = { `• *${group.count}x* \`${group.errorMessage}\``, ` _Location:_ \`${group.location}\` | _retries avg/max:_ ${group.avgRetries}/${group.maxRetries}${group.platforms ? ` | _platforms:_ \`${group.platforms}\`` : ''}`, ` _Age:_ ${ageLabel}`, - ` _Detail:_ ${group.message}`, '', ) } From a6399ef9e8afd732b450fa1fbc6946c8e749cb5d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uro=C5=A1=20Marolt?= Date: Tue, 7 Apr 2026 12:47:28 +0200 Subject: [PATCH 2/4] fix: better location MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Uroš Marolt --- .../src/service/dataSink.service.ts | 38 +++++++++++++------ 1 file changed, 26 insertions(+), 12 deletions(-) diff --git a/services/apps/data_sink_worker/src/service/dataSink.service.ts b/services/apps/data_sink_worker/src/service/dataSink.service.ts index 54fcd50dfa..9769be03d6 100644 --- a/services/apps/data_sink_worker/src/service/dataSink.service.ts +++ b/services/apps/data_sink_worker/src/service/dataSink.service.ts @@ -35,6 +35,30 @@ import MemberService from './member.service' /* eslint-disable @typescript-eslint/no-explicit-any */ +/** + * Extracts the first app-code frame from an error's stack trace as the location. + * Uses process.cwd() (the service root) to match only this service's own source + * files, skipping node_modules and shared library frames. + */ +function extractLocationFromError(error: unknown): string { + const stack = (error as any)?.stack + if (!stack) return 'unknown' + + const serviceDir = process.cwd() + for (const line of (stack as string).split('\n')) { + if (line.includes(serviceDir)) { + const match = line.match(/at\s+(?:(.+?)\s+)?\(?(.+?):(\d+):\d+\)?$/) + if (match) { + const fn = match[1]?.trim() + const file = match[2].replace(`${serviceDir}/`, '') + return fn ? `${file}:${match[3]} (${fn})` : `${file}:${match[3]}` + } + } + } + + return 'unknown' +} + export default class DataSinkService extends LoggerBase { private readonly repo: DataSinkRepository @@ -55,15 +79,12 @@ export default class DataSinkService extends LoggerBase { private async triggerResultError( resultInfo: IResultData, resultExists: boolean, - location: string, - message: string, error: any, metadata?: Record, ): Promise { // eslint-disable-next-line @typescript-eslint/no-explicit-any const errorData: any = { - location, - message, + location: extractLocationFromError(error), metadata, @@ -463,14 +484,7 @@ export default class DataSinkService extends LoggerBase { if (!result.success) { const resultInfo = single(results, (r) => r.id === resultId) - await this.triggerResultError( - resultInfo, - batchEntry.created, - 'process-result', - 'Error processing result.', - result.err, - result.metadata, - ) + await this.triggerResultError(resultInfo, batchEntry.created, result.err, result.metadata) errors++ } else { From f416fd4d528bd1d5c74ea9e6ef827677c21d3b3b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uro=C5=A1=20Marolt?= Date: Tue, 7 Apr 2026 12:54:02 +0200 Subject: [PATCH 3/4] fix: comment MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Uroš Marolt --- services/apps/data_sink_worker/src/service/dataSink.service.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/services/apps/data_sink_worker/src/service/dataSink.service.ts b/services/apps/data_sink_worker/src/service/dataSink.service.ts index 9769be03d6..166bc66806 100644 --- a/services/apps/data_sink_worker/src/service/dataSink.service.ts +++ b/services/apps/data_sink_worker/src/service/dataSink.service.ts @@ -46,7 +46,7 @@ function extractLocationFromError(error: unknown): string { const serviceDir = process.cwd() for (const line of (stack as string).split('\n')) { - if (line.includes(serviceDir)) { + if (line.includes(serviceDir) && !line.includes('node_modules')) { const match = line.match(/at\s+(?:(.+?)\s+)?\(?(.+?):(\d+):\d+\)?$/) if (match) { const fn = match[1]?.trim() From c48bbb7a928f918fa84fe3f72355556621c6a838 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uro=C5=A1=20Marolt?= Date: Tue, 7 Apr 2026 13:12:19 +0200 Subject: [PATCH 4/4] fix: comment MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Uroš Marolt --- .../src/service/dataSink.service.ts | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/services/apps/data_sink_worker/src/service/dataSink.service.ts b/services/apps/data_sink_worker/src/service/dataSink.service.ts index 166bc66806..0f7a616e9f 100644 --- a/services/apps/data_sink_worker/src/service/dataSink.service.ts +++ b/services/apps/data_sink_worker/src/service/dataSink.service.ts @@ -47,11 +47,16 @@ function extractLocationFromError(error: unknown): string { const serviceDir = process.cwd() for (const line of (stack as string).split('\n')) { if (line.includes(serviceDir) && !line.includes('node_modules')) { - const match = line.match(/at\s+(?:(.+?)\s+)?\(?(.+?):(\d+):\d+\)?$/) - if (match) { - const fn = match[1]?.trim() - const file = match[2].replace(`${serviceDir}/`, '') - return fn ? `${file}:${match[3]} (${fn})` : `${file}:${match[3]}` + // Named frame: "at [async] FunctionName (file:line:col)" + const named = line.match(/at\s+(.+)\s+\((.+):(\d+):\d+\)/) + if (named) { + const file = named[2].replace(`${serviceDir}/`, '') + return `${file}:${named[3]} (${named[1].trim()})` + } + // Anonymous frame: "at file:line:col" + const anon = line.match(/at\s+\(?(.+):(\d+):\d+\)?/) + if (anon) { + return `${anon[1].replace(`${serviceDir}/`, '')}:${anon[2]}` } } }