188 lines
5.7 KiB
JavaScript
188 lines
5.7 KiB
JavaScript
// src/utils/logger.js
|
||
// 统一日志工具
|
||
|
||
// 支持开发环境或显式开启调试模式
|
||
// 生产环境下可以通过设置 REACT_APP_ENABLE_DEBUG=true 来开启调试日志
|
||
const isDevelopment =
|
||
process.env.NODE_ENV === 'development' ||
|
||
process.env.REACT_APP_ENABLE_DEBUG === 'true';
|
||
|
||
// ========== 日志限流配置 ==========
|
||
const LOG_THROTTLE_TIME = 1000; // 1秒内相同日志只输出一次
|
||
const recentLogs = new Map(); // 日志缓存,用于去重
|
||
const MAX_CACHE_SIZE = 100; // 最大缓存数量
|
||
|
||
/**
|
||
* 生成日志的唯一键
|
||
*/
|
||
function getLogKey(component, message) {
|
||
return `${component}:${message}`;
|
||
}
|
||
|
||
/**
|
||
* 检查是否应该输出日志(限流检查)
|
||
*/
|
||
function shouldLog(component, message) {
|
||
const key = getLogKey(component, message);
|
||
const now = Date.now();
|
||
const lastLog = recentLogs.get(key);
|
||
|
||
// 如果1秒内已经输出过相同日志,跳过
|
||
if (lastLog && now - lastLog < LOG_THROTTLE_TIME) {
|
||
return false;
|
||
}
|
||
|
||
// 记录日志时间
|
||
recentLogs.set(key, now);
|
||
|
||
// 限制缓存大小,避免内存泄漏
|
||
if (recentLogs.size > MAX_CACHE_SIZE) {
|
||
const oldestKey = recentLogs.keys().next().value;
|
||
recentLogs.delete(oldestKey);
|
||
}
|
||
|
||
return true;
|
||
}
|
||
|
||
/**
|
||
* 统一日志工具
|
||
* 开发环境:输出详细日志
|
||
* 生产环境:仅输出错误日志
|
||
*/
|
||
export const logger = {
|
||
/**
|
||
* API 相关日志
|
||
*/
|
||
api: {
|
||
/**
|
||
* 记录 API 请求
|
||
* @param {string} method - 请求方法 (GET, POST, etc.)
|
||
* @param {string} url - 请求 URL
|
||
* @param {object} data - 请求参数/body
|
||
*/
|
||
request: (method, url, data = null) => {
|
||
if (isDevelopment && shouldLog('API', `${method} ${url}`)) {
|
||
console.group(`🌐 API Request: ${method} ${url}`);
|
||
console.log('Timestamp:', new Date().toISOString());
|
||
if (data) console.log('Data:', data);
|
||
console.groupEnd();
|
||
}
|
||
},
|
||
|
||
/**
|
||
* 记录 API 响应成功
|
||
* @param {string} method - 请求方法
|
||
* @param {string} url - 请求 URL
|
||
* @param {number} status - HTTP 状态码
|
||
* @param {any} data - 响应数据
|
||
*/
|
||
response: (method, url, status, data) => {
|
||
if (isDevelopment && shouldLog('API', `${method} ${url} ${status}`)) {
|
||
console.group(`✅ API Response: ${method} ${url}`);
|
||
console.log('Status:', status);
|
||
console.log('Data:', data);
|
||
console.log('Timestamp:', new Date().toISOString());
|
||
console.groupEnd();
|
||
}
|
||
},
|
||
|
||
/**
|
||
* 记录 API 错误
|
||
* @param {string} method - 请求方法
|
||
* @param {string} url - 请求 URL
|
||
* @param {Error|any} error - 错误对象
|
||
* @param {object} requestData - 请求参数(可选)
|
||
*/
|
||
error: (method, url, error, requestData = null) => {
|
||
// API 错误始终输出,不做限流
|
||
console.group(`❌ API Error: ${method} ${url}`);
|
||
console.error('Error:', error);
|
||
console.error('Message:', error?.message || error);
|
||
if (error?.response) {
|
||
console.error('Response Status:', error.response.status);
|
||
console.error('Response Data:', error.response.data);
|
||
}
|
||
if (requestData) console.error('Request Data:', requestData);
|
||
console.error('Timestamp:', new Date().toISOString());
|
||
if (error?.stack) console.error('Stack:', error.stack);
|
||
console.groupEnd();
|
||
}
|
||
},
|
||
|
||
/**
|
||
* 组件错误日志
|
||
* @param {string} component - 组件名称
|
||
* @param {string} method - 方法名称
|
||
* @param {Error|any} error - 错误对象
|
||
* @param {object} context - 上下文信息(可选)
|
||
*/
|
||
error: (component, method, error, context = {}) => {
|
||
// 错误日志始终输出,不做限流
|
||
console.group(`🔴 Error in ${component}.${method}`);
|
||
console.error('Error:', error);
|
||
console.error('Message:', error?.message || error);
|
||
if (Object.keys(context).length > 0) {
|
||
console.error('Context:', context);
|
||
}
|
||
console.error('Timestamp:', new Date().toISOString());
|
||
if (error?.stack) console.error('Stack:', error.stack);
|
||
console.groupEnd();
|
||
},
|
||
|
||
/**
|
||
* 警告日志
|
||
* @param {string} component - 组件名称
|
||
* @param {string} message - 警告信息
|
||
* @param {object} data - 相关数据(可选)
|
||
*/
|
||
warn: (component, message, data = {}) => {
|
||
if (isDevelopment && shouldLog(component, message)) {
|
||
console.group(`⚠️ Warning: ${component}`);
|
||
console.warn('Message:', message);
|
||
if (Object.keys(data).length > 0) {
|
||
console.warn('Data:', data);
|
||
}
|
||
console.warn('Timestamp:', new Date().toISOString());
|
||
console.groupEnd();
|
||
}
|
||
},
|
||
|
||
/**
|
||
* 调试日志(仅开发环境)
|
||
* @param {string} component - 组件名称
|
||
* @param {string} message - 调试信息
|
||
* @param {object} data - 相关数据(可选)
|
||
*/
|
||
debug: (component, message, data = {}) => {
|
||
if (isDevelopment && shouldLog(component, message)) {
|
||
console.group(`🐛 Debug: ${component}`);
|
||
console.log('Message:', message);
|
||
if (Object.keys(data).length > 0) {
|
||
console.log('Data:', data);
|
||
}
|
||
console.log('Timestamp:', new Date().toISOString());
|
||
console.groupEnd();
|
||
}
|
||
},
|
||
|
||
/**
|
||
* 信息日志(仅开发环境)
|
||
* @param {string} component - 组件名称
|
||
* @param {string} message - 信息内容
|
||
* @param {object} data - 相关数据(可选)
|
||
*/
|
||
info: (component, message, data = {}) => {
|
||
if (isDevelopment && shouldLog(component, message)) {
|
||
console.group(`ℹ️ Info: ${component}`);
|
||
console.log('Message:', message);
|
||
if (Object.keys(data).length > 0) {
|
||
console.log('Data:', data);
|
||
}
|
||
console.log('Timestamp:', new Date().toISOString());
|
||
console.groupEnd();
|
||
}
|
||
}
|
||
};
|
||
|
||
export default logger;
|