Steps 1-11, still need to do 12
This commit is contained in:
@@ -83,32 +83,60 @@ class Logger {
|
||||
/**
|
||||
* Logs operation start with configuration details (Requirement 3.1)
|
||||
* @param {Object} config - Configuration object
|
||||
* @param {Object} schedulingContext - Optional scheduling context
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
async logOperationStart(config) {
|
||||
await this.info(`Starting price update operation with configuration:`);
|
||||
async logOperationStart(config, schedulingContext = null) {
|
||||
if (schedulingContext && schedulingContext.isScheduled) {
|
||||
await this.info(
|
||||
`Starting scheduled price update operation with configuration:`
|
||||
);
|
||||
await this.info(
|
||||
` Scheduled Time: ${schedulingContext.scheduledTime.toLocaleString()}`
|
||||
);
|
||||
await this.info(
|
||||
` Original Schedule Input: ${schedulingContext.originalInput}`
|
||||
);
|
||||
} else {
|
||||
await this.info(`Starting price update operation with configuration:`);
|
||||
}
|
||||
|
||||
await this.info(` Target Tag: ${config.targetTag}`);
|
||||
await this.info(` Price Adjustment: ${config.priceAdjustmentPercentage}%`);
|
||||
await this.info(` Shop Domain: ${config.shopDomain}`);
|
||||
|
||||
// Also log to progress file
|
||||
await this.progressService.logOperationStart(config);
|
||||
// Also log to progress file with scheduling context
|
||||
await this.progressService.logOperationStart(config, schedulingContext);
|
||||
}
|
||||
|
||||
/**
|
||||
* Logs rollback operation start with configuration details (Requirements 3.1, 7.1, 8.3)
|
||||
* @param {Object} config - Configuration object
|
||||
* @param {Object} schedulingContext - Optional scheduling context
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
async logRollbackStart(config) {
|
||||
await this.info(`Starting price rollback operation with configuration:`);
|
||||
async logRollbackStart(config, schedulingContext = null) {
|
||||
if (schedulingContext && schedulingContext.isScheduled) {
|
||||
await this.info(
|
||||
`Starting scheduled price rollback operation with configuration:`
|
||||
);
|
||||
await this.info(
|
||||
` Scheduled Time: ${schedulingContext.scheduledTime.toLocaleString()}`
|
||||
);
|
||||
await this.info(
|
||||
` Original Schedule Input: ${schedulingContext.originalInput}`
|
||||
);
|
||||
} else {
|
||||
await this.info(`Starting price rollback operation with configuration:`);
|
||||
}
|
||||
|
||||
await this.info(` Target Tag: ${config.targetTag}`);
|
||||
await this.info(` Operation Mode: rollback`);
|
||||
await this.info(` Shop Domain: ${config.shopDomain}`);
|
||||
|
||||
// Also log to progress file with rollback-specific format
|
||||
// Also log to progress file with rollback-specific format and scheduling context
|
||||
try {
|
||||
await this.progressService.logRollbackStart(config);
|
||||
await this.progressService.logRollbackStart(config, schedulingContext);
|
||||
} catch (error) {
|
||||
// Progress logging should not block main operations
|
||||
console.warn(`Warning: Failed to log to progress file: ${error.message}`);
|
||||
@@ -267,15 +295,20 @@ class Logger {
|
||||
* @param {string} entry.productId - Product ID
|
||||
* @param {string} entry.variantId - Variant ID (optional)
|
||||
* @param {string} entry.errorMessage - Error message
|
||||
* @param {Object} schedulingContext - Optional scheduling context for error logging (Requirements 5.3, 5.4)
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
async logProductError(entry) {
|
||||
async logProductError(entry, schedulingContext = null) {
|
||||
const variantInfo = entry.variantId ? ` (Variant: ${entry.variantId})` : "";
|
||||
const message = `${this.colors.red}❌${this.colors.reset} Failed to update "${entry.productTitle}"${variantInfo}: ${entry.errorMessage}`;
|
||||
const schedulingInfo =
|
||||
schedulingContext && schedulingContext.isScheduled
|
||||
? ` [Scheduled Operation]`
|
||||
: "";
|
||||
const message = `${this.colors.red}❌${this.colors.reset} Failed to update "${entry.productTitle}"${variantInfo}: ${entry.errorMessage}${schedulingInfo}`;
|
||||
console.error(message);
|
||||
|
||||
// Also log to progress file
|
||||
await this.progressService.logError(entry);
|
||||
// Also log to progress file with scheduling context
|
||||
await this.progressService.logError(entry, schedulingContext);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -312,24 +345,182 @@ class Logger {
|
||||
await this.warning(`Skipped "${productTitle}": ${reason}`);
|
||||
}
|
||||
|
||||
/**
|
||||
* Logs scheduling confirmation with operation details (Requirements 2.1, 2.3)
|
||||
* @param {Object} schedulingInfo - Scheduling information
|
||||
* @param {Date} schedulingInfo.scheduledTime - Target execution time
|
||||
* @param {string} schedulingInfo.originalInput - Original datetime input
|
||||
* @param {string} schedulingInfo.operationType - Type of operation (update/rollback)
|
||||
* @param {Object} schedulingInfo.config - Operation configuration
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
async logSchedulingConfirmation(schedulingInfo) {
|
||||
const { scheduledTime, originalInput, operationType, config } =
|
||||
schedulingInfo;
|
||||
|
||||
await this.info("=".repeat(50));
|
||||
await this.info("SCHEDULED OPERATION CONFIRMED");
|
||||
await this.info("=".repeat(50));
|
||||
await this.info(`Operation Type: ${operationType}`);
|
||||
await this.info(`Scheduled Time: ${scheduledTime.toLocaleString()}`);
|
||||
await this.info(`Original Input: ${originalInput}`);
|
||||
await this.info(`Target Tag: ${config.targetTag}`);
|
||||
|
||||
if (operationType === "update") {
|
||||
await this.info(`Price Adjustment: ${config.priceAdjustmentPercentage}%`);
|
||||
}
|
||||
|
||||
await this.info(`Shop Domain: ${config.shopDomain}`);
|
||||
|
||||
const delay = scheduledTime.getTime() - new Date().getTime();
|
||||
const timeRemaining = this.formatTimeRemaining(delay);
|
||||
await this.info(`Time Remaining: ${timeRemaining}`);
|
||||
await this.info("Press Ctrl+C to cancel the scheduled operation");
|
||||
await this.info("=".repeat(50));
|
||||
|
||||
// Also log to progress file
|
||||
await this.progressService.logSchedulingConfirmation(schedulingInfo);
|
||||
}
|
||||
|
||||
/**
|
||||
* Logs countdown updates during scheduled wait period (Requirements 2.2, 2.3)
|
||||
* @param {Object} countdownInfo - Countdown information
|
||||
* @param {Date} countdownInfo.scheduledTime - Target execution time
|
||||
* @param {number} countdownInfo.remainingMs - Milliseconds remaining
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
async logCountdownUpdate(countdownInfo) {
|
||||
const { scheduledTime, remainingMs } = countdownInfo;
|
||||
const timeRemaining = this.formatTimeRemaining(remainingMs);
|
||||
|
||||
await this.info(
|
||||
`Scheduled execution in: ${timeRemaining} (at ${scheduledTime.toLocaleString()})`
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Logs the start of scheduled operation execution (Requirements 2.3, 5.4)
|
||||
* @param {Object} executionInfo - Execution information
|
||||
* @param {Date} executionInfo.scheduledTime - Original scheduled time
|
||||
* @param {Date} executionInfo.actualTime - Actual execution time
|
||||
* @param {string} executionInfo.operationType - Type of operation
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
async logScheduledExecutionStart(executionInfo) {
|
||||
const { scheduledTime, actualTime, operationType } = executionInfo;
|
||||
const delay = actualTime.getTime() - scheduledTime.getTime();
|
||||
const delayText =
|
||||
Math.abs(delay) < 1000
|
||||
? "on time"
|
||||
: delay > 0
|
||||
? `${Math.round(delay / 1000)}s late`
|
||||
: `${Math.round(Math.abs(delay) / 1000)}s early`;
|
||||
|
||||
await this.info("=".repeat(50));
|
||||
await this.info("SCHEDULED OPERATION STARTING");
|
||||
await this.info("=".repeat(50));
|
||||
await this.info(`Operation Type: ${operationType}`);
|
||||
await this.info(`Scheduled Time: ${scheduledTime.toLocaleString()}`);
|
||||
await this.info(`Actual Start Time: ${actualTime.toLocaleString()}`);
|
||||
await this.info(`Timing: ${delayText}`);
|
||||
await this.info("=".repeat(50));
|
||||
|
||||
// Also log to progress file
|
||||
await this.progressService.logScheduledExecutionStart(executionInfo);
|
||||
}
|
||||
|
||||
/**
|
||||
* Logs scheduled operation cancellation (Requirements 3.1, 3.2)
|
||||
* @param {Object} cancellationInfo - Cancellation information
|
||||
* @param {Date} cancellationInfo.scheduledTime - Original scheduled time
|
||||
* @param {Date} cancellationInfo.cancelledTime - Time when cancelled
|
||||
* @param {string} cancellationInfo.operationType - Type of operation
|
||||
* @param {string} cancellationInfo.reason - Cancellation reason
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
async logScheduledOperationCancellation(cancellationInfo) {
|
||||
const { scheduledTime, cancelledTime, operationType, reason } =
|
||||
cancellationInfo;
|
||||
const timeRemaining = scheduledTime.getTime() - cancelledTime.getTime();
|
||||
const remainingText = this.formatTimeRemaining(timeRemaining);
|
||||
|
||||
await this.info("=".repeat(50));
|
||||
await this.info("SCHEDULED OPERATION CANCELLED");
|
||||
await this.info("=".repeat(50));
|
||||
await this.info(`Operation Type: ${operationType}`);
|
||||
await this.info(`Scheduled Time: ${scheduledTime.toLocaleString()}`);
|
||||
await this.info(`Cancelled Time: ${cancelledTime.toLocaleString()}`);
|
||||
await this.info(`Time Remaining: ${remainingText}`);
|
||||
await this.info(`Reason: ${reason}`);
|
||||
await this.info("=".repeat(50));
|
||||
|
||||
// Also log to progress file
|
||||
await this.progressService.logScheduledOperationCancellation(
|
||||
cancellationInfo
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Format time remaining into human-readable string
|
||||
* @param {number} milliseconds - Time remaining in milliseconds
|
||||
* @returns {string} Formatted time string (e.g., "2h 30m 15s")
|
||||
*/
|
||||
formatTimeRemaining(milliseconds) {
|
||||
if (milliseconds <= 0) {
|
||||
return "0s";
|
||||
}
|
||||
|
||||
const seconds = Math.floor(milliseconds / 1000);
|
||||
const minutes = Math.floor(seconds / 60);
|
||||
const hours = Math.floor(minutes / 60);
|
||||
const days = Math.floor(hours / 24);
|
||||
|
||||
const remainingHours = hours % 24;
|
||||
const remainingMinutes = minutes % 60;
|
||||
const remainingSeconds = seconds % 60;
|
||||
|
||||
const parts = [];
|
||||
|
||||
if (days > 0) parts.push(`${days}d`);
|
||||
if (remainingHours > 0) parts.push(`${remainingHours}h`);
|
||||
if (remainingMinutes > 0) parts.push(`${remainingMinutes}m`);
|
||||
if (remainingSeconds > 0 || parts.length === 0)
|
||||
parts.push(`${remainingSeconds}s`);
|
||||
|
||||
return parts.join(" ");
|
||||
}
|
||||
|
||||
/**
|
||||
* Logs comprehensive error analysis and recommendations
|
||||
* @param {Array} errors - Array of error objects
|
||||
* @param {Object} summary - Operation summary statistics
|
||||
* @param {Object} schedulingContext - Optional scheduling context for error analysis (Requirements 5.3, 5.4)
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
async logErrorAnalysis(errors, summary) {
|
||||
async logErrorAnalysis(errors, summary, schedulingContext = null) {
|
||||
if (!errors || errors.length === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
const operationType =
|
||||
summary.successfulRollbacks !== undefined ? "ROLLBACK" : "UPDATE";
|
||||
const schedulingPrefix =
|
||||
schedulingContext && schedulingContext.isScheduled ? "SCHEDULED " : "";
|
||||
|
||||
await this.info("=".repeat(50));
|
||||
await this.info(`${operationType} ERROR ANALYSIS`);
|
||||
await this.info(`${schedulingPrefix}${operationType} ERROR ANALYSIS`);
|
||||
await this.info("=".repeat(50));
|
||||
|
||||
if (schedulingContext && schedulingContext.isScheduled) {
|
||||
await this.info(
|
||||
`Scheduled Time: ${schedulingContext.scheduledTime.toLocaleString()}`
|
||||
);
|
||||
await this.info(
|
||||
`Original Schedule Input: ${schedulingContext.originalInput}`
|
||||
);
|
||||
await this.info("=".repeat(50));
|
||||
}
|
||||
|
||||
// Enhanced categorization for rollback operations
|
||||
const categories = {};
|
||||
const retryableErrors = [];
|
||||
@@ -411,8 +602,8 @@ class Logger {
|
||||
await this.info("\nRecommendations:");
|
||||
await this.provideErrorRecommendations(categories, summary, operationType);
|
||||
|
||||
// Log to progress file as well
|
||||
await this.progressService.logErrorAnalysis(errors);
|
||||
// Log to progress file as well with scheduling context
|
||||
await this.progressService.logErrorAnalysis(errors, schedulingContext);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user