Centralized logging system for QwickApps with development debugging and production optimization
npm install @qwickapps/logging- Critical Production Fix: Moved pino dependency from devDependencies to dependencies, fixing production deployment failures
- Improved Reliability: Ensures Pino logger is available in all deployment environments
- Zero Breaking Changes: Drop-in replacement for v1.0.2
See CHANGELOG.md for full details.
The QwickApps React Framework includes a sophisticated logging system designed for development debugging while ensuring zero performance impact and complete removal in production builds. The system provides namespaced loggers, multiple log levels, and flexible build configurations.
- Runtime Environment Detection: Checks NODE_ENV at runtime, allowing consumers to control logging behavior
- Namespaced Loggers: Pre-configured loggers for different components
- Multiple Log Levels: debug, info, warn, error with appropriate console methods
- Complete Production Stripping: Optional build flag to completely remove all logging code
- Zero Performance Impact: Early returns and build-time stripping prevent any overhead
- TypeScript Support: Full type definitions included
``typescript
import { commonLoggers, createLogger } from '@qwickapps/logging';
// Use common pre-configured loggers
const logger = commonLoggers.app;
// Log at different levels
logger.debug('Navigation changed to:', path);
logger.info('Component initialized');
logger.warn('Deprecated prop used:', propName);
logger.error('Failed to load:', error);
`
- commonLoggers.app - For general application loggingcommonLoggers.api
- - For API-related loggingcommonLoggers.auth
- - For authentication loggingcommonLoggers.data
- - For data management loggingcommonLoggers.ui
- - For UI component loggingcommonLoggers.perf
- - For performance loggingcommonLoggers.error
- - For error loggingcommonLoggers.debug
- - For debug-specific logging
`typescript
import { createLogger } from '@qwickapps/logging';
// Create a logger with custom namespace
const myLogger = createLogger('MyComponent');
myLogger.debug('Component mounted');
myLogger.info('Data loaded:', data);
`
Create sub-namespaced loggers for better organization:
`typescript
const logger = createLogger('MyApp');
const authLogger = logger.child('Auth');
const apiLogger = logger.child('API');
authLogger.debug('Login attempt'); // [MyApp:Auth] Login attempt
apiLogger.info('Request sent'); // [MyApp:API] Request sent
`
`typescript`
logger.time('DataFetch');
// ... perform operation
logger.timeEnd('DataFetch'); // [Namespace] DataFetch: 123.45ms
`typescript`
logger.group('User Actions');
logger.debug('Click event:', event);
logger.debug('State updated:', newState);
logger.groupEnd();
For simple logging without creating logger instances:
`typescript
import { devLog, devWarn, devError } from '@qwickapps/logging';
devLog('MyComponent', 'Render triggered', props);
devWarn('MyComponent', 'Using deprecated API');
devError('MyComponent', 'Validation failed', errors);
`
For development builds with full logging:
`bash`In your application's package.json
"scripts": {
"build:dev": "NODE_ENV=development webpack build",
"deploy:dev": "npm run build:dev && npm run deploy"
}
For production builds with runtime logging control (logs disabled but code present):
`bash`Standard production build
"scripts": {
"build": "NODE_ENV=production webpack build",
"deploy": "npm run build && npm run deploy"
}
For maximum optimization, completely remove all logging code:
`bashIn your application's webpack.config.js or vite.config.js
import replace from '@rollup/plugin-replace';
export default {
plugins: [
replace({
preventAssignment: true,
'process.env.NODE_ENV': JSON.stringify('production'),
// Add these to completely strip logging
delimiters: ['', ''],
values: {
'logger.': 'null && ',
'devLog(': '(() => {})(',
'devWarn(': '(() => {})(',
'devError(': '(() => {})(',
}
})
]
}
`
The main entry point (@qwickapps/logging) is browser-compatible and automatically falls back to console-based logging when pino is not available.
`typescript
// Works in both browser and Node.js
import { getLogger, Logger } from '@qwickapps/logging';
const logger = getLogger('MyComponent');
logger.info('Hello from browser or Node.js!');
`
The StartupLogger class is available via a separate entry point since it uses Node.js-specific modules (fs, path):
`typescript
// Node.js only - DO NOT import in browser code
import { StartupLogger, getStartupLogger } from '@qwickapps/logging/startup';
const startup = getStartupLogger();
startup.startPhase('INIT');
startup.log('info', 'Application starting...');
`
Important: Never import from @qwickapps/logging/startup in browser/PWA code - it will cause build failures.
| Entry Point | Environment | Description |
|-------------|-------------|-------------|
| @qwickapps/logging | Browser + Node.js | Main logger (getLogger, Logger, commonLoggers) |@qwickapps/logging/startup
| | Node.js only | StartupLogger for file-based startup logging |
`javascript
// vite.config.js
import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react';
export default defineConfig(({ mode }) => ({
plugins: [react()],
define: {
'process.env.NODE_ENV': JSON.stringify(mode),
},
build: {
// For production builds, minification will help remove dead code
minify: mode === 'production' ? 'terser' : false,
terserOptions: {
compress: {
drop_console: mode === 'production',
drop_debugger: mode === 'production',
},
},
},
}));
`
`javascript
// In your app code, the logger will automatically detect CRA's NODE_ENV
import { loggers } from '@qwickapps/react-framework';
const logger = loggers.navigation;
// Logs appear in development, silent in production
logger.debug('Route changed');
`
`javascript`
// next.config.js
module.exports = {
env: {
NODE_ENV: process.env.NODE_ENV,
},
webpack: (config, { dev }) => {
if (!dev) {
// Production optimizations
config.optimization.minimize = true;
}
return config;
},
};
1. Development Mode: Full logging with minimal overhead
2. Production Mode (Runtime Check): Logger checks disabled state and returns immediately
3. Production Mode (Stripped): No logging code present in bundle at all
- With Logging Code: ~2KB gzipped (but inactive in production)
- With Complete Stripping: 0KB - all logging code removed
`typescript
// ✅ Good
logger.debug('Detailed state:', state); // Development details
logger.info('User logged in'); // Important events
logger.warn('API deprecated'); // Warnings
logger.error('Failed to save:', error); // Errors
// ❌ Avoid
console.log('Debug:', data); // Use logger instead
if (process.env.NODE_ENV === 'development') { // Logger handles this
console.log(data);
}
`
`typescript
// ✅ Good - Clear component identification
const logger = loggers.auth;
logger.debug('Login attempt');
// ❌ Avoid - No context
console.log('Login attempt');
`
`typescript
// ✅ Good - Structured logging
logger.debug('Navigation event', {
from: currentPath,
to: newPath,
timestamp: Date.now(),
user: userId
});
// ❌ Avoid - Unstructured
logger.debug(Nav: ${currentPath} -> ${newPath} at ${Date.now()});`
`typescript
// ✅ Good - Sanitized data
logger.debug('User data', {
id: user.id,
email: user.email.replace(/(.{2}).(@.)/, '$1*$2')
});
// ❌ Never log sensitive data
logger.debug('User data', {
password: user.password, // Never!
creditCard: user.cc // Never!
});
`
`typescript
// Before
if (process.env.NODE_ENV === 'development') {
console.log('Scaffold: Current path changed to:', currentPath);
}
// After
import { loggers } from '@qwickapps/react-framework';
const logger = loggers.scaffold;
logger.debug('Current path changed to:', currentPath);
`
`typescript
// Before
const DEBUG = process.env.REACT_APP_DEBUG === 'true';
if (DEBUG) {
console.log('Debug info:', data);
}
// After
import { createLogger } from '@qwickapps/react-framework';
const logger = createLogger('MyApp');
logger.debug('Debug info:', data);
`
1. Check NODE_ENV is set to 'development'
2. Verify logger is imported correctly
3. Check browser console filters
1. Ensure NODE_ENV is set to 'production' during build
2. Consider using complete log stripping for production builds
3. Check for any console.log statements not using the logger
`typescript
// Ensure proper imports
import { loggers, createLogger, Logger } from '@qwickapps/react-framework';
// Type logger instances
const logger: Logger = createLogger('MyComponent');
`
Creates a new logger instance with optional namespace.
- debug(message: string, ...args: any[]): void - Debug level logginginfo(message: string, ...args: any[]): void
- - Info level loggingwarn(message: string, ...args: any[]): void
- - Warning level loggingerror(message: string, ...args: any[]): void
- - Error level logginggroup(label: string): void
- - Start a console groupgroupEnd(): void
- - End a console grouptime(label: string): void
- - Start a timertimeEnd(label: string): void
- - End a timer and log durationchild(subNamespace: string): Logger
- - Create a child logger
- devLog(namespace: string, message: string, ...args: any[]): voiddevWarn(namespace: string, message: string, ...args: any[]): void
- devError(namespace: string, message: string, ...args: any[]): void`
-
When adding new components or features to QwickApps React Framework:
1. Create or use appropriate namespaced logger
2. Use consistent log levels
3. Include relevant context in log messages
4. Test with both development and production builds
5. Document any new logger namespaces
This software is licensed under the PolyForm Shield License 1.0.0.
✅ Permitted Uses:
- Internal business applications
- Learning and educational projects
- Non-competitive commercial applications
- Academic research and teaching
- Building applications that use this logging library
❌ Prohibited Uses:
- Creating competing logging frameworks
- Building competing developer tools
- Reselling or redistributing as a competing product
- Reverse engineering to create competitive products
For full license terms, see PolyForm Shield 1.0.0.
For commercial licensing options, contact legal@qwickapps.com.
---
Copyright (c) 2025 QwickApps. All rights reserved.