From 6df591c5f2395aec2182c17b75c23fa3a0bc8b83 Mon Sep 17 00:00:00 2001 From: Esteban Galvis Date: Thu, 28 May 2026 15:25:12 -0500 Subject: [PATCH 1/2] fix: enhance antivirus log routing to support structured log entries and info level logs --- .../logging/setup-app-log-routing.test.ts | 33 ++++++++ .../main/logging/setup-app-log-routing.ts | 78 ++++++++++++------- 2 files changed, 84 insertions(+), 27 deletions(-) diff --git a/src/apps/main/logging/setup-app-log-routing.test.ts b/src/apps/main/logging/setup-app-log-routing.test.ts index 62120f946..787956306 100644 --- a/src/apps/main/logging/setup-app-log-routing.test.ts +++ b/src/apps/main/logging/setup-app-log-routing.test.ts @@ -43,6 +43,20 @@ describe('setup-app-log-routing', () => { expect(result).toBe('/tmp/internxt-logs/drive-important.log'); }); + it('should keep info level logs in the important file to match core logger behavior', () => { + // When + const result = resolveAppLogFilePath({ + logsPath, + message: { + level: 'info', + data: [createSerializedLogMessage({ header: 'E - b - anti', msg: '[CLAM_AVD] clamd process exited' })], + }, + }); + + // Then + expect(result).toBe('/tmp/internxt-logs/drive-important.log'); + }); + it('should keep non-antivirus logs in the main log file', () => { // When const result = resolveAppLogFilePath({ @@ -72,5 +86,24 @@ describe('setup-app-log-routing', () => { // Then expect(result).toBe('/tmp/internxt-logs/drive-antivirus.log'); }); + + it('should route structured antivirus logs when message data is an object', () => { + // When + const result = resolveAppLogFilePath({ + logsPath, + message: { + level: 'debug', + data: [ + { + tag: 'ANTIVIRUS', + msg: 'ClamAV initialized successfully', + }, + ], + }, + }); + + // Then + expect(result).toBe('/tmp/internxt-logs/drive-antivirus.log'); + }); }); }); diff --git a/src/apps/main/logging/setup-app-log-routing.ts b/src/apps/main/logging/setup-app-log-routing.ts index 39703545f..bd3914ecc 100644 --- a/src/apps/main/logging/setup-app-log-routing.ts +++ b/src/apps/main/logging/setup-app-log-routing.ts @@ -1,4 +1,3 @@ -import { createRequire } from 'node:module'; import { join } from 'node:path'; type Pops = { @@ -10,6 +9,13 @@ type LogMessage = { level?: string; }; +type StructuredLogEntry = { + tag?: unknown; + header?: unknown; + msg?: unknown; + message?: unknown; +}; + type ElectronLogModule = { transports: { file: { @@ -23,15 +29,28 @@ const DEFAULT_LOG_FILE_NAME = 'drive.log'; const IMPORTANT_LOG_FILE_NAME = 'drive-important.log'; const ANTIVIRUS_LOG_FILE_NAME = 'drive-antivirus.log'; const ANTIVIRUS_HEADER_PATTERN = /header:\s'[^']*-\santi'/; +const ANTIVIRUS_STRUCTURED_HEADER_PATTERN = /-\s*anti\b/i; const ANTIVIRUS_MESSAGE_PATTERNS = [ /\[CLAM_AVD\]/, /\[freshclam/i, /\[ANTIVIRUS_MANAGER\]/, /window\.electron\.antivirus/i, + /\bclamd?\b/i, /\bantivirus\b/i, ]; -const ELECTRON_LOG_MODULE_IDS = ['electron-log', '@internxt/drive-desktop-core/node_modules/electron-log']; -const moduleRequire = createRequire(__filename); + +/** + * Esteban Galvis Triana + * v2.6.0 + * Import the electron-log module that @internxt/drive-desktop-core + * bundles (nested node_modules). When webpack processes this file, it resolves + * this path to the same module instance used by setup-electron-log.js from the + * core package. Using createRequire() at runtime would load a DIFFERENT native + * instance that bypasses webpack's module registry, so patching it has no + * effect on the instance the logger actually uses. + */ +// eslint-disable-next-line @typescript-eslint/no-require-imports +const coreElectronLog = require('@internxt/drive-desktop-core/node_modules/electron-log') as ElectronLogModule; function isSerializedAntivirusLogEntry({ value }: { value: unknown }) { if (typeof value !== 'string') { @@ -41,12 +60,35 @@ function isSerializedAntivirusLogEntry({ value }: { value: unknown }) { return ANTIVIRUS_HEADER_PATTERN.test(value) || ANTIVIRUS_MESSAGE_PATTERNS.some((pattern) => pattern.test(value)); } +function isStructuredLogEntry(value: unknown): value is StructuredLogEntry { + return Boolean(value) && typeof value === 'object' && !Array.isArray(value); +} + +function isStructuredAntivirusLogEntry({ value }: { value: unknown }) { + if (!isStructuredLogEntry(value)) { + return false; + } + + const { tag, header, msg, message } = value; + const hasAntivirusTag = typeof tag === 'string' && (tag === 'ANTIVIRUS' || tag === 'anti'); + const hasAntivirusHeader = typeof header === 'string' && ANTIVIRUS_STRUCTURED_HEADER_PATTERN.test(header); + const hasAntivirusMessage = + (typeof msg === 'string' && ANTIVIRUS_MESSAGE_PATTERNS.some((pattern) => pattern.test(msg))) || + (typeof message === 'string' && ANTIVIRUS_MESSAGE_PATTERNS.some((pattern) => pattern.test(message))); + + return hasAntivirusTag || hasAntivirusHeader || hasAntivirusMessage; +} + function isAntivirusLogMessage({ message }: { message?: LogMessage }) { - return message?.data?.some((value) => isSerializedAntivirusLogEntry({ value })) ?? false; + return ( + message?.data?.some((value) => { + return isSerializedAntivirusLogEntry({ value }) || isStructuredAntivirusLogEntry({ value }); + }) ?? false + ); } export function resolveAppLogFilePath({ logsPath, message }: Pops & { message?: LogMessage }) { - if (message?.level === 'error') { + if (message?.level === 'error' || message?.level === 'info') { return join(logsPath, IMPORTANT_LOG_FILE_NAME); } @@ -57,28 +99,10 @@ export function resolveAppLogFilePath({ logsPath, message }: Pops & { message?: return join(logsPath, DEFAULT_LOG_FILE_NAME); } -function getElectronLogModules() { - const modules = new Map(); - - for (const moduleId of ELECTRON_LOG_MODULE_IDS) { - try { - const electronLog = moduleRequire(moduleId) as ElectronLogModule; - const resolvedModulePath = moduleRequire.resolve(moduleId); - modules.set(resolvedModulePath, electronLog); - } catch { - continue; - } - } - - return [...modules.values()]; -} - export function setupAppLogRouting({ logsPath }: Pops) { - for (const electronLog of getElectronLogModules()) { - electronLog.transports.file.resolvePathFn = (_, message) => { - return resolveAppLogFilePath({ logsPath, message }); - }; + coreElectronLog.transports.file.resolvePathFn = (_, message) => { + return resolveAppLogFilePath({ logsPath, message }); + }; - electronLog.transports.file.resolvePath = electronLog.transports.file.resolvePathFn; - } + coreElectronLog.transports.file.resolvePath = coreElectronLog.transports.file.resolvePathFn; } From 4602556c62713398023c66b80ff21ddd0d90faca Mon Sep 17 00:00:00 2001 From: Esteban Galvis Date: Thu, 28 May 2026 15:53:41 -0500 Subject: [PATCH 2/2] fix: correct eslint directive for import style in log routing setup --- src/apps/main/logging/setup-app-log-routing.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/apps/main/logging/setup-app-log-routing.ts b/src/apps/main/logging/setup-app-log-routing.ts index bd3914ecc..947469450 100644 --- a/src/apps/main/logging/setup-app-log-routing.ts +++ b/src/apps/main/logging/setup-app-log-routing.ts @@ -49,7 +49,7 @@ const ANTIVIRUS_MESSAGE_PATTERNS = [ * instance that bypasses webpack's module registry, so patching it has no * effect on the instance the logger actually uses. */ -// eslint-disable-next-line @typescript-eslint/no-require-imports +// eslint-disable-next-line @typescript-eslint/no-var-requires const coreElectronLog = require('@internxt/drive-desktop-core/node_modules/electron-log') as ElectronLogModule; function isSerializedAntivirusLogEntry({ value }: { value: unknown }) {