cc / src /utils /tokenRefreshLogger.js
hequ's picture
Upload 221 files
69b897d verified
const winston = require('winston')
const path = require('path')
const fs = require('fs')
const { maskToken } = require('./tokenMask')
// 确保日志目录存在
const logDir = path.join(process.cwd(), 'logs')
if (!fs.existsSync(logDir)) {
fs.mkdirSync(logDir, { recursive: true })
}
// 创建专用的 token 刷新日志记录器
const tokenRefreshLogger = winston.createLogger({
level: 'info',
format: winston.format.combine(
winston.format.timestamp({
format: 'YYYY-MM-DD HH:mm:ss.SSS'
}),
winston.format.json(),
winston.format.printf((info) => JSON.stringify(info, null, 2))
),
transports: [
// 文件传输 - 每日轮转
new winston.transports.File({
filename: path.join(logDir, 'token-refresh.log'),
maxsize: 10 * 1024 * 1024, // 10MB
maxFiles: 30, // 保留30天
tailable: true
}),
// 错误单独记录
new winston.transports.File({
filename: path.join(logDir, 'token-refresh-error.log'),
level: 'error',
maxsize: 10 * 1024 * 1024,
maxFiles: 30
})
],
// 错误处理
exitOnError: false
})
// 在开发环境添加控制台输出
if (process.env.NODE_ENV !== 'production') {
tokenRefreshLogger.add(
new winston.transports.Console({
format: winston.format.combine(winston.format.colorize(), winston.format.simple())
})
)
}
/**
* 记录 token 刷新开始
*/
function logRefreshStart(accountId, accountName, platform = 'claude', reason = '') {
tokenRefreshLogger.info({
event: 'token_refresh_start',
accountId,
accountName,
platform,
reason,
timestamp: new Date().toISOString()
})
}
/**
* 记录 token 刷新成功
*/
function logRefreshSuccess(accountId, accountName, platform = 'claude', tokenData = {}) {
const maskedTokenData = {
accessToken: tokenData.accessToken ? maskToken(tokenData.accessToken) : '[NOT_PROVIDED]',
refreshToken: tokenData.refreshToken ? maskToken(tokenData.refreshToken) : '[NOT_PROVIDED]',
expiresAt: tokenData.expiresAt || tokenData.expiry_date || '[NOT_PROVIDED]',
scopes: tokenData.scopes || tokenData.scope || '[NOT_PROVIDED]'
}
tokenRefreshLogger.info({
event: 'token_refresh_success',
accountId,
accountName,
platform,
tokenData: maskedTokenData,
timestamp: new Date().toISOString()
})
}
/**
* 记录 token 刷新失败
*/
function logRefreshError(accountId, accountName, platform = 'claude', error, attemptNumber = 1) {
const errorInfo = {
message: error.message || error.toString(),
code: error.code || 'UNKNOWN',
statusCode: error.response?.status || 'N/A',
responseData: error.response?.data || 'N/A'
}
tokenRefreshLogger.error({
event: 'token_refresh_error',
accountId,
accountName,
platform,
error: errorInfo,
attemptNumber,
timestamp: new Date().toISOString()
})
}
/**
* 记录 token 刷新跳过(由于并发锁)
*/
function logRefreshSkipped(accountId, accountName, platform = 'claude', reason = 'locked') {
tokenRefreshLogger.info({
event: 'token_refresh_skipped',
accountId,
accountName,
platform,
reason,
timestamp: new Date().toISOString()
})
}
/**
* 记录 token 使用情况
*/
function logTokenUsage(accountId, accountName, platform = 'claude', expiresAt, isExpired) {
tokenRefreshLogger.debug({
event: 'token_usage_check',
accountId,
accountName,
platform,
expiresAt,
isExpired,
remainingMinutes: expiresAt ? Math.floor((new Date(expiresAt) - Date.now()) / 60000) : 'N/A',
timestamp: new Date().toISOString()
})
}
/**
* 记录批量刷新任务
*/
function logBatchRefreshStart(totalAccounts, platform = 'all') {
tokenRefreshLogger.info({
event: 'batch_refresh_start',
totalAccounts,
platform,
timestamp: new Date().toISOString()
})
}
/**
* 记录批量刷新结果
*/
function logBatchRefreshComplete(results) {
tokenRefreshLogger.info({
event: 'batch_refresh_complete',
results: {
total: results.total || 0,
success: results.success || 0,
failed: results.failed || 0,
skipped: results.skipped || 0
},
timestamp: new Date().toISOString()
})
}
module.exports = {
logger: tokenRefreshLogger,
logRefreshStart,
logRefreshSuccess,
logRefreshError,
logRefreshSkipped,
logTokenUsage,
logBatchRefreshStart,
logBatchRefreshComplete
}