sfcc-dev-mcp
Version:
MCP server for Salesforce B2C Commerce Cloud development assistance including logs, debugging, and development tools
189 lines • 7.04 kB
JavaScript
/**
* Output formatting and presentation logic for logs
*/
import { formatBytes } from '../../utils/utils.js';
import { LOG_CONSTANTS, LOG_MESSAGES } from './log-constants.js';
export class LogFormatter {
/**
* Format latest log entries response
*/
static formatLatestLogs(entries, level, limit, files) {
const fileList = files.join(', ');
return `Latest ${limit} ${level} messages from files: ${fileList}\n\n${entries.join('\n\n---\n\n')}`;
}
/**
* Format search results
*/
static formatSearchResults(matches, pattern, date) {
if (matches.length === 0) {
return LOG_MESSAGES.NO_SEARCH_MATCHES(pattern, date);
}
return `${LOG_MESSAGES.SEARCH_RESULTS(matches.length, pattern)}\n\n${matches.join('\n\n')}`;
}
/**
* Format "no files found" message
*/
static formatNoFilesFound(level, date, availableFiles) {
const available = availableFiles.join(', ');
return LOG_MESSAGES.NO_FILES_FOUND(level, date, available);
}
/**
* Format log summary into a readable string
*/
static formatLogSummary(summary) {
const keyIssuesSection = summary.keyIssues.length > 0
? summary.keyIssues.map((issue) => `- ${issue}`).join('\n')
: 'No major issues detected';
return [
`Log Summary for ${summary.date}:`,
'',
'📊 Counts:',
`- Errors: ${summary.errorCount}`,
`- Warnings: ${summary.warningCount}`,
`- Info: ${summary.infoCount}`,
`- Debug: ${summary.debugCount}`,
'',
`📁 Log Files (${summary.files.length}):`,
summary.files.map((f) => `- ${f}`).join('\n'),
'',
'🔥 Key Issues:',
keyIssuesSection,
].join('\n');
}
/**
* Format log files list with metadata
*/
static formatLogFilesList(logFiles) {
const totalFiles = logFiles.totalCount ?? logFiles.length;
const showingText = totalFiles > LOG_CONSTANTS.MAX_LOG_FILES_DISPLAY
? ` (showing latest ${LOG_CONSTANTS.MAX_LOG_FILES_DISPLAY} of ${totalFiles} total)`
: '';
return `Available log files${showingText}:\n\n${logFiles.map((file) => `📄 ${file.name}\n Size: ${formatBytes(file.size)}\n Modified: ${file.lastModified}`).join('\n\n')}`;
}
/**
* Format file processing summary
*/
static formatProcessingSummary(entriesReturned, filesProcessed, totalEntries) {
return `Parsed ${totalEntries} total entries from ${filesProcessed} files, returning latest ${entriesReturned}`;
}
/**
* Format log level statistics
*/
static formatLogLevelStats(stats) {
const entries = Object.entries(stats);
return entries
.map(([level, count]) => `${level}: ${count}`)
.join(', ');
}
/**
* Format error message with context
*/
static formatError(operation, error) {
const message = error instanceof Error ? error.message : String(error);
return `Failed to ${operation}: ${message}`;
}
/**
* Format file list for debugging
*/
static formatFileList(files, prefix = '') {
return files.map(f => `${prefix}${f}`).join(', ');
}
/**
* Format timestamp for display
*/
static formatTimestamp(date) {
return date.toISOString().replace('T', ' ').substring(0, 19);
}
/**
* Format log entry with timestamp and level highlighting
*/
static formatLogEntry(entry, highlightLevel = false) {
if (!highlightLevel) {
return entry;
}
return entry
.replace(/ ERROR /g, ' 🔴 ERROR ')
.replace(/ WARN /g, ' 🟡 WARN ')
.replace(/ INFO /g, ' 🔵 INFO ')
.replace(/ DEBUG /g, ' 🟢 DEBUG ');
}
/**
* Format progress indicator
*/
static formatProgress(current, total, operation) {
const percentage = Math.round((current / total) * 100);
return `${operation}: ${current}/${total} (${percentage}%)`;
}
/**
* Format file size summary
*/
static formatFileSizes(files) {
const totalSize = files.reduce((sum, file) => sum + file.size, 0);
const avgSize = totalSize / files.length;
return `Total: ${formatBytes(totalSize)}, Average: ${formatBytes(avgSize)}, Files: ${files.length}`;
}
/**
* Truncate long text with ellipsis
*/
static truncateText(text, maxLength) {
if (text.length <= maxLength) {
return text;
}
return `${text.substring(0, maxLength - 3)}...`;
}
/**
* Format job log list
*/
static formatJobLogList(jobLogs) {
if (jobLogs.length === 0) {
return 'No job logs found.';
}
return `Found ${jobLogs.length} job logs:\n\n${jobLogs.map((jobLog) => {
const baseInfo = `🔧 Job: ${jobLog.jobName}\n ID: ${jobLog.jobId}\n File: ${jobLog.logFile.split('/').pop()}\n Modified: ${jobLog.lastModified}`;
const sizeInfo = jobLog.size ? `\n Size: ${formatBytes(jobLog.size)}` : '';
return baseInfo + sizeInfo;
}).join('\n\n')}`;
}
/**
* Format job log entries with job context
*/
static formatJobLogEntries(entries, level, limit, jobContext) {
const levelDisplay = level === 'all' ? 'all levels' : level;
const contextText = jobContext ? ` from ${jobContext}` : '';
return `Latest ${limit} ${levelDisplay} messages${contextText}:\n\n${entries.join('\n\n---\n\n')}`;
}
/**
* Format job execution summary
*/
static formatJobExecutionSummary(summary, jobName) {
const sections = [
`Job Execution Summary: ${jobName}`,
'',
'⏱️ Timing:',
`- Start: ${summary.startTime ?? 'Unknown'}`,
`- End: ${summary.endTime ?? 'Unknown'}`,
`- Duration: ${summary.duration ?? 'Unknown'}`,
'',
'📊 Status:',
`- Status: ${summary.status ?? 'Unknown'}`,
`- Errors: ${summary.errorCount}`,
`- Warnings: ${summary.warningCount}`,
];
if (summary.steps.length > 0) {
sections.push('', '🔄 Steps:', ...summary.steps.map(step => `- ${step}`));
}
return sections.join('\n');
}
/**
* Format job search results
*/
static formatJobSearchResults(matches, pattern, jobContext) {
if (matches.length === 0) {
const contextText = jobContext ? ` in ${jobContext} logs` : ' in job logs';
return `No matches found for "${pattern}"${contextText}`;
}
const contextText = jobContext ? ` in ${jobContext} logs` : ' in job logs';
return `Found ${matches.length} matches for "${pattern}"${contextText}:\n\n${matches.join('\n\n')}`;
}
}
//# sourceMappingURL=log-formatter.js.map