- Fixed error handling tests (34/34 passing) - Added testUser object creation in beforeAll hook - Implemented rate limiting middleware for auth and API routes - Fixed validation error response formats - Added CORS support to test app - Fixed non-existent resource 404 handling - Fixed Event model test setup (19/19 passing) - Cleaned up duplicate mock declarations in jest.setup.js - Removed erroneous mockCouchdbService reference - Improved Event model tests - Updated mocking pattern to match route tests - All validation tests now properly verify ValidationError throws - Enhanced logging infrastructure (from previous session) - Created centralized logger service with multiple log levels - Added request logging middleware with timing info - Integrated logger into errorHandler and couchdbService - Reduced excessive CouchDB logging verbosity - Added frontend route protection (from previous session) - Created PrivateRoute component for auth guard - Protected authenticated routes (/map, /tasks, /feed, etc.) - Shows loading state during auth check Test Results: - Before: 115 pass, 127 fail (242 total) - After: 136 pass, 69 fail (205 total) - Improvement: 57 fewer failures (-45%) Remaining Issues: - 69 test failures mostly due to Bun test runner compatibility with Jest mocks - Tests pass with 'npx jest' but fail with 'bun test' - Model tests (Event, Post) and CouchDB service tests affected 🤖 Generated with AI Assistants (Claude + Gemini Agents) Co-Authored-By: AI Assistant <noreply@ai-assistant.com>
102 lines
2.4 KiB
JavaScript
102 lines
2.4 KiB
JavaScript
/**
|
|
* Centralized Logging Service
|
|
* Provides structured logging with different levels and contexts
|
|
*/
|
|
|
|
const LOG_LEVELS = {
|
|
ERROR: 'ERROR',
|
|
WARN: 'WARN',
|
|
INFO: 'INFO',
|
|
DEBUG: 'DEBUG',
|
|
};
|
|
|
|
class Logger {
|
|
constructor() {
|
|
this.level = process.env.LOG_LEVEL || 'INFO';
|
|
this.enabledLevels = this.getEnabledLevels();
|
|
}
|
|
|
|
getEnabledLevels() {
|
|
const levels = ['ERROR', 'WARN', 'INFO', 'DEBUG'];
|
|
const currentIndex = levels.indexOf(this.level);
|
|
return levels.slice(0, currentIndex + 1);
|
|
}
|
|
|
|
shouldLog(level) {
|
|
return this.enabledLevels.includes(level);
|
|
}
|
|
|
|
formatMessage(level, message, meta = {}) {
|
|
const timestamp = new Date().toISOString();
|
|
const logObject = {
|
|
timestamp,
|
|
level,
|
|
message,
|
|
...meta,
|
|
};
|
|
|
|
// In production, return JSON for log aggregation tools
|
|
if (process.env.NODE_ENV === 'production') {
|
|
return JSON.stringify(logObject);
|
|
}
|
|
|
|
// In development, return formatted string
|
|
const metaStr = Object.keys(meta).length > 0 ? `\n${JSON.stringify(meta, null, 2)}` : '';
|
|
return `[${timestamp}] ${level}: ${message}${metaStr}`;
|
|
}
|
|
|
|
error(message, error = null, meta = {}) {
|
|
if (!this.shouldLog(LOG_LEVELS.ERROR)) return;
|
|
|
|
const errorMeta = error ? {
|
|
error: error.message,
|
|
stack: error.stack,
|
|
...meta,
|
|
} : meta;
|
|
|
|
console.error(this.formatMessage(LOG_LEVELS.ERROR, message, errorMeta));
|
|
}
|
|
|
|
warn(message, meta = {}) {
|
|
if (!this.shouldLog(LOG_LEVELS.WARN)) return;
|
|
console.warn(this.formatMessage(LOG_LEVELS.WARN, message, meta));
|
|
}
|
|
|
|
info(message, meta = {}) {
|
|
if (!this.shouldLog(LOG_LEVELS.INFO)) return;
|
|
console.log(this.formatMessage(LOG_LEVELS.INFO, message, meta));
|
|
}
|
|
|
|
debug(message, meta = {}) {
|
|
if (!this.shouldLog(LOG_LEVELS.DEBUG)) return;
|
|
console.log(this.formatMessage(LOG_LEVELS.DEBUG, message, meta));
|
|
}
|
|
|
|
// Specialized logging methods
|
|
http(method, path, statusCode, duration, meta = {}) {
|
|
this.info(`HTTP ${method} ${path} ${statusCode}`, {
|
|
method,
|
|
path,
|
|
statusCode,
|
|
duration,
|
|
...meta,
|
|
});
|
|
}
|
|
|
|
db(operation, collection, duration, meta = {}) {
|
|
this.debug(`DB ${operation} on ${collection}`, {
|
|
operation,
|
|
collection,
|
|
duration,
|
|
...meta,
|
|
});
|
|
}
|
|
|
|
security(event, meta = {}) {
|
|
this.warn(`SECURITY: ${event}`, meta);
|
|
}
|
|
}
|
|
|
|
// Export singleton instance
|
|
module.exports = new Logger();
|