github-actions[bot]
Update from GitHub Actions
f9e1174
import fs from 'fs';
import path from 'path';
// 日志文件路径
const LOG_FILE = './logs/app.log';
const LOG_DIR = './logs';
/**
* 确保日志目录存在
*/
function ensureLogDirectory() {
if (!fs.existsSync(LOG_DIR)) {
fs.mkdirSync(LOG_DIR, { recursive: true });
}
}
/**
* 写入日志到文件
* @param {string} level - 日志级别 (INFO, ERROR, WARN)
* @param {string} message - 日志消息
*/
export function writeLog(level, message) {
ensureLogDirectory();
const timestamp = new Date().toISOString();
const logEntry = `[${timestamp}] [${level}] ${message}\n`;
try {
fs.appendFileSync(LOG_FILE, logEntry);
} catch (error) {
console.error('写入日志文件失败:', error);
}
}
/**
* 增强的 console.log,同时输出到控制台和文件
* @param {...any} args - 要记录的参数
*/
export function log(...args) {
const message = args.map(arg =>
typeof arg === 'object' ? JSON.stringify(arg) : String(arg)
).join(' ');
console.log(...args);
writeLog('INFO', message);
}
/**
* 增强的 console.error,同时输出到控制台和文件
* @param {...any} args - 要记录的参数
*/
export function logError(...args) {
const message = args.map(arg =>
typeof arg === 'object' ? JSON.stringify(arg) : String(arg)
).join(' ');
console.error(...args);
writeLog('ERROR', message);
}
/**
* 读取最近的日志
* @param {number} lines - 要读取的行数,默认100行
* @returns {Array} 日志行数组
*/
export function getRecentLogs(lines = 100) {
try {
if (!fs.existsSync(LOG_FILE)) {
return [];
}
const content = fs.readFileSync(LOG_FILE, 'utf8');
const logLines = content.trim().split('\n').filter(line => line.length > 0);
// 返回最后 N 行
return logLines.slice(-lines);
} catch (error) {
console.error('读取日志文件失败:', error);
return [];
}
}
/**
* 创建人类可读的时间戳
* @returns {string} 格式化的时间戳 YYYY-MM-DD_HH-MM-SS
*/
export function getHumanReadableTimestamp() {
const now = new Date();
const year = now.getFullYear();
const month = String(now.getMonth() + 1).padStart(2, '0');
const day = String(now.getDate()).padStart(2, '0');
const hours = String(now.getHours()).padStart(2, '0');
const minutes = String(now.getMinutes()).padStart(2, '0');
const seconds = String(now.getSeconds()).padStart(2, '0');
return `${year}-${month}-${day}_${hours}-${minutes}-${seconds}`;
}
/**
* 确保截图目录存在
* @param {string} dir - 目录路径
*/
export function ensureScreenshotDirectory(dir) {
if (!fs.existsSync(dir)) {
fs.mkdirSync(dir, { recursive: true });
console.log(`创建截图目录: ${dir}`);
}
}
/**
* 检查 Cookie 文件是否存在
* @param {string} cookieFile - Cookie 文件路径
* @returns {boolean} 文件是否存在
*/
export function checkCookieFile(cookieFile) {
if (!fs.existsSync(cookieFile)) {
console.error(`Cookie文件不存在: ${cookieFile}`);
console.log('请先运行 npm run login 进行登录');
return false;
}
return true;
}
/**
* 读取并解析 Cookie 文件
* @param {string} cookieFile - Cookie 文件路径
* @returns {Array} Cookie 数组
*/
export function loadCookies(cookieFile) {
try {
const cookies = JSON.parse(fs.readFileSync(cookieFile, 'utf8'));
console.log(`已加载 ${cookies.length} 个cookies`);
return cookies;
} catch (error) {
console.error('读取 Cookie 文件失败:', error);
throw error;
}
}
/**
* 保存截图
* @param {Object} page - Playwright 页面对象
* @param {string} screenshotDir - 截图目录
* @param {string} prefix - 文件名前缀
* @returns {string} 截图文件路径
*/
export async function saveScreenshot(page, screenshotDir, prefix = 'screenshot') {
ensureScreenshotDirectory(screenshotDir);
const timestamp = getHumanReadableTimestamp();
const screenshotPath = path.join(screenshotDir, `${prefix}-${timestamp}.png`);
await page.screenshot({ path: screenshotPath });
console.log(`截图已保存: ${screenshotPath}`);
return screenshotPath;
}