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
55 changes: 29 additions & 26 deletions frontend/src/App.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@ import Layout from './components/Layout';
import LoadingState from './components/LoadingState';
import { BrowserRouter as Router } from 'react-router-dom';
import { comm } from './utils/websocket';
import { createLogger } from './lib/logger';

const logger = createLogger('App');

const App = () => {
const [components, setComponents] = useState({ rows: [] });
Expand All @@ -17,7 +20,7 @@ const App = () => {

useEffect(() => {
comm.connect();
console.log('[App] Connected to comm');
logger.debug('Connected to comm');
const unsubscribe = comm.subscribe(handleMessage);

return () => {
Expand All @@ -40,7 +43,7 @@ const App = () => {
}, [config]);

const handleMessage = (message) => {
console.log('[App] Received message:', message);
logger.debug('Received message:', message);

switch (message.type) {
case 'components':
Expand Down Expand Up @@ -74,7 +77,7 @@ const App = () => {

case 'initial_state':
// Handle initial state with bulk processing
console.log('[App] Received initial state:', message);
logger.debug('Received initial state:', message);
if (message.states) {
handleBulkStateUpdate(message.states);
}
Expand All @@ -84,15 +87,15 @@ const App = () => {

const handleBulkStateUpdate = (stateUpdates) => {
const startTime = performance.now();

try {
if (!stateUpdates || typeof stateUpdates !== 'object') {
console.warn('[App] Invalid bulk state updates received:', stateUpdates);
logger.warn('Invalid bulk state updates received:', stateUpdates);
return;
}

const updateCount = Object.keys(stateUpdates).length;
console.log(`[App] Processing bulk state update: ${updateCount} components`);
logger.debug(`Processing bulk state update: ${updateCount} components`);
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remaining console.warn not migrated to logger in App

Low Severity

One console.warn('[App] Invalid component found during bulk state update:', component) call was not converted to logger.warn(...) while every other console.* call in App.jsx was migrated. This is inconsistent with the logging migration and will bypass the logger's level filtering in production.

Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit ec6fe10. Configure here.


// Apply bulk state updates to current components
setComponents((prevState) => {
Expand All @@ -119,21 +122,21 @@ const App = () => {
);

const processingTime = performance.now() - startTime;
console.log(`[App] Bulk state update applied: ${updateCount} components in ${processingTime.toFixed(2)}ms`);
logger.debug(`Bulk state update applied: ${updateCount} components in ${processingTime.toFixed(2)}ms`);

return { rows: updatedRows };
});

} catch (error) {
console.error('[App] Error processing bulk state update:', error);
logger.error('Error processing bulk state update:', error);
setError('Error processing bulk state update');
}
};

const refreshComponentsList = async (components) => {
if (!components || !components.rows) {
setAreComponentsLoading(false);
console.warn('[App] Invalid components data received:', components);
logger.warn('Invalid components data received:', components);
setComponents({ rows: [] });
return;
}
Expand Down Expand Up @@ -178,7 +181,7 @@ const App = () => {
const updatedRows = components.rows.map((row) =>
row.map((component) => {
if (!component || !component.id) {
console.warn('[App] Invalid component found during component refresh:', component);
logger.warn('Invalid component found during component refresh:', component);
return component;
}

Expand All @@ -192,7 +195,7 @@ const App = () => {
);

const processingTime = performance.now() - startTime;

// Enhanced performance metrics for production monitoring
const metrics = {
componentCount: componentIds.length,
Expand All @@ -201,22 +204,22 @@ const App = () => {
batchCount: Math.ceil(componentIds.length / batchSize),
timestamp: new Date().toISOString()
};
console.debug(`[App] Enhanced bulk component processing completed: ${componentIds.length} components in ${processingTime.toFixed(2)}ms`, { metrics });

logger.debug(`Enhanced bulk component processing completed: ${componentIds.length} components in ${processingTime.toFixed(2)}ms`, { metrics });

setAreComponentsLoading(false);
setComponents({ rows: updatedRows });
setError(null);
} catch (error) {
console.error('[App] Error processing components:', error);
logger.error('Error processing components:', error);
setAreComponentsLoading(false);
setError('Error processing components data');
setComponents({ rows: [] });
}
};

const handleError = (errorContent) => {
console.error('[App] Received error:', errorContent);
logger.error('Received error:', errorContent);
setAreComponentsLoading(false);
setError(errorContent.message);

Expand All @@ -238,7 +241,7 @@ const App = () => {
};

const handleTransformErrors = (errorContents, components = null) => {
console.error('[App] Received transform errors:', {errorContents, components});
logger.error('Received transform errors:', {errorContents, components});
setAreComponentsLoading(false);
setTransformErrors(errorContents || []);
if (components) {
Expand All @@ -250,7 +253,7 @@ const App = () => {
try {
comm.updateComponentState(componentId, value);
} catch (error) {
console.error('[App] Error updating component state:', error);
logger.error('Error updating component state:', error);
setComponents((prevState) => {
if (!prevState || !prevState.rows) return { rows: [] };

Expand All @@ -267,21 +270,21 @@ const App = () => {

const processBulkComponentUpdates = async (updates) => {
const startTime = performance.now();

try {
if (!updates || typeof updates !== 'object') {
console.warn('[App] Invalid bulk component updates:', updates);
logger.warn('Invalid bulk component updates:', updates);
return;
}

const updateCount = Object.keys(updates).length;
console.log(`[App] Processing bulk component update: ${updateCount} components`);
logger.debug(`Processing bulk component update: ${updateCount} components`);

// Use the communication layer's bulk update capability
const result = await comm.bulkStateUpdate(updates);

const processingTime = performance.now() - startTime;
console.log(`[App] Bulk component update completed in ${processingTime.toFixed(2)}ms:`, {
logger.debug(`Bulk component update completed in ${processingTime.toFixed(2)}ms:`, {
totalProcessed: result.totalProcessed,
successCount: result.successCount,
localChanges: result.localChanges,
Expand All @@ -295,7 +298,7 @@ const App = () => {
const updatedRows = prevState.rows.map((row) =>
row.map((component) => {
if (!component || !component.id) {
console.warn('[App] Invalid component found during bulk component update:', component);
logger.warn('Invalid component found during bulk component update:', component);
return component;
}

Expand All @@ -316,13 +319,13 @@ const App = () => {
});

} catch (error) {
console.error('[App] Error processing bulk component update:', error);
logger.error('Error processing bulk component update:', error);
setError('Error processing bulk component update');
}
};

const updateConnectionStatus = (message) => {
console.log('[App] Updating connection status:', message);
logger.debug('Updating connection status:', message);
setIsConnected(message.connected);
setError(message.connected ? null : 'Lost connection. Attempting to reconnect...');
};
Expand Down
9 changes: 6 additions & 3 deletions frontend/src/backend/service.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
import * as Comlink from 'comlink';
import { createLogger } from '../lib/logger';

const logger = createLogger('Service');

// import PreswaldWorker from './worker.js?worker&inline'; // ← change

Expand All @@ -7,18 +10,18 @@ let workerInstance = null;
export function createWorker() {
// If we're already initialized, return the existing worker
if (workerInstance) {
console.log('[Service] Reusing existing worker instance');
logger.debug('[Service] Reusing existing worker instance');
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Double namespace prefix in service.js log messages

Low Severity

The logger is created with createLogger('Service') and _formatMessage prepends [${this.namespace}] to every message. But the message strings still include the [Service] prefix (e.g., '[Service] Reusing existing worker instance'), resulting in doubled output like [Service] [Service] Reusing existing worker instance.

Additional Locations (2)
Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit ec6fe10. Configure here.

return workerInstance;
}

console.log('[Service] Starting new worker initialization');
logger.debug('[Service] Starting new worker initialization');
try {
const worker = new Worker(new URL('./worker.js', import.meta.url), { type: 'module' });
// const worker = new PreswaldWorker(); // ← no URL needed
workerInstance = Comlink.wrap(worker);
return workerInstance;
} catch (error) {
console.error('[Service] Worker initialization failed:', error);
logger.error('[Service] Worker initialization failed:', error);
workerInstance = null;
throw error;
}
Expand Down
106 changes: 106 additions & 0 deletions frontend/src/lib/logger.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
/**
* Production-ready logging utility with configurable log levels
* Automatically disables debug logs in production builds
*/

const LogLevel = {
DEBUG: 0,
INFO: 1,
WARN: 2,
ERROR: 3,
NONE: 4
};

// Determine log level based on environment
const getDefaultLogLevel = () => {
if (typeof process !== 'undefined' && process.env) {
// Node.js environment
if (process.env.NODE_ENV === 'production') {
return LogLevel.WARN;
}
if (process.env.NODE_ENV === 'test') {
return LogLevel.ERROR;
}
}

// Browser environment - check for debug flag
if (typeof window !== 'undefined') {
const urlParams = new URLSearchParams(window.location.search);
if (urlParams.has('debug')) {
return LogLevel.DEBUG;
}
// Check for production indicators
if (window.location.hostname !== 'localhost' &&
!window.location.hostname.includes('127.0.0.1') &&
!window.location.hostname.includes('dev.')) {
return LogLevel.WARN;
}
}

return LogLevel.DEBUG;
};

class Logger {
constructor(namespace = 'App', level = null) {
this.namespace = namespace;
this.level = level !== null ? level : getDefaultLogLevel();
}

_shouldLog(level) {
return level >= this.level;
}

_formatMessage(level, message) {
return `[${this.namespace}] ${message}`;
}

debug(message, ...args) {
if (this._shouldLog(LogLevel.DEBUG)) {
console.debug(this._formatMessage('DEBUG', message), ...args);
}
}

info(message, ...args) {
if (this._shouldLog(LogLevel.INFO)) {
console.info(this._formatMessage('INFO', message), ...args);
}
}

warn(message, ...args) {
if (this._shouldLog(LogLevel.WARN)) {
console.warn(this._formatMessage('WARN', message), ...args);
}
}

error(message, ...args) {
if (this._shouldLog(LogLevel.ERROR)) {
console.error(this._formatMessage('ERROR', message), ...args);
}
}

// Set log level dynamically
setLevel(level) {
this.level = level;
}
}

// Create default logger instance
const defaultLogger = new Logger('App');

// Factory function for creating namespaced loggers
export const createLogger = (namespace) => {
return new Logger(namespace);
};

// Export default logger methods
export const logger = {
debug: (...args) => defaultLogger.debug(...args),
info: (...args) => defaultLogger.info(...args),
warn: (...args) => defaultLogger.warn(...args),
error: (...args) => defaultLogger.error(...args),
setLevel: (level) => defaultLogger.setLevel(level),
LogLevel
};

export { LogLevel, Logger };
export default logger;
Loading