Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ export async function trySetupAntivirusIpcAndInitialize() {
try {
logger.debug({ tag: 'ANTIVIRUS', msg: '[Main] Setting up antivirus IPC handlers' });
setupAntivirusIpc();
logger.debug({ msg: '[Main] Antivirus IPC handlers setup complete' });
logger.debug({ tag: 'ANTIVIRUS', msg: '[Main] Antivirus IPC handlers setup complete' });
await getAntivirusManager().initialize();
} catch (error) {
logger.error({ tag: 'ANTIVIRUS', msg: '[Main] Error setting up antivirus:', error });
Expand Down
76 changes: 76 additions & 0 deletions src/apps/main/logging/setup-app-log-routing.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
import { resolveAppLogFilePath } from './setup-app-log-routing';

type Pops = {
header: string;
msg: string;
};

function createSerializedLogMessage({ header, msg }: Pops) {
return `{ header: '${header}', msg: '${msg}' }`;
}

describe('setup-app-log-routing', () => {
const logsPath = '/tmp/internxt-logs';

describe('resolveAppLogFilePath', () => {
it('should route antivirus debug logs to the dedicated antivirus file', () => {
// When
const result = resolveAppLogFilePath({
logsPath,
message: {
level: 'debug',
data: [createSerializedLogMessage({ header: ' - b - anti', msg: '[CLAM_AVD] Starting clamd server...' })],
},
});

// Then
expect(result).toBe('/tmp/internxt-logs/drive-antivirus.log');
});

it('should keep important logs in the important file even for antivirus entries', () => {
// When
const result = resolveAppLogFilePath({
logsPath,
message: {
level: 'info',
data: [
createSerializedLogMessage({ header: 'E - b - anti', msg: '[CLAM_AVD] clamd process unexpectedly 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({
logsPath,
message: {
level: 'debug',
data: [createSerializedLogMessage({ header: ' - b - auth', msg: 'Starting app' })],
},
});

// Then
expect(result).toBe('/tmp/internxt-logs/drive.log');
});

it('should route antivirus messages even when the serialized header is missing the antivirus tag', () => {
// When
const result = resolveAppLogFilePath({
logsPath,
message: {
level: 'debug',
data: [
createSerializedLogMessage({ header: ' - b - ', msg: '[Main] Antivirus IPC handlers setup complete' }),
],
},
});

// Then
expect(result).toBe('/tmp/internxt-logs/drive-antivirus.log');
});
});
});
84 changes: 84 additions & 0 deletions src/apps/main/logging/setup-app-log-routing.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
import { createRequire } from 'node:module';
import { join } from 'node:path';

type Pops = {
logsPath: string;
};

type LogMessage = {
data?: unknown[];
level?: string;
};

type ElectronLogModule = {
transports: {
file: {
resolvePathFn: (variables: unknown, message?: LogMessage) => string;
resolvePath?: (variables: unknown, message?: LogMessage) => string;
};
};
};

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_MESSAGE_PATTERNS = [
/\[CLAM_AVD\]/,
/\[freshclam/i,
/\[ANTIVIRUS_MANAGER\]/,
/window\.electron\.antivirus/i,
/\bantivirus\b/i,
];
const ELECTRON_LOG_MODULE_IDS = ['electron-log', '@internxt/drive-desktop-core/node_modules/electron-log'];
const moduleRequire = createRequire(__filename);

export function setupAppLogRouting({ logsPath }: Pops) {
for (const electronLog of getElectronLogModules()) {
electronLog.transports.file.resolvePathFn = (_, message) => {
return resolveAppLogFilePath({ logsPath, message });
};

electronLog.transports.file.resolvePath = electronLog.transports.file.resolvePathFn;
}
}

export function resolveAppLogFilePath({ logsPath, message }: Pops & { message?: LogMessage }) {
if (message?.level === 'info') {
return join(logsPath, IMPORTANT_LOG_FILE_NAME);
}

if (isAntivirusLogMessage({ message })) {
return join(logsPath, ANTIVIRUS_LOG_FILE_NAME);
}

return join(logsPath, DEFAULT_LOG_FILE_NAME);
}

function isAntivirusLogMessage({ message }: { message?: LogMessage }) {
return message?.data?.some((value) => isSerializedAntivirusLogEntry({ value })) ?? false;
}

function isSerializedAntivirusLogEntry({ value }: { value: unknown }) {
if (typeof value !== 'string') {
return false;
}

return ANTIVIRUS_HEADER_PATTERN.test(value) || ANTIVIRUS_MESSAGE_PATTERNS.some((pattern) => pattern.test(value));
}

function getElectronLogModules() {
const modules = new Map<string, ElectronLogModule>();

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()];
}
6 changes: 3 additions & 3 deletions src/apps/main/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,10 @@ import 'dotenv/config';
// ***** APP BOOTSTRAPPING ****************************************************** //
import { PATHS } from '../../core/electron/paths';
import { setupElectronLog } from '@internxt/drive-desktop-core/build/backend';
import { setupAppLogRouting } from './logging/setup-app-log-routing';

setupElectronLog({
logsPath: PATHS.LOGS,
});
setupElectronLog({ logsPath: PATHS.LOGS });
setupAppLogRouting({ logsPath: PATHS.LOGS });

import './virtual-root-folder/handlers';
import './auto-launch/handlers';
Expand Down
1 change: 0 additions & 1 deletion src/types/NodeClamError.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ declare module '@internxt/scan/lib/NodeClamError' {
constructor(message: string);
data?: {
err?: Error;
[key: string]: any;
};
}
}
Loading