UNPKG

@ufdevsllc/authme2.0

Version:

SDK for license management and remote monitoring with automatic system tracking, license validation, and remote control capabilities

353 lines (307 loc) 12.3 kB
import DatabaseManager from './database-manager.js'; class DataLogger { constructor(errorHandler = null) { this.errorHandler = errorHandler; this.databaseManager = new DatabaseManager(this.errorHandler); this.isInitialized = false; } /** * Initialize the data logger with database connection * @returns {Promise<void>} */ async init() { if (this.isInitialized) { return; } const context = { component: 'data-logger', operation: 'initialization' }; try { if (this.errorHandler) { await this.errorHandler.initialize(); } await this.databaseManager.initMonitoringConnection(); this.isInitialized = true; if (this.errorHandler) { await this.errorHandler.logInfo('Data logger initialized successfully', context); } else { console.log('Data logger initialized successfully'); } } catch (error) { if (this.errorHandler) { await this.errorHandler.handleError(error, context); } else { console.error('Failed to initialize DataLogger:', error.message); } throw new Error(`DataLogger initialization failed: ${error.message}`); } } /** * Validate input parameters for logging operations * @param {string} collectionName - Name of the collection * @param {*} data - Data to validate * @param {string} operation - Operation type * @throws {Error} If validation fails */ _validateInput(collectionName, data, operation) { // Validate collection name if (this.errorHandler) { const collectionValidation = this.errorHandler.validateInput(collectionName, { type: 'string', required: true, minLength: 1, maxLength: 100, pattern: /^[a-zA-Z0-9_-]+$/ }, { field: 'collectionName' }); if (!collectionValidation.isValid) { throw new Error(`Invalid collection name: ${collectionValidation.errors.join(', ')}`); } // Validate operation if (operation) { const operationValidation = this.errorHandler.validateInput(operation, { type: 'string', required: false, maxLength: 50 }, { field: 'operation' }); if (!operationValidation.isValid) { throw new Error(`Invalid operation: ${operationValidation.errors.join(', ')}`); } } } else { // Basic validation without error handler if (!collectionName || typeof collectionName !== 'string') { throw new Error('Collection name must be a non-empty string'); } if (operation && typeof operation !== 'string') { throw new Error('Operation must be a string'); } } // Validate data if (data === null || data === undefined) { throw new Error('Data cannot be null or undefined'); } } /** * Ensure the logger is initialized before operations * @throws {Error} If not initialized */ _ensureInitialized() { if (!this.isInitialized) { throw new Error('DataLogger not initialized. Call init() first.'); } if (!this.databaseManager.isMonitoringConnected()) { throw new Error('Monitoring database not connected'); } } /** * Log general data operations to monitoring database * @param {string} collectionName - Name of the collection to log to * @param {Object} data - Data to log * @param {string} operation - Type of operation (create, update, delete, read) * @returns {Promise<Object>} Result of the logging operation */ async logData(collectionName, data, operation = 'unknown') { this._validateInput(collectionName, data, operation); this._ensureInitialized(); const context = { component: 'data-logger', operation: 'log-data', collection: collectionName, dataOperation: operation }; try { const logEntry = { collectionName, operation, data: typeof data === 'object' ? JSON.parse(JSON.stringify(data)) : data, timestamp: new Date(), logType: 'general_data' }; let result; if (this.errorHandler) { result = await this.errorHandler.executeWithRetry( async () => { return await this.databaseManager.saveUserData('usage_logs', logEntry); }, context, { maxRetries: 3 } ); await this.errorHandler.logInfo(`Data logged successfully to collection: ${collectionName}`, context); } else { result = await this.databaseManager.saveUserData('usage_logs', logEntry); console.log(`Data logged successfully to collection: ${collectionName}`); } return result; } catch (error) { if (this.errorHandler) { await this.errorHandler.handleError(error, context); } else { console.error('Error logging data:', error.message); } throw new Error(`Failed to log data: ${error.message}`); } } /** * Log user activity and actions * @param {string} userId - User identifier * @param {string} action - Action performed by user * @param {Object} details - Additional details about the action * @returns {Promise<Object>} Result of the logging operation */ async logUserActivity(userId, action, details = {}) { if (!userId || typeof userId !== 'string') { throw new Error('User ID must be a non-empty string'); } if (!action || typeof action !== 'string') { throw new Error('Action must be a non-empty string'); } this._ensureInitialized(); try { const logEntry = { userId, action, details: typeof details === 'object' ? JSON.parse(JSON.stringify(details)) : details, timestamp: new Date(), logType: 'user_activity' }; const result = await this.databaseManager.saveUserData('usage_logs', logEntry); return result; } catch (error) { console.error('Error logging user activity:', error.message); throw new Error(`Failed to log user activity: ${error.message}`); } } /** * Log model-specific operations * @param {string} modelName - Name of the model * @param {string} operation - Operation performed (save, update, delete, find) * @param {Object} data - Data involved in the operation * @returns {Promise<Object>} Result of the logging operation */ async logModelOperation(modelName, operation, data) { if (!modelName || typeof modelName !== 'string') { throw new Error('Model name must be a non-empty string'); } this._validateInput('model_operations', data, operation); this._ensureInitialized(); try { const logEntry = { modelName, operation, data: typeof data === 'object' ? JSON.parse(JSON.stringify(data)) : data, timestamp: new Date(), logType: 'model_operation' }; const result = await this.databaseManager.saveUserData('usage_logs', logEntry); return result; } catch (error) { console.error('Error logging model operation:', error.message); throw new Error(`Failed to log model operation: ${error.message}`); } } /** * Log multiple operations in batch * @param {Array} operations - Array of operation objects * @returns {Promise<Array>} Results of all logging operations */ async bulkLog(operations) { if (!Array.isArray(operations)) { throw new Error('Operations must be an array'); } if (operations.length === 0) { throw new Error('Operations array cannot be empty'); } this._ensureInitialized(); const results = []; const errors = []; for (let i = 0; i < operations.length; i++) { const op = operations[i]; try { // Validate operation structure if (!op || typeof op !== 'object') { throw new Error(`Operation at index ${i} must be an object`); } const { type, ...params } = op; if (!type || typeof type !== 'string') { throw new Error(`Operation at index ${i} must have a valid type`); } let result; switch (type) { case 'logData': const { collectionName, data, operation } = params; result = await this.logData(collectionName, data, operation); break; case 'logUserActivity': const { userId, action, details } = params; result = await this.logUserActivity(userId, action, details); break; case 'logModelOperation': const { modelName, operation: modelOp, data: modelData } = params; result = await this.logModelOperation(modelName, modelOp, modelData); break; default: throw new Error(`Unknown operation type: ${type}`); } results.push({ index: i, success: true, result }); } catch (error) { const errorInfo = { index: i, success: false, error: error.message, operation: op }; errors.push(errorInfo); results.push(errorInfo); } } // If there were errors, log them but don't throw unless all operations failed if (errors.length > 0) { console.warn(`${errors.length} out of ${operations.length} bulk operations failed:`, errors); // If all operations failed, throw an error if (errors.length === operations.length) { throw new Error(`All bulk operations failed. First error: ${errors[0].error}`); } } return results; } /** * Check if the data logger is properly initialized and connected * @returns {boolean} True if initialized and connected */ isReady() { return this.isInitialized && this.databaseManager.isMonitoringConnected(); } /** * Close the data logger and database connections * @returns {Promise<void>} */ async close() { const context = { component: 'data-logger', operation: 'close' }; try { if (this.databaseManager) { await this.databaseManager.closeConnection(); } this.isInitialized = false; if (this.errorHandler) { await this.errorHandler.logInfo('Data logger closed successfully', context); } else { console.log('Data logger closed successfully'); } } catch (error) { if (this.errorHandler) { await this.errorHandler.handleError(error, context); } else { console.error('Error closing data logger:', error); } } finally { if (this.errorHandler) { await this.errorHandler.cleanup(); } } } } export default DataLogger;