Browse Source

Fix circular dependency in logging during initialization

- Add initialization phase detection to logger (2-second delay)
- Prevent database logging during critical startup phase
- Use console logging for critical startup messages to avoid circular dependency
- Add manual initialization control functions (markInitializationComplete, isInitializationPhase)
- Filter initialization-related messages from database logging

Files modified:
- src/utils/logger.ts: Add initialization state tracking and filtering
- src/registerSQLWorker.js: Use console for critical startup message
- src/services/PlatformServiceFactory.ts: Use console for singleton creation message
- src/services/platforms/WebPlatformService.ts: Use console for worker context message

Resolves circular dependency where logging tried to access database during platform service initialization, causing infinite loops with [DB-PREVENTED-INFO] messages.
pull/142/head
Matthew Raymer 3 days ago
parent
commit
f06b6aa367
  1. 4
      src/registerSQLWorker.js
  2. 5
      src/services/PlatformServiceFactory.ts
  3. 4
      src/services/platforms/WebPlatformService.ts
  4. 77
      src/utils/logger.ts

4
src/registerSQLWorker.js

@ -215,4 +215,6 @@ onerror = function (error) {
* Auto-initialize on worker startup (removed to prevent circular dependency) * Auto-initialize on worker startup (removed to prevent circular dependency)
* Initialization now happens on first database operation * Initialization now happens on first database operation
*/ */
logger.log("[SQLWorker] Worker loaded, ready to receive messages"); // Use console for critical startup message to avoid circular dependency
// eslint-disable-next-line no-console
console.log("[SQLWorker] Worker loaded, ready to receive messages");

5
src/services/PlatformServiceFactory.ts

@ -1,7 +1,6 @@
import { PlatformService } from "./PlatformService"; import { PlatformService } from "./PlatformService";
import { WebPlatformService } from "./platforms/WebPlatformService"; import { WebPlatformService } from "./platforms/WebPlatformService";
import { CapacitorPlatformService } from "./platforms/CapacitorPlatformService"; import { CapacitorPlatformService } from "./platforms/CapacitorPlatformService";
import { logger } from "../utils/logger";
/** /**
* Factory class for creating platform-specific service implementations. * Factory class for creating platform-specific service implementations.
@ -42,7 +41,9 @@ export class PlatformServiceFactory {
const platform = process.env.VITE_PLATFORM || "web"; const platform = process.env.VITE_PLATFORM || "web";
if (!PlatformServiceFactory.creationLogged) { if (!PlatformServiceFactory.creationLogged) {
logger.log( // Use console for critical startup message to avoid circular dependency
// eslint-disable-next-line no-console
console.log(
`[PlatformServiceFactory] Creating singleton instance for platform: ${platform}`, `[PlatformServiceFactory] Creating singleton instance for platform: ${platform}`,
); );
PlatformServiceFactory.creationLogged = true; PlatformServiceFactory.creationLogged = true;

4
src/services/platforms/WebPlatformService.ts

@ -97,7 +97,9 @@ export class WebPlatformService implements PlatformService {
} }
} else { } else {
// We're in a worker context - skip initBackend call // We're in a worker context - skip initBackend call
logger.log( // Use console for critical startup message to avoid circular dependency
// eslint-disable-next-line no-console
console.log(
"[WebPlatformService] Skipping initBackend call in worker context", "[WebPlatformService] Skipping initBackend call in worker context",
); );
} }

77
src/utils/logger.ts

@ -23,6 +23,40 @@ export function safeStringify(obj: unknown) {
const isElectron = process.env.VITE_PLATFORM === "electron"; const isElectron = process.env.VITE_PLATFORM === "electron";
const isProduction = process.env.NODE_ENV === "production"; const isProduction = process.env.NODE_ENV === "production";
// Track initialization state to prevent circular dependencies
let isInitializing = true;
// Mark initialization as complete after a delay to allow all services to start
setTimeout(() => {
isInitializing = false;
}, 2000); // 2 second delay to allow all services to initialize
// Function to check if we should skip database logging during initialization
function shouldSkipDatabaseLogging(message: string): boolean {
// Skip during initialization phase
if (isInitializing) {
return true;
}
// Skip specific initialization-related messages even after initialization
const initializationMessages = [
"[PlatformServiceFactory]",
"[SQLWorker]",
"[WebPlatformService]",
"[CapacitorPlatformService]",
"[CapacitorMigration]",
"[DB-Integrity]",
"[Migration]",
"[IndexedDBMigrationService]",
"Creating singleton instance",
"Worker loaded",
"Worker initialized",
"Platform service",
];
return initializationMessages.some((pattern) => message.includes(pattern));
}
export const logger = { export const logger = {
debug: (message: string, ...args: unknown[]) => { debug: (message: string, ...args: unknown[]) => {
// Debug logs are very verbose - only show in development mode for web // Debug logs are very verbose - only show in development mode for web
@ -42,15 +76,8 @@ export const logger = {
console.log(message, ...args); console.log(message, ...args);
} }
// Only log to database for important messages (not routine operations) // Skip database logging during initialization or for initialization-related messages
// Skip database logging for migration messages to avoid circular dependency if (!shouldSkipDatabaseLogging(message)) {
if (
!message.includes("[CapacitorPlatformService]") &&
!message.includes("[CapacitorMigration]") &&
!message.includes("[DB-Integrity]") &&
!message.includes("[Migration]") &&
!message.includes("[IndexedDBMigrationService]")
) {
const argsString = args.length > 0 ? " - " + safeStringify(args) : ""; const argsString = args.length > 0 ? " - " + safeStringify(args) : "";
logToDb(message + argsString); logToDb(message + argsString);
} }
@ -63,6 +90,10 @@ export const logger = {
) { ) {
// eslint-disable-next-line no-console // eslint-disable-next-line no-console
console.info(message, ...args); console.info(message, ...args);
}
// Skip database logging during initialization or for initialization-related messages
if (!shouldSkipDatabaseLogging(message)) {
const argsString = args.length > 0 ? " - " + safeStringify(args) : ""; const argsString = args.length > 0 ? " - " + safeStringify(args) : "";
logToDb(message + argsString); logToDb(message + argsString);
} }
@ -74,26 +105,44 @@ export const logger = {
console.warn(message, ...args); console.warn(message, ...args);
} }
// Log warnings to database, but filter out routine operations // Skip database logging during initialization or for initialization-related messages
if (!message.includes("[CapacitorPlatformService]")) { if (!shouldSkipDatabaseLogging(message)) {
const argsString = args.length > 0 ? " - " + safeStringify(args) : ""; const argsString = args.length > 0 ? " - " + safeStringify(args) : "";
logToDb(message + argsString); logToDb(message + argsString);
} }
}, },
error: (message: string, ...args: unknown[]) => { error: (message: string, ...args: unknown[]) => {
// Errors will always be logged // Errors will always be logged to console
// eslint-disable-next-line no-console // eslint-disable-next-line no-console
console.error(message, ...args); console.error(message, ...args);
// Skip database logging during initialization or for initialization-related messages
if (!shouldSkipDatabaseLogging(message)) {
const messageString = safeStringify(message); const messageString = safeStringify(message);
const argsString = args.length > 0 ? safeStringify(args) : ""; const argsString = args.length > 0 ? safeStringify(args) : "";
logToDb(messageString + argsString); logToDb(messageString + argsString);
}
}, },
}; };
// Function to manually mark initialization as complete
export function markInitializationComplete(): void {
isInitializing = false;
}
// Function to check initialization status
export function isInitializationPhase(): boolean {
return isInitializing;
}
// Add CommonJS export for Electron // Add CommonJS export for Electron
if (typeof module !== "undefined" && module.exports) { if (typeof module !== "undefined" && module.exports) {
module.exports = { logger }; module.exports = {
logger,
markInitializationComplete,
isInitializationPhase,
};
} }
// Add default export for ESM // Add default export for ESM
export default { logger }; export default { logger, markInitializationComplete, isInitializationPhase };

Loading…
Cancel
Save