backend v4 half
This commit is contained in:
@@ -0,0 +1,183 @@
|
||||
import { createLogger, format, transports } from 'winston';
|
||||
import { DATABASE_LOG_CONFIG, PERFORMANCE_THRESHOLDS, LOG_FILTERS, getEnvironmentConfig } from './LoggingConfig';
|
||||
|
||||
// Database operation logger
|
||||
export const dbLogger = createLogger(DATABASE_LOG_CONFIG);
|
||||
|
||||
// Apply environment-specific configuration
|
||||
const envConfig = getEnvironmentConfig();
|
||||
dbLogger.level = envConfig.level;
|
||||
|
||||
// Performance monitoring
|
||||
export class PerformanceMonitor {
|
||||
private static timers: Map<string, number> = new Map();
|
||||
|
||||
static startTimer(operationId: string): void {
|
||||
this.timers.set(operationId, Date.now());
|
||||
}
|
||||
|
||||
static endTimer(operationId: string, operation: string, entityName: string): number {
|
||||
const startTime = this.timers.get(operationId);
|
||||
if (!startTime) {
|
||||
dbLogger.warn('Timer not found for operation', { operationId, operation, entityName });
|
||||
return 0;
|
||||
}
|
||||
|
||||
const duration = Date.now() - startTime;
|
||||
this.timers.delete(operationId);
|
||||
|
||||
// Log based on performance thresholds
|
||||
if (duration > PERFORMANCE_THRESHOLDS.VERY_SLOW_OPERATION) {
|
||||
dbLogger.error('Very slow database operation detected', {
|
||||
operation,
|
||||
entityName,
|
||||
duration,
|
||||
operationId,
|
||||
threshold: PERFORMANCE_THRESHOLDS.VERY_SLOW_OPERATION,
|
||||
severity: 'critical'
|
||||
});
|
||||
} else if (duration > PERFORMANCE_THRESHOLDS.SLOW_OPERATION) {
|
||||
dbLogger.warn('Slow database operation detected', {
|
||||
operation,
|
||||
entityName,
|
||||
duration,
|
||||
operationId,
|
||||
threshold: PERFORMANCE_THRESHOLDS.SLOW_OPERATION,
|
||||
severity: 'warning'
|
||||
});
|
||||
} else {
|
||||
dbLogger.debug('Database operation completed', {
|
||||
operation,
|
||||
entityName,
|
||||
duration,
|
||||
operationId
|
||||
});
|
||||
}
|
||||
|
||||
return duration;
|
||||
}
|
||||
|
||||
static generateOperationId(): string {
|
||||
return `${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
|
||||
}
|
||||
}
|
||||
|
||||
// Database operation types for logging
|
||||
export enum DBOperation {
|
||||
CREATE = 'CREATE',
|
||||
READ = 'READ',
|
||||
UPDATE = 'UPDATE',
|
||||
DELETE = 'DELETE',
|
||||
SOFT_DELETE = 'SOFT_DELETE',
|
||||
BULK_CREATE = 'BULK_CREATE',
|
||||
BULK_UPDATE = 'BULK_UPDATE',
|
||||
BULK_DELETE = 'BULK_DELETE',
|
||||
FIND = 'FIND',
|
||||
SEARCH = 'SEARCH',
|
||||
COUNT = 'COUNT',
|
||||
AGGREGATE = 'AGGREGATE',
|
||||
TRANSACTION = 'TRANSACTION'
|
||||
}
|
||||
|
||||
// Logging decorators
|
||||
export function LogDBOperation(operation: DBOperation, entityName: string) {
|
||||
return function (target: any, propertyName: string, descriptor: PropertyDescriptor) {
|
||||
const method = descriptor.value;
|
||||
|
||||
descriptor.value = async function (...args: any[]) {
|
||||
const operationId = PerformanceMonitor.generateOperationId();
|
||||
const startTime = Date.now();
|
||||
|
||||
PerformanceMonitor.startTimer(operationId);
|
||||
|
||||
dbLogger.info('Database operation started', {
|
||||
operation,
|
||||
entityName,
|
||||
method: propertyName,
|
||||
operationId,
|
||||
args: args.length > 0 ? 'provided' : 'none'
|
||||
});
|
||||
|
||||
try {
|
||||
const result = await method.apply(this, args);
|
||||
|
||||
const duration = PerformanceMonitor.endTimer(operationId, operation, entityName);
|
||||
|
||||
dbLogger.info('Database operation successful', {
|
||||
operation,
|
||||
entityName,
|
||||
method: propertyName,
|
||||
operationId,
|
||||
duration,
|
||||
resultCount: Array.isArray(result) ? result.length : result ? 1 : 0
|
||||
});
|
||||
|
||||
return result;
|
||||
} catch (error) {
|
||||
const duration = Date.now() - startTime;
|
||||
|
||||
dbLogger.error('Database operation failed', {
|
||||
operation,
|
||||
entityName,
|
||||
method: propertyName,
|
||||
operationId,
|
||||
duration,
|
||||
error: error instanceof Error ? error.message : String(error),
|
||||
stack: error instanceof Error ? error.stack : undefined
|
||||
});
|
||||
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
// Connection logging
|
||||
export function logDatabaseConnection(status: 'connecting' | 'connected' | 'disconnected' | 'error', details?: any) {
|
||||
const logData = {
|
||||
event: 'database_connection',
|
||||
status,
|
||||
timestamp: new Date().toISOString(),
|
||||
...details
|
||||
};
|
||||
|
||||
if (status === 'error') {
|
||||
dbLogger.error('Database connection error', logData);
|
||||
} else {
|
||||
dbLogger.info('Database connection status', logData);
|
||||
}
|
||||
}
|
||||
|
||||
// Query logging
|
||||
export function logQuery(query: string, parameters?: any[], duration?: number) {
|
||||
const envConfig = getEnvironmentConfig();
|
||||
|
||||
if (!envConfig.logQueries) return;
|
||||
|
||||
const sanitizedQuery = LOG_FILTERS.sanitizeQuery(query);
|
||||
const sanitizedParams = parameters ? LOG_FILTERS.sanitizeParameters(parameters) : [];
|
||||
|
||||
const logData = {
|
||||
event: 'database_query',
|
||||
query: sanitizedQuery,
|
||||
parameters: sanitizedParams,
|
||||
duration: duration || 0,
|
||||
timestamp: new Date().toISOString()
|
||||
};
|
||||
|
||||
if (duration && duration > PERFORMANCE_THRESHOLDS.VERY_SLOW_QUERY) {
|
||||
dbLogger.error('Very slow query detected', {
|
||||
...logData,
|
||||
severity: 'critical',
|
||||
threshold: PERFORMANCE_THRESHOLDS.VERY_SLOW_QUERY
|
||||
});
|
||||
} else if (duration && duration > PERFORMANCE_THRESHOLDS.SLOW_QUERY) {
|
||||
dbLogger.warn('Slow query detected', {
|
||||
...logData,
|
||||
severity: 'warning',
|
||||
threshold: PERFORMANCE_THRESHOLDS.SLOW_QUERY
|
||||
});
|
||||
} else {
|
||||
dbLogger.debug('Database query executed', logData);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user