fix: 增加日志方法,方便排查问题

master
Lxy 3 months ago
parent 32ca747deb
commit 02606aeaad

@ -290,10 +290,10 @@ class DataFetcher:
symbols_by_exchange = self.get_all_symbols_by_exchange() symbols_by_exchange = self.get_all_symbols_by_exchange()
symbols = [] symbols = []
for exchange, products in symbols_by_exchange.items(): for exchange, products in symbols_by_exchange.items():
for product, product_data in products.items(): for product, product_contracts in products.items():
# 使用每个品种的第一个合约作为代表 # 使用每个品种的第一个合约作为代表
if product_data['contracts']: if product_contracts:
symbols.append(product_data['contracts'][0]) symbols.append(product_contracts[0])
return symbols return symbols
except Exception as e: except Exception as e:
print(f"获取所有品种列表失败:{e}") print(f"获取所有品种列表失败:{e}")
@ -321,49 +321,49 @@ class DataFetcher:
"SHFE": { # 上海期货交易所 "SHFE": { # 上海期货交易所
"AU": ["AU2603", "AU2604", "AU2605", "AU2606", "AU2607", "AU2608", "AU2609"], # 黄金 "AU": ["AU2603", "AU2604", "AU2605", "AU2606", "AU2607", "AU2608", "AU2609"], # 黄金
"AG": ["AG2603", "AG2604", "AG2605", "AG2606", "AG2607", "AG2608", "AG2609"], # 白银 "AG": ["AG2603", "AG2604", "AG2605", "AG2606", "AG2607", "AG2608", "AG2609"], # 白银
"CU": ["CU2603", "CU2604", "CU2605", "CU2606", "CU2607", "CU2608", "CU2609"], # 铜 "CU": ["CU2603", "CU2604", "CU2605", "CU2606", "CU2607", "CU2608", "CU2609"]#, # 铜
"NI": ["NI2603", "NI2604", "NI2605", "NI2606", "NI2607", "NI2608", "NI2609"], # 镍 # "NI": ["NI2603", "NI2604", "NI2605", "NI2606", "NI2607", "NI2608", "NI2609"], # 镍
"SN": ["SN2603", "SN2604", "SN2605", "SN2606", "SN2607", "SN2608", "SN2609"], # 锡 # "SN": ["SN2603", "SN2604", "SN2605", "SN2606", "SN2607", "SN2608", "SN2609"], # 锡
"FG": ["FG2603", "FG2604", "FG2605", "FG2606", "FG2607", "FG2608", "FG2609"], # 玻璃 # "FG": ["FG2603", "FG2604", "FG2605", "FG2606", "FG2607", "FG2608", "FG2609"], # 玻璃
"RB": ["RB2603", "RB2604", "RB2605", "RB2606", "RB2607", "RB2608", "RB2609"], # 螺纹钢 # "RB": ["RB2603", "RB2604", "RB2605", "RB2606", "RB2607", "RB2608", "RB2609"], # 螺纹钢
"AL": ["AL2603", "AL2604", "AL2605", "AL2606", "AL2607", "AL2608", "AL2609"], # 铝 # "AL": ["AL2603", "AL2604", "AL2605", "AL2606", "AL2607", "AL2608", "AL2609"], # 铝
"ZN": ["ZN2603", "ZN2604", "ZN2605", "ZN2606", "ZN2607", "ZN2608", "ZN2609"], # 锌 # "ZN": ["ZN2603", "ZN2604", "ZN2605", "ZN2606", "ZN2607", "ZN2608", "ZN2609"], # 锌
"RU": ["RU2603", "RU2604", "RU2605", "RU2606", "RU2607", "RU2608", "RU2609"], # 橡胶 # "RU": ["RU2603", "RU2604", "RU2605", "RU2606", "RU2607", "RU2608", "RU2609"], # 橡胶
"NR": ["NR2603", "NR2604", "NR2605", "NR2606", "NR2607", "NR2608", "NR2609"], # 20号胶 # "NR": ["NR2603", "NR2604", "NR2605", "NR2606", "NR2607", "NR2608", "NR2609"], # 20号胶
"FU": ["FU2603", "FU2604", "FU2605", "FU2606", "FU2607", "FU2608", "FU2609"], # 燃油 # "FU": ["FU2603", "FU2604", "FU2605", "FU2606", "FU2607", "FU2608", "FU2609"], # 燃油
"SC": ["SC2603", "SC2604", "SC2605", "SC2606", "SC2607", "SC2608", "SC2609"], # 原油 # "SC": ["SC2603", "SC2604", "SC2605", "SC2606", "SC2607", "SC2608", "SC2609"], # 原油
"LU": ["LU2603", "LU2604", "LU2605", "LU2606", "LU2607", "LU2608", "LU2609"], # 低硫燃油 # "LU": ["LU2603", "LU2604", "LU2605", "LU2606", "LU2607", "LU2608", "LU2609"], # 低硫燃油
"ALO": ["ALO2603", "ALO2604", "ALO2605", "ALO2606", "ALO2607", "ALO2608", "ALO2609"], # 氧化铝 # "ALO": ["ALO2603", "ALO2604", "ALO2605", "ALO2606", "ALO2607", "ALO2608", "ALO2609"], # 氧化铝
"LI": ["LI2603", "LI2604", "LI2605", "LI2606", "LI2607", "LI2608", "LI2609"], # 碳酸锂 # "LI": ["LI2603", "LI2604", "LI2605", "LI2606", "LI2607", "LI2608", "LI2609"], # 碳酸锂
"SI": ["SI2603", "SI2604", "SI2605", "SI2606", "SI2607", "SI2608", "SI2609"] # 工业硅 # "SI": ["SI2603", "SI2604", "SI2605", "SI2606", "SI2607", "SI2608", "SI2609"] # 工业硅
}, }#,
"INE": { # 上海国际能源交易中心 # "INE": { # 上海国际能源交易中心
"SC": ["SC2603", "SC2604", "SC2605", "SC2606", "SC2607", "SC2608", "SC2609"], # 原油 # "SC": ["SC2603", "SC2604", "SC2605", "SC2606", "SC2607", "SC2608", "SC2609"], # 原油
"LU": ["LU2603", "LU2604", "LU2605", "LU2606", "LU2607", "LU2608", "LU2609"] # 低硫燃油 # "LU": ["LU2603", "LU2604", "LU2605", "LU2606", "LU2607", "LU2608", "LU2609"] # 低硫燃油
}, # },
"DCE": { # 大连商品交易所 # "DCE": { # 大连商品交易所
"JM": ["JM2603", "JM2604", "JM2605", "JM2606", "JM2607", "JM2608", "JM2609"], # 焦煤 # "JM": ["JM2603", "JM2604", "JM2605", "JM2606", "JM2607", "JM2608", "JM2609"], # 焦煤
"P": ["P2603", "P2604", "P2605", "P2606", "P2607", "P2608", "P2609"], # 棕榈油 # "P": ["P2603", "P2604", "P2605", "P2606", "P2607", "P2608", "P2609"], # 棕榈油
"V": ["V2603", "V2604", "V2605", "V2606", "V2607", "V2608", "V2609"], # PVC # "V": ["V2603", "V2604", "V2605", "V2606", "V2607", "V2608", "V2609"], # PVC
"MA": ["MA2603", "MA2604", "MA2605", "MA2606", "MA2607", "MA2608", "MA2609"], # 甲醇 # "MA": ["MA2603", "MA2604", "MA2605", "MA2606", "MA2607", "MA2608", "MA2609"], # 甲醇
"BR": ["BR2603", "BR2604", "BR2605", "BR2606", "BR2607", "BR2608", "BR2609"] # 合成橡胶 # "BR": ["BR2603", "BR2604", "BR2605", "BR2606", "BR2607", "BR2608", "BR2609"] # 合成橡胶
}, # },
"CZCE": { # 郑州商品交易所 # "CZCE": { # 郑州商品交易所
"FG": ["FG2603", "FG2604", "FG2605", "FG2606", "FG2607", "FG2608", "FG2609"], # 玻璃 # "FG": ["FG2603", "FG2604", "FG2605", "FG2606", "FG2607", "FG2608", "FG2609"], # 玻璃
"MA": ["MA2603", "MA2604", "MA2605", "MA2606", "MA2607", "MA2608", "MA2609"], # 甲醇 # "MA": ["MA2603", "MA2604", "MA2605", "MA2606", "MA2607", "MA2608", "MA2609"], # 甲醇
"V": ["V2603", "V2604", "V2605", "V2606", "V2607", "V2608", "V2609"], # PVC # "V": ["V2603", "V2604", "V2605", "V2606", "V2607", "V2608", "V2609"], # PVC
"SA": ["SA2603", "SA2604", "SA2605", "SA2606", "SA2607", "SA2608", "SA2609"], # 纯碱 # "SA": ["SA2603", "SA2604", "SA2605", "SA2606", "SA2607", "SA2608", "SA2609"], # 纯碱
"LY": ["LY2603", "LY2604", "LY2605", "LY2606", "LY2607", "LY2608", "LY2609"] # 烧碱 # "LY": ["LY2603", "LY2604", "LY2605", "LY2606", "LY2607", "LY2608", "LY2609"] # 烧碱
}, # },
"CFFEX": { # 中国金融期货交易所 # "CFFEX": { # 中国金融期货交易所
"IH": ["IH2603", "IH2604", "IH2605", "IH2606", "IH2607", "IH2608", "IH2609"], # 上证50 # "IH": ["IH2603", "IH2604", "IH2605", "IH2606", "IH2607", "IH2608", "IH2609"], # 上证50
"IC": ["IC2603", "IC2604", "IC2605", "IC2606", "IC2607", "IC2608", "IC2609"], # 中证500 # "IC": ["IC2603", "IC2604", "IC2605", "IC2606", "IC2607", "IC2608", "IC2609"], # 中证500
"IM": ["IM2603", "IM2604", "IM2605", "IM2606", "IM2607", "IM2608", "IM2609"] # 中证1000 # "IM": ["IM2603", "IM2604", "IM2605", "IM2606", "IM2607", "IM2608", "IM2609"] # 中证1000
}, # },
"GEM": { # 广州期货交易所 # "GEM": { # 广州期货交易所
"SI": ["SI2603", "SI2604", "SI2605", "SI2606", "SI2607", "SI2608", "SI2609"], # 工业硅 # "SI": ["SI2603", "SI2604", "SI2605", "SI2606", "SI2607", "SI2608", "SI2609"], # 工业硅
"SP": ["SP2603", "SP2604", "SP2605", "SP2606", "SP2607", "SP2608", "SP2609"] # 多晶硅 # "SP": ["SP2603", "SP2604", "SP2605", "SP2606", "SP2607", "SP2608", "SP2609"] # 多晶硅
} # }
} }
return symbols_by_exchange return symbols_by_exchange

@ -1,5 +1,6 @@
import express from 'express'; import express from 'express';
import { fetchDataSources, saveDataSource, fetchAIModels, saveAIModel, fetchSystemSettings, saveSystemSettings } from '../services/configService'; import { fetchDataSources, saveDataSource, fetchAIModels, saveAIModel, fetchSystemSettings, saveSystemSettings } from '../services/configService';
import { logger } from '../utils/logger';
const router = express.Router(); const router = express.Router();
@ -99,14 +100,14 @@ router.post('/user', async (req, res) => {
router.post('/test-database', async (req, res) => { router.post('/test-database', async (req, res) => {
try { try {
const { dbType, config } = req.body; const { dbType, config } = req.body;
console.log(`测试${dbType}连接`, config); logger.log(`测试${dbType}连接`, config);
// 模拟测试操作 // 模拟测试操作
await new Promise(resolve => setTimeout(resolve, 1000)); await new Promise(resolve => setTimeout(resolve, 1000));
res.status(200).json({ success: true, message: `${dbType}连接测试成功` }); res.status(200).json({ success: true, message: `${dbType}连接测试成功` });
} catch (error) { } catch (error) {
console.error('测试数据库连接失败:', error); logger.error('测试数据库连接失败:', error);
res.status(500).json({ success: false, message: '测试数据库连接失败' }); res.status(500).json({ success: false, message: '测试数据库连接失败' });
} }
}); });
@ -115,14 +116,14 @@ router.post('/test-database', async (req, res) => {
router.post('/test-datasource', async (req, res) => { router.post('/test-datasource', async (req, res) => {
try { try {
const { dsType, config } = req.body; const { dsType, config } = req.body;
console.log(`测试${dsType}数据源连接`, config); logger.log(`测试${dsType}数据源连接`, config);
// 模拟测试操作 // 模拟测试操作
await new Promise(resolve => setTimeout(resolve, 1000)); await new Promise(resolve => setTimeout(resolve, 1000));
res.status(200).json({ success: true, message: `${dsType}数据源连接测试成功` }); res.status(200).json({ success: true, message: `${dsType}数据源连接测试成功` });
} catch (error) { } catch (error) {
console.error('测试数据源连接失败:', error); logger.error('测试数据源连接失败:', error);
res.status(500).json({ success: false, message: '测试数据源连接失败' }); res.status(500).json({ success: false, message: '测试数据源连接失败' });
} }
}); });
@ -131,7 +132,7 @@ router.post('/test-datasource', async (req, res) => {
router.post('/save', async (req, res) => { router.post('/save', async (req, res) => {
try { try {
const config = req.body; const config = req.body;
console.log('保存配置:', config); logger.log('保存配置:', config);
// 保存配置到文件 // 保存配置到文件
const fs = require('fs'); const fs = require('fs');
@ -142,7 +143,7 @@ router.post('/save', async (req, res) => {
res.status(200).json({ success: true, message: '配置保存成功' }); res.status(200).json({ success: true, message: '配置保存成功' });
} catch (error) { } catch (error) {
console.error('保存配置失败:', error); logger.error('保存配置失败:', error);
res.status(500).json({ success: false, message: '保存配置失败' }); res.status(500).json({ success: false, message: '保存配置失败' });
} }
}); });
@ -163,7 +164,7 @@ router.get('/get', async (req, res) => {
res.status(200).json({ success: true, data: config }); res.status(200).json({ success: true, data: config });
} catch (error) { } catch (error) {
console.error('获取配置失败:', error); logger.error('获取配置失败:', error);
res.status(500).json({ success: false, message: '获取配置失败' }); res.status(500).json({ success: false, message: '获取配置失败' });
} }
}); });

@ -1,14 +1,18 @@
import express from 'express'; import express from 'express';
import { fetchMarketOverview, fetchMarketDetail, fetchKlineData, fetchMarketHotspots, fetchRiskAlerts } from '../services/marketService'; import { fetchMarketOverview, fetchMarketDetail, fetchKlineData, fetchMarketHotspots, fetchRiskAlerts } from '../services/marketService';
import { logger } from '../utils/logger';
const router = express.Router(); const router = express.Router();
// 获取市场概览 // 获取市场概览
router.get('/overview', async (req, res) => { router.get('/overview', async (req, res) => {
try { try {
logger.info('start 获取市场概览');
const data = await fetchMarketOverview(); const data = await fetchMarketOverview();
logger.info('end 获取市场概览');
res.status(200).json({ success: true, data }); res.status(200).json({ success: true, data });
} catch (error) { } catch (error) {
logger.error('获取市场概览失败:', error);
res.status(500).json({ success: false, message: '获取市场概览失败' }); res.status(500).json({ success: false, message: '获取市场概览失败' });
} }
}); });
@ -16,10 +20,13 @@ router.get('/overview', async (req, res) => {
// 获取品种详情 // 获取品种详情
router.get('/detail/:symbol', async (req, res) => { router.get('/detail/:symbol', async (req, res) => {
try { try {
logger.info(`start 获取合约${req.params.symbol}详情`);
const { symbol } = req.params; const { symbol } = req.params;
const data = await fetchMarketDetail(symbol); const data = await fetchMarketDetail(symbol);
logger.info(`end 获取合约${symbol}详情`);
res.status(200).json({ success: true, data }); res.status(200).json({ success: true, data });
} catch (error) { } catch (error) {
logger.error(`获取合约${req.params.symbol}详情失败:`, error);
res.status(500).json({ success: false, message: '获取品种详情失败' }); res.status(500).json({ success: false, message: '获取品种详情失败' });
} }
}); });
@ -27,11 +34,14 @@ router.get('/detail/:symbol', async (req, res) => {
// 获取K线数据 // 获取K线数据
router.get('/klines/:symbol', async (req, res) => { router.get('/klines/:symbol', async (req, res) => {
try { try {
logger.info(`start 获取合约${req.params.symbol}K线数据`);
const { symbol } = req.params; const { symbol } = req.params;
const { period = '1H' } = req.query; const { period = '1H' } = req.query;
const data = await fetchKlineData(symbol, period as string); const data = await fetchKlineData(symbol, period as string);
logger.info(`end 获取合约${symbol}K线数据`);
res.status(200).json({ success: true, data }); res.status(200).json({ success: true, data });
} catch (error) { } catch (error) {
logger.error(`获取合约${req.params.symbol}K线数据失败:`, error);
res.status(500).json({ success: false, message: '获取K线数据失败' }); res.status(500).json({ success: false, message: '获取K线数据失败' });
} }
}); });
@ -39,9 +49,12 @@ router.get('/klines/:symbol', async (req, res) => {
// 获取市场热点 // 获取市场热点
router.get('/hotspots', async (req, res) => { router.get('/hotspots', async (req, res) => {
try { try {
logger.info('start 获取市场热点');
const data = await fetchMarketHotspots(); const data = await fetchMarketHotspots();
logger.info('end 获取市场热点');
res.status(200).json({ success: true, data }); res.status(200).json({ success: true, data });
} catch (error) { } catch (error) {
logger.error('获取市场热点失败:', error);
res.status(500).json({ success: false, message: '获取市场热点失败' }); res.status(500).json({ success: false, message: '获取市场热点失败' });
} }
}); });
@ -49,9 +62,12 @@ router.get('/hotspots', async (req, res) => {
// 获取风险预警 // 获取风险预警
router.get('/alerts', async (req, res) => { router.get('/alerts', async (req, res) => {
try { try {
logger.info('start 获取风险预警');
const data = await fetchRiskAlerts(); const data = await fetchRiskAlerts();
logger.info('end 获取风险预警');
res.status(200).json({ success: true, data }); res.status(200).json({ success: true, data });
} catch (error) { } catch (error) {
logger.error('获取风险预警失败:', error);
res.status(500).json({ success: false, message: '获取风险预警失败' }); res.status(500).json({ success: false, message: '获取风险预警失败' });
} }
}); });

@ -10,6 +10,7 @@ import riskRoutes from './api/risk';
import configRoutes from './api/config'; import configRoutes from './api/config';
import watchlistRoutes from './api/watchlist'; import watchlistRoutes from './api/watchlist';
import pushRoutes from './api/push'; import pushRoutes from './api/push';
import { logger } from './utils/logger';
const app = express(); const app = express();
@ -50,7 +51,7 @@ app.use((req, res) => {
// 错误处理 // 错误处理
app.use((err: any, req: express.Request, res: express.Response, next: express.NextFunction) => { app.use((err: any, req: express.Request, res: express.Response, next: express.NextFunction) => {
console.error(err.stack); logger.error(err.stack);
res.status(500).json({ success: false, message: '服务器内部错误' }); res.status(500).json({ success: false, message: '服务器内部错误' });
}); });
@ -62,15 +63,15 @@ async function startServer() {
try { try {
// 启动Express服务器 // 启动Express服务器
const server = app.listen(port, () => { const server = app.listen(port, () => {
console.log(`服务器运行在 http://localhost:${port}`); logger.log(`服务器运行在 http://localhost:${port}`);
}); });
// 处理服务器关闭事件 // 处理服务器关闭事件
function handleShutdown() { function handleShutdown() {
console.log('正在关闭服务器...'); logger.log('正在关闭服务器...');
// 关闭Express服务器 // 关闭Express服务器
server.close(() => { server.close(() => {
console.log('服务器已关闭'); logger.log('服务器已关闭');
process.exit(0); process.exit(0);
}); });
} }
@ -80,7 +81,7 @@ async function startServer() {
process.on('SIGTERM', handleShutdown); process.on('SIGTERM', handleShutdown);
process.on('exit', handleShutdown); process.on('exit', handleShutdown);
} catch (error) { } catch (error) {
console.error('启动服务器时出错:', error); logger.error('启动服务器时出错:', error);
} }
} }

@ -1,6 +1,7 @@
import dotenv from 'dotenv'; import dotenv from 'dotenv';
import fs from 'fs'; import fs from 'fs';
import path from 'path'; import path from 'path';
import { logger } from '../utils/logger';
dotenv.config(); dotenv.config();
@ -40,11 +41,11 @@ try {
if (fs.existsSync(configPath)) { if (fs.existsSync(configPath)) {
const configData = fs.readFileSync(configPath, 'utf8'); const configData = fs.readFileSync(configPath, 'utf8');
fileConfig = JSON.parse(configData); fileConfig = JSON.parse(configData);
console.log('已读取配置文件:', configPath); logger.log('已读取配置文件:', configPath);
console.log('配置文件内容:', fileConfig); logger.log('配置文件内容:', fileConfig);
} }
} catch (error) { } catch (error) {
console.error('读取配置文件失败:', error); logger.error('读取配置文件失败:', error);
} }
export const config = { export const config = {
@ -109,7 +110,7 @@ export const config = {
}, },
defaultDataSource: 'tqsdk' defaultDataSource: 'tqsdk'
}; };
console.log('数据源配置初始化完成:', { logger.log('数据源配置初始化完成:', {
hasFileConfig: !!fileConfig.dataSource, hasFileConfig: !!fileConfig.dataSource,
enabledDataSources: Object.keys(dataSourceConfig).filter(key => enabledDataSources: Object.keys(dataSourceConfig).filter(key =>
key !== 'defaultDataSource' && dataSourceConfig[key].enabled key !== 'defaultDataSource' && dataSourceConfig[key].enabled

@ -1,6 +1,8 @@
// Service Implementation API Client // Service Implementation API Client
// This client interacts with the service_implementation API documented in api_documentation.md // This client interacts with the service_implementation API documented in api_documentation.md
import { logger } from '../utils/logger';
class ServiceImplementationClient { class ServiceImplementationClient {
private baseUrl: string; private baseUrl: string;
@ -31,7 +33,7 @@ class ServiceImplementationClient {
const data = await response.json(); const data = await response.json();
return data as T; return data as T;
} catch (error: any) { } catch (error: any) {
console.error('GET request failed:', error.message || error); logger.error('GET request failed:', error.message || error);
throw new Error(`Network request failed: ${error.message || error}`); throw new Error(`Network request failed: ${error.message || error}`);
} }
} }
@ -56,7 +58,7 @@ class ServiceImplementationClient {
const responseData = await response.json(); const responseData = await response.json();
return responseData as T; return responseData as T;
} catch (error: any) { } catch (error: any) {
console.error('POST request failed:', error.message || error); logger.error('POST request failed:', error.message || error);
throw new Error(`Network request failed: ${error.message || error}`); throw new Error(`Network request failed: ${error.message || error}`);
} }
} }

@ -1,5 +1,7 @@
// 配置服务 // 配置服务
import { logger } from '../utils/logger';
// 获取数据源列表 // 获取数据源列表
export const fetchDataSources = async () => { export const fetchDataSources = async () => {
// 模拟API请求延迟 // 模拟API请求延迟
@ -19,7 +21,7 @@ export const fetchDataSources = async () => {
export const saveDataSource = async (data: any) => { export const saveDataSource = async (data: any) => {
// 模拟API请求延迟 // 模拟API请求延迟
await new Promise(resolve => setTimeout(resolve, 300)); await new Promise(resolve => setTimeout(resolve, 300));
console.log('保存数据源配置:', data); logger.log('保存数据源配置:', data);
return data; return data;
}; };
@ -40,7 +42,7 @@ export const fetchAIModels = async () => {
export const saveAIModel = async (data: any) => { export const saveAIModel = async (data: any) => {
// 模拟API请求延迟 // 模拟API请求延迟
await new Promise(resolve => setTimeout(resolve, 300)); await new Promise(resolve => setTimeout(resolve, 300));
console.log('保存AI模型配置:', data); logger.log('保存AI模型配置:', data);
return data; return data;
}; };
@ -60,6 +62,6 @@ export const fetchSystemSettings = async () => {
export const saveSystemSettings = async (data: any) => { export const saveSystemSettings = async (data: any) => {
// 模拟API请求延迟 // 模拟API请求延迟
await new Promise(resolve => setTimeout(resolve, 200)); await new Promise(resolve => setTimeout(resolve, 200));
console.log('保存系统设置:', data); logger.log('保存系统设置:', data);
return data; return data;
}; };

@ -1,6 +1,7 @@
// 数据源工厂类 // 数据源工厂类
import { DataSource } from './DataSource'; import { DataSource } from './DataSource';
import { TQDataSource } from './TQDataSource'; import { TQDataSource } from './TQDataSource';
import { logger } from '../../utils/logger';
// 数据源类型 // 数据源类型
export enum DataSourceType { export enum DataSourceType {
@ -16,7 +17,7 @@ export class DataSourceFactory {
// 获取数据源实例 // 获取数据源实例
static async getDataSource(type: DataSourceType = DataSourceType.TQSDK, config: any = {}): Promise<DataSource> { static async getDataSource(type: DataSourceType = DataSourceType.TQSDK, config: any = {}): Promise<DataSource> {
console.log('获取数据源实例:', type); logger.log('获取数据源实例:', type);
if (!this.dataSources.has(type)) { if (!this.dataSources.has(type)) {
let dataSource: DataSource; let dataSource: DataSource;
@ -51,9 +52,9 @@ export class DataSourceFactory {
for (const [type, dataSource] of this.dataSources) { for (const [type, dataSource] of this.dataSources) {
try { try {
await dataSource.close(); await dataSource.close();
console.log(`数据源${type}已关闭`); logger.log(`数据源${type}已关闭`);
} catch (error) { } catch (error) {
console.error(`关闭数据源${type}失败:`, error); logger.error(`关闭数据源${type}失败:`, error);
} }
} }
this.dataSources.clear(); this.dataSources.clear();

@ -1,6 +1,7 @@
// 模拟数据源实现 // 模拟数据源实现
import { DataSource } from './DataSource'; import { DataSource } from './DataSource';
import { futuresList, generateFuturesOverview, generateFutureData, generateKlineData, riskAlerts } from '../../utils/mockData'; import { futuresList, generateFuturesOverview, generateFutureData, generateKlineData, riskAlerts } from '../../utils/mockData';
import { logger } from '../../utils/logger';
export class MockDataSource implements DataSource { export class MockDataSource implements DataSource {
private initialized: boolean = false; private initialized: boolean = false;
@ -8,7 +9,7 @@ export class MockDataSource implements DataSource {
async initialize(): Promise<boolean> { async initialize(): Promise<boolean> {
// 模拟初始化 // 模拟初始化
this.initialized = true; this.initialized = true;
console.log('模拟数据源初始化成功'); logger.log('模拟数据源初始化成功');
return true; return true;
} }
@ -157,7 +158,7 @@ export class MockDataSource implements DataSource {
async close(): Promise<void> { async close(): Promise<void> {
// 模拟关闭 // 模拟关闭
this.initialized = false; this.initialized = false;
console.log('模拟数据源已关闭'); logger.log('模拟数据源已关闭');
} }
// 根据合约代码获取交易所 // 根据合约代码获取交易所

@ -1,6 +1,7 @@
import { spawn } from 'child_process'; import { spawn } from 'child_process';
import * as path from 'path'; import * as path from 'path';
import { config } from '../../config'; import { config } from '../../config';
import { logger } from '../../utils/logger';
class PythonServiceManager { class PythonServiceManager {
private pythonProcess: any = null; private pythonProcess: any = null;
@ -8,7 +9,7 @@ class PythonServiceManager {
async start(): Promise<boolean> { async start(): Promise<boolean> {
if (this.isRunning) { if (this.isRunning) {
console.log('Python服务已经在运行'); logger.log('Python服务已经在运行');
return true; return true;
} }
@ -19,7 +20,7 @@ class PythonServiceManager {
// 从配置中读取端口默认3007 // 从配置中读取端口默认3007
const port = config.dataSource?.tqsdk?.pythonPort || 3007; const port = config.dataSource?.tqsdk?.pythonPort || 3007;
console.log(`启动Python TQAPI服务端口: ${port}...`); logger.log(`启动Python TQAPI服务端口: ${port}...`);
// 启动Python服务传递端口参数 // 启动Python服务传递端口参数
this.pythonProcess = spawn('python', [pythonServicePath, '--port', port.toString()], { this.pythonProcess = spawn('python', [pythonServicePath, '--port', port.toString()], {
@ -29,12 +30,12 @@ class PythonServiceManager {
}); });
this.pythonProcess.on('error', (error: any) => { this.pythonProcess.on('error', (error: any) => {
console.error('启动Python服务失败:', error); logger.error('启动Python服务失败:', error);
this.isRunning = false; this.isRunning = false;
}); });
this.pythonProcess.on('exit', (code: number, signal: string) => { this.pythonProcess.on('exit', (code: number, signal: string) => {
console.log(`Python服务退出代码: ${code}, 信号: ${signal}`); logger.log(`Python服务退出代码: ${code}, 信号: ${signal}`);
this.isRunning = false; this.isRunning = false;
}); });
@ -42,10 +43,10 @@ class PythonServiceManager {
await new Promise(resolve => setTimeout(resolve, 2000)); await new Promise(resolve => setTimeout(resolve, 2000));
this.isRunning = true; this.isRunning = true;
console.log('Python TQAPI服务启动成功'); logger.log('Python TQAPI服务启动成功');
return true; return true;
} catch (error) { } catch (error) {
console.error('启动Python服务时出错:', error); logger.error('启动Python服务时出错:', error);
this.isRunning = false; this.isRunning = false;
return false; return false;
} }
@ -54,23 +55,23 @@ class PythonServiceManager {
stop(): void { stop(): void {
if (this.pythonProcess) { if (this.pythonProcess) {
try { try {
console.log('停止Python TQAPI服务...'); logger.log('停止Python TQAPI服务...');
// 发送终止信号 // 发送终止信号
this.pythonProcess.kill(); this.pythonProcess.kill();
// 等待进程退出 // 等待进程退出
this.pythonProcess.on('exit', (code: number, signal: string) => { this.pythonProcess.on('exit', (code: number, signal: string) => {
console.log(`Python服务退出代码: ${code}, 信号: ${signal}`); logger.log(`Python服务退出代码: ${code}, 信号: ${signal}`);
}); });
this.pythonProcess = null; this.pythonProcess = null;
this.isRunning = false; this.isRunning = false;
console.log('Python TQAPI服务已停止'); logger.log('Python TQAPI服务已停止');
} catch (error) { } catch (error) {
console.error('停止Python服务时出错:', error); logger.error('停止Python服务时出错:', error);
this.pythonProcess = null; this.pythonProcess = null;
this.isRunning = false; this.isRunning = false;
} }
} else { } else {
console.log('Python服务未运行无需停止'); logger.log('Python服务未运行无需停止');
} }
} }

@ -1,5 +1,6 @@
// TQAPI数据源实现 - 使用Python服务 // TQAPI数据源实现 - 使用Python服务
import { DataSource } from './DataSource'; import { DataSource } from './DataSource';
import { logger } from '../../utils/logger';
// 简化的HTTP客户端 // 简化的HTTP客户端
class HttpClient { class HttpClient {
@ -16,18 +17,18 @@ class HttpClient {
url += `?${queryString}`; url += `?${queryString}`;
} }
console.log('发送GET请求:', url); logger.log('发送GET请求:', url);
try { try {
// 设置20秒超时 // 设置20秒超时
const controller = new AbortController(); const controller = new AbortController();
const timeoutId = setTimeout(() => { const timeoutId = setTimeout(() => {
console.error('GET请求超时正在中止请求...'); logger.error('GET请求超时正在中止请求...');
controller.abort(); controller.abort();
}, 20000); }, 20000);
try { try {
console.log('正在发送GET请求...'); logger.log('正在发送GET请求...');
const start = Date.now(); const start = Date.now();
const response = await fetch(url, { const response = await fetch(url, {
method: 'GET', method: 'GET',
@ -37,44 +38,44 @@ class HttpClient {
signal: controller.signal signal: controller.signal
}); });
const end = Date.now(); const end = Date.now();
console.log(`GET请求完成耗时: ${end - start}ms`); logger.log(`GET请求完成耗时: ${end - start}ms`);
console.log('GET请求响应状态:', response.status); logger.log('GET请求响应状态:', response.status);
if (!response.ok) { if (!response.ok) {
const errorText = await response.text(); const errorText = await response.text();
console.error('GET请求失败:', errorText); logger.error('GET请求失败:', errorText);
throw new Error(`HTTP error! status: ${response.status}, message: ${errorText}`); throw new Error(`HTTP error! status: ${response.status}, message: ${errorText}`);
} }
console.log('正在解析GET响应数据...'); logger.log('正在解析GET响应数据...');
const data = await response.json(); const data = await response.json();
console.log('GET请求响应数据:', data); logger.log('GET请求响应数据:', data);
return data as T; return data as T;
} finally { } finally {
clearTimeout(timeoutId); clearTimeout(timeoutId);
} }
} catch (error: any) { } catch (error: any) {
console.error('GET请求网络错误:', error.message || error); logger.error('GET请求网络错误:', error.message || error);
console.error('错误详情:', error); logger.error('错误详情:', error);
console.error('错误堆栈:', error.stack); logger.error('错误堆栈:', error.stack);
throw new Error(`网络请求失败: ${error.message || error}`); throw new Error(`网络请求失败: ${error.message || error}`);
} }
} }
async post<T>(endpoint: string, data?: any): Promise<T> { async post<T>(endpoint: string, data?: any): Promise<T> {
const url = `${this.baseUrl}${endpoint}`; const url = `${this.baseUrl}${endpoint}`;
console.log('发送POST请求:', url, '数据:', data); logger.log('发送POST请求:', url, '数据:', data);
try { try {
// 设置20秒超时 // 设置20秒超时
const controller = new AbortController(); const controller = new AbortController();
const timeoutId = setTimeout(() => { const timeoutId = setTimeout(() => {
console.error('POST请求超时正在中止请求...'); logger.error('POST请求超时正在中止请求...');
controller.abort(); controller.abort();
}, 20000); }, 20000);
try { try {
console.log('正在发送请求...'); logger.log('正在发送请求...');
const start = Date.now(); const start = Date.now();
const response = await fetch(url, { const response = await fetch(url, {
method: 'POST', method: 'POST',
@ -85,26 +86,26 @@ class HttpClient {
signal: controller.signal signal: controller.signal
}); });
const end = Date.now(); const end = Date.now();
console.log(`请求完成,耗时: ${end - start}ms`); logger.log(`请求完成,耗时: ${end - start}ms`);
console.log('POST请求响应状态:', response.status); logger.log('POST请求响应状态:', response.status);
if (!response.ok) { if (!response.ok) {
const errorText = await response.text(); const errorText = await response.text();
console.error('POST请求失败:', errorText); logger.error('POST请求失败:', errorText);
throw new Error(`HTTP error! status: ${response.status}, message: ${errorText}`); throw new Error(`HTTP error! status: ${response.status}, message: ${errorText}`);
} }
console.log('正在解析响应数据...'); logger.log('正在解析响应数据...');
const responseData = await response.json(); const responseData = await response.json();
console.log('POST请求响应数据:', responseData); logger.log('POST请求响应数据:', responseData);
return responseData as T; return responseData as T;
} finally { } finally {
clearTimeout(timeoutId); clearTimeout(timeoutId);
} }
} catch (error: any) { } catch (error: any) {
console.error('POST请求网络错误:', error.message || error); logger.error('POST请求网络错误:', error.message || error);
console.error('错误详情:', error); logger.error('错误详情:', error);
console.error('错误堆栈:', error.stack); logger.error('错误堆栈:', error.stack);
throw new Error(`网络请求失败: ${error.message || error}`); throw new Error(`网络请求失败: ${error.message || error}`);
} }
} }
@ -123,7 +124,7 @@ export class TQDataSource implements DataSource {
}; };
constructor(config: any = {}) { constructor(config: any = {}) {
console.log('使用TQAPI数据源初始化...'); logger.log('使用TQAPI数据源初始化...');
// 从配置中读取端口默认8001 // 从配置中读取端口默认8001
const port = config.pythonPort || 8001; const port = config.pythonPort || 8001;
this.config = { this.config = {
@ -134,26 +135,26 @@ export class TQDataSource implements DataSource {
maxConnections: config.maxConnections || 5, maxConnections: config.maxConnections || 5,
pythonServiceUrl: config.pythonServiceUrl || `http://127.0.0.1:${port}/api` pythonServiceUrl: config.pythonServiceUrl || `http://127.0.0.1:${port}/api`
}; };
console.log('TQAPI数据源配置:', this.config); logger.log('TQAPI数据源配置:', this.config);
// 测试Python服务URL是否正确 // 测试Python服务URL是否正确
console.log('测试Python服务URL:', this.config.pythonServiceUrl); logger.log('测试Python服务URL:', this.config.pythonServiceUrl);
this.httpClient = new HttpClient(this.config.pythonServiceUrl!); this.httpClient = new HttpClient(this.config.pythonServiceUrl!);
} }
async initialize(): Promise<boolean> { async initialize(): Promise<boolean> {
try { try {
console.log('开始初始化TQAPI数据源...'); logger.log('开始初始化TQAPI数据源...');
console.log('Python服务URL:', this.config.pythonServiceUrl); logger.log('Python服务URL:', this.config.pythonServiceUrl);
console.log('连接参数:', { logger.log('连接参数:', {
username: this.config.username ? '***' : '', username: this.config.username ? '***' : '',
password: this.config.password ? '***' : '' password: this.config.password ? '***' : ''
}); });
// 先测试Python服务是否可达 // 先测试Python服务是否可达
console.log('测试Python服务是否可达...'); logger.log('测试Python服务是否可达...');
try { try {
const testUrl = `${this.config.pythonServiceUrl}/../health`; const testUrl = `${this.config.pythonServiceUrl}/../health`;
console.log('测试URL:', testUrl); logger.log('测试URL:', testUrl);
// 使用AbortController设置超时 // 使用AbortController设置超时
const controller = new AbortController(); const controller = new AbortController();
const timeoutId = setTimeout(() => controller.abort(), 10000); const timeoutId = setTimeout(() => controller.abort(), 10000);
@ -162,21 +163,21 @@ export class TQDataSource implements DataSource {
method: 'GET', method: 'GET',
signal: controller.signal signal: controller.signal
}); });
console.log('Python服务健康检查响应:', testResponse.status); logger.log('Python服务健康检查响应:', testResponse.status);
if (testResponse.ok) { if (testResponse.ok) {
console.log('Python服务可达'); logger.log('Python服务可达');
} else { } else {
console.error('Python服务不可达状态码:', testResponse.status); logger.error('Python服务不可达状态码:', testResponse.status);
} }
} finally { } finally {
clearTimeout(timeoutId); clearTimeout(timeoutId);
} }
} catch (error: any) { } catch (error: any) {
console.error('Python服务健康检查失败:', error.message || error); logger.error('Python服务健康检查失败:', error.message || error);
} }
// 连接到天勤服务器 // 连接到天勤服务器
console.log('连接到天勤服务器...'); logger.log('连接到天勤服务器...');
try { try {
const response = await this.httpClient.post<any>('/connect', { const response = await this.httpClient.post<any>('/connect', {
@ -184,24 +185,24 @@ export class TQDataSource implements DataSource {
password: this.config.password password: this.config.password
}); });
console.log('连接响应:', response); logger.log('连接响应:', response);
if (response.success) { if (response.success) {
console.log('TQAPI连接成功'); logger.log('TQAPI连接成功');
this.initialized = true; this.initialized = true;
return true; return true;
} else { } else {
console.error('TQAPI连接失败:', response.message); logger.error('TQAPI连接失败:', response.message);
this.initialized = false; this.initialized = false;
return false; return false;
} }
} catch (error: any) { } catch (error: any) {
console.error('连接请求失败:', error.message || error); logger.error('连接请求失败:', error.message || error);
console.error('错误详情:', error); logger.error('错误详情:', error);
throw error; throw error;
} }
} catch (error) { } catch (error) {
console.error('TQAPI数据源初始化失败:', error); logger.error('TQAPI数据源初始化失败:', error);
this.initialized = false; this.initialized = false;
return false; return false;
} }
@ -213,18 +214,18 @@ export class TQDataSource implements DataSource {
} }
try { try {
console.log('获取合约列表...'); logger.log('获取合约列表...');
const response = await this.httpClient.get<any>('/contracts'); const response = await this.httpClient.get<any>('/contracts');
if (response.success && Array.isArray(response.data)) { if (response.success && Array.isArray(response.data)) {
console.log('获取合约列表成功,数量:', response.data.length); logger.log('获取合约列表成功,数量:', response.data.length);
return response.data; return response.data;
} else { } else {
console.error('获取合约列表失败:', response.message); logger.error('获取合约列表失败:', response.message);
return []; return [];
} }
} catch (error) { } catch (error) {
console.error('获取合约列表失败:', error); logger.error('获取合约列表失败:', error);
throw error; throw error;
} }
} }
@ -235,18 +236,18 @@ export class TQDataSource implements DataSource {
} }
try { try {
console.log(`获取合约${symbol}详情...`); logger.log(`获取合约${symbol}详情...`);
const response = await this.httpClient.get<any>(`/contract/${symbol}`); const response = await this.httpClient.get<any>(`/contract/${symbol}`);
if (response.success) { if (response.success) {
console.log(`获取合约${symbol}详情成功`); logger.log(`获取合约${symbol}详情成功`);
return response.data; return response.data;
} else { } else {
console.error(`获取合约${symbol}详情失败:`, response.message); logger.error(`获取合约${symbol}详情失败:`, response.message);
throw new Error(`获取合约${symbol}详情失败`); throw new Error(`获取合约${symbol}详情失败`);
} }
} catch (error) { } catch (error) {
console.error(`获取合约${symbol}详情失败:`, error); logger.error(`获取合约${symbol}详情失败:`, error);
throw error; throw error;
} }
} }
@ -257,7 +258,7 @@ export class TQDataSource implements DataSource {
} }
try { try {
console.log('开始获取K线数据:', { logger.log('开始获取K线数据:', {
symbol: symbol, symbol: symbol,
period: period, period: period,
count: count count: count
@ -267,10 +268,10 @@ export class TQDataSource implements DataSource {
let contractSymbol = symbol; let contractSymbol = symbol;
if (!contractSymbol.includes('.')) { if (!contractSymbol.includes('.')) {
// 如果没有交易所前缀,尝试添加默认交易所 // 如果没有交易所前缀,尝试添加默认交易所
console.warn('合约代码缺少交易所前缀,尝试添加默认交易所'); logger.warn('合约代码缺少交易所前缀,尝试添加默认交易所');
contractSymbol = `SHFE.${contractSymbol}`; contractSymbol = `SHFE.${contractSymbol}`;
} }
console.log('使用的合约代码:', contractSymbol); logger.log('使用的合约代码:', contractSymbol);
const response = await this.httpClient.get<any>('/klines/' + contractSymbol, { const response = await this.httpClient.get<any>('/klines/' + contractSymbol, {
period: period, period: period,
@ -278,14 +279,14 @@ export class TQDataSource implements DataSource {
}); });
if (response.success && Array.isArray(response.data)) { if (response.success && Array.isArray(response.data)) {
console.log('获取K线数据成功长度:', response.data.length); logger.log('获取K线数据成功长度:', response.data.length);
return response.data; return response.data;
} else { } else {
console.error('获取K线数据失败:', response.message); logger.error('获取K线数据失败:', response.message);
return []; return [];
} }
} catch (error) { } catch (error) {
console.error(`获取合约${symbol}K线数据失败:`, error); logger.error(`获取合约${symbol}K线数据失败:`, error);
throw error; throw error;
} }
} }
@ -296,33 +297,33 @@ export class TQDataSource implements DataSource {
} }
try { try {
console.log(`获取合约${symbol}实时行情数据...`); logger.log(`获取合约${symbol}实时行情数据...`);
// 确保合约代码格式正确 // 确保合约代码格式正确
let contractSymbol = symbol; let contractSymbol = symbol;
if (!contractSymbol.includes('.')) { if (!contractSymbol.includes('.')) {
// 如果没有交易所前缀,尝试添加默认交易所 // 如果没有交易所前缀,尝试添加默认交易所
console.warn('合约代码缺少交易所前缀,尝试添加默认交易所'); logger.warn('合约代码缺少交易所前缀,尝试添加默认交易所');
contractSymbol = `SHFE.${contractSymbol}`; contractSymbol = `SHFE.${contractSymbol}`;
} }
console.log('使用的合约代码:', contractSymbol); logger.log('使用的合约代码:', contractSymbol);
console.log('正在发送GET请求到:', `/tick/${contractSymbol}`); logger.log('正在发送GET请求到:', `/tick/${contractSymbol}`);
const start = Date.now(); const start = Date.now();
const response = await this.httpClient.get<any>(`/tick/${contractSymbol}`); const response = await this.httpClient.get<any>(`/tick/${contractSymbol}`);
const end = Date.now(); const end = Date.now();
console.log(`GET请求完成耗时: ${end - start}ms`); logger.log(`GET请求完成耗时: ${end - start}ms`);
console.log('响应数据:', response); logger.log('响应数据:', response);
if (response.success) { if (response.success) {
console.log(`获取合约${symbol}实时行情数据成功`); logger.log(`获取合约${symbol}实时行情数据成功`);
// 计算价格变化 // 计算价格变化
const tickData = response.data; const tickData = response.data;
tickData.price_change = tickData.last_price - (tickData.pre_close || 0); tickData.price_change = tickData.last_price - (tickData.pre_close || 0);
console.log('计算价格变化后的数据:', tickData); logger.log('计算价格变化后的数据:', tickData);
return tickData; return tickData;
} else { } else {
console.error(`获取合约${symbol}实时行情数据失败:`, response.message); logger.error(`获取合约${symbol}实时行情数据失败:`, response.message);
// 返回默认数据,避免整个请求失败 // 返回默认数据,避免整个请求失败
return { return {
last_price: 0, last_price: 0,
@ -341,7 +342,7 @@ export class TQDataSource implements DataSource {
}; };
} }
} catch (error) { } catch (error) {
console.error(`获取合约${symbol}实时行情数据失败:`, error); logger.error(`获取合约${symbol}实时行情数据失败:`, error);
// 返回默认数据,避免整个请求失败 // 返回默认数据,避免整个请求失败
return { return {
last_price: 0, last_price: 0,
@ -393,12 +394,12 @@ export class TQDataSource implements DataSource {
open_interest: open_interest open_interest: open_interest
}); });
} catch (error) { } catch (error) {
console.error(`获取合约${contract.symbol}行情失败:`, error); logger.error(`获取合约${contract.symbol}行情失败:`, error);
} }
} }
return overview; return overview;
} catch (error) { } catch (error) {
console.error('获取市场概览失败:', error); logger.error('获取市场概览失败:', error);
throw error; throw error;
} }
} }
@ -410,29 +411,29 @@ export class TQDataSource implements DataSource {
try { try {
// 目前Python服务未实现此功能 // 目前Python服务未实现此功能
console.warn('TQAPI服务暂未实现历史成交数据获取功能'); logger.warn('TQAPI服务暂未实现历史成交数据获取功能');
return []; return [];
} catch (error) { } catch (error) {
console.error(`获取合约${symbol}历史成交数据失败:`, error); logger.error(`获取合约${symbol}历史成交数据失败:`, error);
throw error; throw error;
} }
} }
async close(): Promise<void> { async close(): Promise<void> {
try { try {
console.log('关闭TQAPI连接...'); logger.log('关闭TQAPI连接...');
const response = await this.httpClient.post<any>('/disconnect'); const response = await this.httpClient.post<any>('/disconnect');
if (response.success) { if (response.success) {
console.log('TQAPI连接已关闭'); logger.log('TQAPI连接已关闭');
} else { } else {
console.error('关闭TQAPI连接失败:', response.message); logger.error('关闭TQAPI连接失败:', response.message);
} }
} catch (error) { } catch (error) {
console.error('关闭TQAPI连接失败:', error); logger.error('关闭TQAPI连接失败:', error);
} finally { } finally {
this.initialized = false; this.initialized = false;
console.log('TQAPI数据源已关闭'); logger.log('TQAPI数据源已关闭');
} }
} }
} }

@ -3,6 +3,7 @@ import { DataSourceFactory, DataSourceType } from './datasource/DataSourceFactor
import { futuresList, generateFuturesOverview, generateFutureData, generateKlineData, riskAlerts } from '../utils/mockData'; import { futuresList, generateFuturesOverview, generateFutureData, generateKlineData, riskAlerts } from '../utils/mockData';
import { config } from '../config'; import { config } from '../config';
import { serviceImplementationClient } from './ServiceImplementationClient'; import { serviceImplementationClient } from './ServiceImplementationClient';
import { logger } from '../utils/logger';
// 获取数据源配置 // 获取数据源配置
const getDataSourceConfig = () => { const getDataSourceConfig = () => {
@ -15,10 +16,10 @@ export const fetchMarketOverview = async () => {
try { try {
// 首先尝试使用 service_implementation API // 首先尝试使用 service_implementation API
try { try {
console.log('尝试使用 service_implementation API 获取市场概览...'); logger.log('尝试使用 service_implementation API 获取市场概览...');
// 先获取合约列表 // 先获取合约列表
console.log('获取合约列表...'); logger.log('获取合约列表...');
const contractsResponse = await serviceImplementationClient.getContracts(); const contractsResponse = await serviceImplementationClient.getContracts();
const allContracts = contractsResponse.data; const allContracts = contractsResponse.data;
@ -38,7 +39,7 @@ export const fetchMarketOverview = async () => {
// 转换为数组 // 转换为数组
const contractList = Array.from(uniqueContracts.values()); const contractList = Array.from(uniqueContracts.values());
console.log(`获取到 ${contractList.length} 个独特品种`); logger.log(`获取到 ${contractList.length} 个独特品种`);
// 使用获取到的合约列表 // 使用获取到的合约列表
const overview = []; const overview = [];
@ -48,19 +49,24 @@ export const fetchMarketOverview = async () => {
const symbol = `${future.code}${new Date().getFullYear().toString().slice(-2)}05`; const symbol = `${future.code}${new Date().getFullYear().toString().slice(-2)}05`;
// 获取合约详情 // 获取合约详情
console.log(`获取合约${symbol}详情...`); logger.log(`获取合约${symbol}详情...`);
const contractsResponse = await serviceImplementationClient.getContracts(future.exchange, future.code); const contractsResponse = await serviceImplementationClient.getContracts(future.exchange, future.code);
const contract = contractsResponse.data.find((c: any) => c.symbol === symbol); const contract = contractsResponse.data.find((c: any) => c.symbol === symbol);
if (!contract) { if (!contract) {
console.warn(`合约${symbol}不存在,跳过`); logger.warn(`合约${symbol}不存在,跳过`);
continue; continue;
} }
// 更新未来合约的中文名称
future.name = `${contract.product_name || future.name}`;
// 获取分析数据 // 获取分析数据
console.log(`分析合约${symbol}...`); logger.log(`分析合约${symbol}...`);
logger.log(`before analyzeMarket: symbol=${symbol}time=${new Date().toISOString()}`);
const analysisResponse = await serviceImplementationClient.analyzeMarket(symbol); const analysisResponse = await serviceImplementationClient.analyzeMarket(symbol);
const analysis = analysisResponse.data; const analysis = analysisResponse.data;
logger.log(`after analyzeMarket: symbol=${symbol}, analysis=${JSON.stringify(analysis)}, time=${new Date().toISOString()}`);
overview.push({ overview.push({
code: future.code, code: future.code,
@ -108,26 +114,26 @@ export const fetchMarketOverview = async () => {
aiAnalysis: `趋势:${analysis.trend || '中性'} | 概率:${analysis.probability ? Math.round(analysis.probability * 100) : 50}% | 方向:${analysis.direction || '观望'}` aiAnalysis: `趋势:${analysis.trend || '中性'} | 概率:${analysis.probability ? Math.round(analysis.probability * 100) : 50}% | 方向:${analysis.direction || '观望'}`
}); });
} catch (error) { } catch (error) {
console.error(`获取合约${future.code}行情失败:`, error); logger.error(`获取合约${future.code}行情失败:`, error);
// 跳过获取失败的合约 // 跳过获取失败的合约
continue; continue;
} }
} }
if (overview.length > 0) { if (overview.length > 0) {
console.log('使用 service_implementation API 获取市场概览成功'); logger.log('使用 service_implementation API 获取市场概览成功');
return overview; return overview;
} }
console.warn('service_implementation API 未返回数据,尝试使用其他数据源'); logger.warn('service_implementation API 未返回数据,尝试使用其他数据源');
} catch (error) { } catch (error) {
console.error('service_implementation API 获取失败:', error); logger.error('service_implementation API 获取失败:', error);
// service_implementation API 失败,尝试使用其他数据源 // service_implementation API 失败,尝试使用其他数据源
} }
// 获取数据源配置 // 获取数据源配置
const dataSourceConfig = getDataSourceConfig(); const dataSourceConfig = getDataSourceConfig();
console.log('获取数据源配置:', dataSourceConfig); logger.log('获取数据源配置:', dataSourceConfig);
// 检查是否有可用的数据源 // 检查是否有可用的数据源
const hasAvailableDataSource = dataSourceConfig.tqsdk?.enabled || dataSourceConfig.test?.enabled; const hasAvailableDataSource = dataSourceConfig.tqsdk?.enabled || dataSourceConfig.test?.enabled;
if (!hasAvailableDataSource) { if (!hasAvailableDataSource) {
@ -194,7 +200,7 @@ export const fetchMarketOverview = async () => {
aiAnalysis: `MACD:金叉向上 | RSI:${Math.floor(Math.random() * 80) + 10}(中性) | 布林带:中轨附近` aiAnalysis: `MACD:金叉向上 | RSI:${Math.floor(Math.random() * 80) + 10}(中性) | 布林带:中轨附近`
}); });
} catch (error) { } catch (error) {
console.error(`获取合约${future.code}行情失败:`, error); logger.error(`获取合约${future.code}行情失败:`, error);
// 跳过获取失败的合约 // 跳过获取失败的合约
continue; continue;
} }
@ -202,10 +208,10 @@ export const fetchMarketOverview = async () => {
return overview; return overview;
} catch (error) { } catch (error) {
console.error('TQSDK数据源获取失败:', error); logger.error('TQSDK数据源获取失败:', error);
// TQSDK数据源失败尝试使用测试数据源 // TQSDK数据源失败尝试使用测试数据源
if (dataSourceConfig.test?.enabled) { if (dataSourceConfig.test?.enabled) {
console.log('切换到测试数据源'); logger.log('切换到测试数据源');
// 启用了测试数据源,使用测试数据 // 启用了测试数据源,使用测试数据
await new Promise(resolve => setTimeout(resolve, 300)); await new Promise(resolve => setTimeout(resolve, 300));
return generateFuturesOverview(); return generateFuturesOverview();
@ -216,7 +222,7 @@ export const fetchMarketOverview = async () => {
} }
} else if (dataSourceConfig.test?.enabled) { } else if (dataSourceConfig.test?.enabled) {
// 直接使用测试数据源 // 直接使用测试数据源
console.log('使用测试数据源'); logger.log('使用测试数据源');
await new Promise(resolve => setTimeout(resolve, 300)); await new Promise(resolve => setTimeout(resolve, 300));
return generateFuturesOverview(); return generateFuturesOverview();
} else { } else {
@ -224,7 +230,7 @@ export const fetchMarketOverview = async () => {
throw new Error('无可用数据源,请在管理配置中启用至少一个数据源'); throw new Error('无可用数据源,请在管理配置中启用至少一个数据源');
} }
} catch (error) { } catch (error) {
console.error('获取市场概览失败:', error); logger.error('获取市场概览失败:', error);
// 直接返回友好的错误提示 // 直接返回友好的错误提示
throw new Error(error instanceof Error ? error.message : '获取市场概览失败,请检查数据源配置'); throw new Error(error instanceof Error ? error.message : '获取市场概览失败,请检查数据源配置');
} }
@ -243,26 +249,31 @@ export const fetchMarketDetail = async (symbol: string) => {
// 首先尝试使用 service_implementation API // 首先尝试使用 service_implementation API
try { try {
console.log('尝试使用 service_implementation API 获取品种详情...'); logger.log('尝试使用 service_implementation API 获取品种详情...');
// 构建合约符号(使用大写代码,因为 service_implementation API 期望大写) // 构建合约符号(使用大写代码,因为 service_implementation API 期望大写)
const contractSymbol = `${future.code}${new Date().getFullYear().toString().slice(-2)}05`; const contractSymbol = `${future.code}${new Date().getFullYear().toString().slice(-2)}05`;
// 获取合约详情 // 获取合约详情
console.log(`获取合约${contractSymbol}详情...`); logger.log(`获取合约${contractSymbol}详情...`);
const contractsResponse = await serviceImplementationClient.getContracts(future.exchange, future.code); const contractsResponse = await serviceImplementationClient.getContracts(future.exchange, future.code);
const contract = contractsResponse.data.find((c: any) => c.symbol === contractSymbol); const contract = contractsResponse.data.find((c: any) => c.symbol === contractSymbol);
if (!contract) { if (!contract) {
console.warn(`合约${contractSymbol}不存在,尝试使用其他数据源`); logger.warn(`合约${contractSymbol}不存在,尝试使用其他数据源`);
} else { } else {
// 更新未来合约的中文名称
future.name = `${contract.product_name || future.name} - ${future.code}`;
// 获取分析数据 // 获取分析数据
console.log(`分析合约${contractSymbol}...`); logger.log(`分析合约${contractSymbol}...`);
logger.log(`before analyzeMarket: symbol=${contractSymbol}time=${new Date().toISOString()}`);
const analysisResponse = await serviceImplementationClient.analyzeMarket(contractSymbol); const analysisResponse = await serviceImplementationClient.analyzeMarket(contractSymbol);
const analysis = analysisResponse.data; const analysis = analysisResponse.data;
logger.log(`after analyzeMarket: symbol=${contractSymbol}time=${new Date().toISOString()}`);
// 获取交易建议 // 获取交易建议
console.log(`获取合约${contractSymbol}交易建议...`); logger.log(`获取合约${contractSymbol}交易建议...`);
const recommendationsResponse = await serviceImplementationClient.getRecommendations(contractSymbol); const recommendationsResponse = await serviceImplementationClient.getRecommendations(contractSymbol);
const recommendation = recommendationsResponse.data[0]; const recommendation = recommendationsResponse.data[0];
@ -322,13 +333,13 @@ export const fetchMarketDetail = async (symbol: string) => {
aiAnalysis: `趋势:${analysis.trend || '中性'} | 概率:${analysis.probability ? Math.round(analysis.probability * 100) : 50}% | 方向:${analysis.direction || '观望'}` aiAnalysis: `趋势:${analysis.trend || '中性'} | 概率:${analysis.probability ? Math.round(analysis.probability * 100) : 50}% | 方向:${analysis.direction || '观望'}`
}; };
console.log('使用 service_implementation API 获取品种详情成功'); logger.log('使用 service_implementation API 获取品种详情成功');
return result; return result;
} }
console.warn('service_implementation API 未返回数据,尝试使用其他数据源'); logger.warn('service_implementation API 未返回数据,尝试使用其他数据源');
} catch (error) { } catch (error) {
console.error('service_implementation API 获取失败:', error); logger.error('service_implementation API 获取失败:', error);
// service_implementation API 失败,尝试使用其他数据源 // service_implementation API 失败,尝试使用其他数据源
} }
@ -408,10 +419,10 @@ export const fetchMarketDetail = async (symbol: string) => {
aiAnalysis: `MACD:金叉向上 | RSI:${Math.floor(Math.random() * 80) + 10}(中性) | 布林带:中轨附近` aiAnalysis: `MACD:金叉向上 | RSI:${Math.floor(Math.random() * 80) + 10}(中性) | 布林带:中轨附近`
}; };
} catch (error) { } catch (error) {
console.error('TQSDK数据源获取失败:', error); logger.error('TQSDK数据源获取失败:', error);
// TQSDK数据源失败尝试使用测试数据源 // TQSDK数据源失败尝试使用测试数据源
if (dataSourceConfig.test?.enabled) { if (dataSourceConfig.test?.enabled) {
console.log('切换到测试数据源'); logger.log('切换到测试数据源');
// 启用了测试数据源,使用测试数据 // 启用了测试数据源,使用测试数据
await new Promise(resolve => setTimeout(resolve, 200)); await new Promise(resolve => setTimeout(resolve, 200));
return generateFutureData(symbol, future.name); return generateFutureData(symbol, future.name);
@ -422,7 +433,7 @@ export const fetchMarketDetail = async (symbol: string) => {
} }
} else if (dataSourceConfig.test?.enabled) { } else if (dataSourceConfig.test?.enabled) {
// 直接使用测试数据源 // 直接使用测试数据源
console.log('使用测试数据源'); logger.log('使用测试数据源');
await new Promise(resolve => setTimeout(resolve, 200)); await new Promise(resolve => setTimeout(resolve, 200));
return generateFutureData(symbol, future.name); return generateFutureData(symbol, future.name);
} else { } else {
@ -430,7 +441,7 @@ export const fetchMarketDetail = async (symbol: string) => {
throw new Error('无可用数据源,请在管理配置中启用至少一个数据源'); throw new Error('无可用数据源,请在管理配置中启用至少一个数据源');
} }
} catch (error) { } catch (error) {
console.error(`获取品种${symbol}详情失败:`, error); logger.error(`获取品种${symbol}详情失败:`, error);
// 直接返回友好的错误提示 // 直接返回友好的错误提示
throw new Error(error instanceof Error ? error.message : '获取品种详情失败,请检查数据源配置'); throw new Error(error instanceof Error ? error.message : '获取品种详情失败,请检查数据源配置');
} }
@ -447,7 +458,7 @@ export const fetchKlineData = async (symbol: string, period: string) => {
// 首先尝试使用 service_implementation API // 首先尝试使用 service_implementation API
try { try {
console.log('尝试使用 service_implementation API 获取K线数据...'); logger.log('尝试使用 service_implementation API 获取K线数据...');
// 构建合约符号(使用大写代码,因为 service_implementation API 期望大写) // 构建合约符号(使用大写代码,因为 service_implementation API 期望大写)
const contractSymbol = `${future.code}${new Date().getFullYear().toString().slice(-2)}05`; const contractSymbol = `${future.code}${new Date().getFullYear().toString().slice(-2)}05`;
@ -481,7 +492,7 @@ export const fetchKlineData = async (symbol: string, period: string) => {
} }
// 获取K线数据 // 获取K线数据
console.log(`获取合约${contractSymbol}K线数据周期: ${duration}...`); logger.log(`获取合约${contractSymbol}K线数据周期: ${duration}...`);
const klineResponse = await serviceImplementationClient.getKlineData(contractSymbol, duration, 30); const klineResponse = await serviceImplementationClient.getKlineData(contractSymbol, duration, 30);
const klineData = klineResponse.data; const klineData = klineResponse.data;
@ -496,13 +507,13 @@ export const fetchKlineData = async (symbol: string, period: string) => {
volume: item.volume volume: item.volume
})); }));
console.log('使用 service_implementation API 获取K线数据成功'); logger.log('使用 service_implementation API 获取K线数据成功');
return result; return result;
} }
console.warn('service_implementation API 未返回K线数据尝试使用其他数据源'); logger.warn('service_implementation API 未返回K线数据尝试使用其他数据源');
} catch (error) { } catch (error) {
console.error('service_implementation API 获取K线数据失败:', error); logger.error('service_implementation API 获取K线数据失败:', error);
// service_implementation API 失败,尝试使用其他数据源 // service_implementation API 失败,尝试使用其他数据源
} }
@ -536,10 +547,10 @@ export const fetchKlineData = async (symbol: string, period: string) => {
volume: item.volume volume: item.volume
})); }));
} catch (error) { } catch (error) {
console.error('TQSDK数据源获取失败:', error); logger.error('TQSDK数据源获取失败:', error);
// TQSDK数据源失败尝试使用测试数据源 // TQSDK数据源失败尝试使用测试数据源
if (dataSourceConfig.test?.enabled) { if (dataSourceConfig.test?.enabled) {
console.log('切换到测试数据源'); logger.log('切换到测试数据源');
// 启用了测试数据源,使用测试数据 // 启用了测试数据源,使用测试数据
await new Promise(resolve => setTimeout(resolve, 200)); await new Promise(resolve => setTimeout(resolve, 200));
return generateKlineData(30); return generateKlineData(30);
@ -550,7 +561,7 @@ export const fetchKlineData = async (symbol: string, period: string) => {
} }
} else if (dataSourceConfig.test?.enabled) { } else if (dataSourceConfig.test?.enabled) {
// 直接使用测试数据源 // 直接使用测试数据源
console.log('使用测试数据源'); logger.log('使用测试数据源');
await new Promise(resolve => setTimeout(resolve, 200)); await new Promise(resolve => setTimeout(resolve, 200));
return generateKlineData(30); return generateKlineData(30);
} else { } else {
@ -558,7 +569,7 @@ export const fetchKlineData = async (symbol: string, period: string) => {
throw new Error('无可用数据源,请在管理配置中启用至少一个数据源'); throw new Error('无可用数据源,请在管理配置中启用至少一个数据源');
} }
} catch (error) { } catch (error) {
console.error(`获取合约${symbol}K线数据失败:`, error); logger.error(`获取合约${symbol}K线数据失败:`, error);
// 直接返回友好的错误提示 // 直接返回友好的错误提示
throw new Error(error instanceof Error ? error.message : '获取K线数据失败请检查数据源配置'); throw new Error(error instanceof Error ? error.message : '获取K线数据失败请检查数据源配置');
} }
@ -569,10 +580,10 @@ export const fetchMarketHotspots = async () => {
try { try {
// 首先尝试使用 service_implementation API // 首先尝试使用 service_implementation API
try { try {
console.log('尝试使用 service_implementation API 获取市场热点...'); logger.log('尝试使用 service_implementation API 获取市场热点...');
// 先获取合约列表 // 先获取合约列表
console.log('获取合约列表...'); logger.log('获取合约列表...');
const contractsResponse = await serviceImplementationClient.getContracts(); const contractsResponse = await serviceImplementationClient.getContracts();
const allContracts = contractsResponse.data; const allContracts = contractsResponse.data;
@ -592,7 +603,7 @@ export const fetchMarketHotspots = async () => {
// 转换为数组 // 转换为数组
const contractList = Array.from(uniqueContracts.values()); const contractList = Array.from(uniqueContracts.values());
console.log(`获取到 ${contractList.length} 个独特品种`); logger.log(`获取到 ${contractList.length} 个独特品种`);
// 使用获取到的合约列表 // 使用获取到的合约列表
const hotspots = []; const hotspots = [];
@ -602,17 +613,20 @@ export const fetchMarketHotspots = async () => {
const symbol = `${future.code}${new Date().getFullYear().toString().slice(-2)}05`; const symbol = `${future.code}${new Date().getFullYear().toString().slice(-2)}05`;
// 获取合约详情 // 获取合约详情
console.log(`获取合约${symbol}详情...`); logger.log(`获取合约${symbol}详情...`);
const contractsResponse = await serviceImplementationClient.getContracts(future.exchange, future.code); const contractsResponse = await serviceImplementationClient.getContracts(future.exchange, future.code);
const contract = contractsResponse.data.find((c: any) => c.symbol === symbol); const contract = contractsResponse.data.find((c: any) => c.symbol === symbol);
if (!contract) { if (!contract) {
console.warn(`合约${symbol}不存在,跳过`); logger.warn(`合约${symbol}不存在,跳过`);
continue; continue;
} }
// 更新未来合约的中文名称
future.name = `${contract.product_name || future.name} - ${future.code}`;
// 获取分析数据 // 获取分析数据
console.log(`分析合约${symbol}...`); logger.log(`分析合约${symbol}...`);
const analysisResponse = await serviceImplementationClient.analyzeMarket(symbol); const analysisResponse = await serviceImplementationClient.analyzeMarket(symbol);
const analysis = analysisResponse.data; const analysis = analysisResponse.data;
@ -623,7 +637,7 @@ export const fetchMarketHotspots = async () => {
volume: analysis.volume || Math.floor(Math.random() * 1000000) + 100000 volume: analysis.volume || Math.floor(Math.random() * 1000000) + 100000
}); });
} catch (error) { } catch (error) {
console.error(`获取合约${future.code}行情失败:`, error); logger.error(`获取合约${future.code}行情失败:`, error);
// 跳过获取失败的合约 // 跳过获取失败的合约
continue; continue;
} }
@ -635,13 +649,13 @@ export const fetchMarketHotspots = async () => {
.sort((a, b) => Math.abs(b.change) - Math.abs(a.change)) .sort((a, b) => Math.abs(b.change) - Math.abs(a.change))
.slice(0, 10); .slice(0, 10);
console.log('使用 service_implementation API 获取市场热点成功'); logger.log('使用 service_implementation API 获取市场热点成功');
return sortedHotspots; return sortedHotspots;
} }
console.warn('service_implementation API 未返回市场热点数据,尝试使用其他数据源'); logger.warn('service_implementation API 未返回市场热点数据,尝试使用其他数据源');
} catch (error) { } catch (error) {
console.error('service_implementation API 获取市场热点失败:', error); logger.error('service_implementation API 获取市场热点失败:', error);
// service_implementation API 失败,尝试使用其他数据源 // service_implementation API 失败,尝试使用其他数据源
} }
@ -675,7 +689,7 @@ export const fetchMarketHotspots = async () => {
volume: tick.volume volume: tick.volume
}); });
} catch (error) { } catch (error) {
console.error(`获取合约${future.code}行情失败:`, error); logger.error(`获取合约${future.code}行情失败:`, error);
// 跳过获取失败的合约 // 跳过获取失败的合约
continue; continue;
} }
@ -686,10 +700,10 @@ export const fetchMarketHotspots = async () => {
.sort((a, b) => Math.abs(b.change) - Math.abs(a.change)) .sort((a, b) => Math.abs(b.change) - Math.abs(a.change))
.slice(0, 10); .slice(0, 10);
} catch (error) { } catch (error) {
console.error('TQSDK数据源获取失败:', error); logger.error('TQSDK数据源获取失败:', error);
// TQSDK数据源失败尝试使用测试数据源 // TQSDK数据源失败尝试使用测试数据源
if (dataSourceConfig.test?.enabled) { if (dataSourceConfig.test?.enabled) {
console.log('切换到测试数据源'); logger.log('切换到测试数据源');
// 启用了测试数据源,使用测试数据 // 启用了测试数据源,使用测试数据
await new Promise(resolve => setTimeout(resolve, 200)); await new Promise(resolve => setTimeout(resolve, 200));
const overview = generateFuturesOverview(); const overview = generateFuturesOverview();
@ -710,7 +724,7 @@ export const fetchMarketHotspots = async () => {
} }
} else if (dataSourceConfig.test?.enabled) { } else if (dataSourceConfig.test?.enabled) {
// 直接使用测试数据源 // 直接使用测试数据源
console.log('使用测试数据源'); logger.log('使用测试数据源');
await new Promise(resolve => setTimeout(resolve, 200)); await new Promise(resolve => setTimeout(resolve, 200));
const overview = generateFuturesOverview(); const overview = generateFuturesOverview();
// 按涨跌幅排序返回前10个 // 按涨跌幅排序返回前10个
@ -728,7 +742,7 @@ export const fetchMarketHotspots = async () => {
throw new Error('无可用数据源,请在管理配置中启用至少一个数据源'); throw new Error('无可用数据源,请在管理配置中启用至少一个数据源');
} }
} catch (error) { } catch (error) {
console.error('获取市场热点失败:', error); logger.error('获取市场热点失败:', error);
// 直接返回友好的错误提示 // 直接返回友好的错误提示
throw new Error(error instanceof Error ? error.message : '获取市场热点失败,请检查数据源配置'); throw new Error(error instanceof Error ? error.message : '获取市场热点失败,请检查数据源配置');
} }

@ -1,5 +1,7 @@
// 推送服务 // 推送服务
import { logger } from '../utils/logger';
// 模拟推送设置存储 // 模拟推送设置存储
const pushSettings: Record<string, any> = { const pushSettings: Record<string, any> = {
'AU': { 'AU': {
@ -41,7 +43,7 @@ export const savePushSettings = async (symbol: string, settings: any) => {
await new Promise(resolve => setTimeout(resolve, 300)); await new Promise(resolve => setTimeout(resolve, 300));
pushSettings[symbol] = settings; pushSettings[symbol] = settings;
console.log('保存推送设置:', symbol, settings); logger.log('保存推送设置:', symbol, settings);
return settings; return settings;
}; };
@ -51,7 +53,7 @@ export const testPush = async (method: string, content: string) => {
// 模拟API请求延迟 // 模拟API请求延迟
await new Promise(resolve => setTimeout(resolve, 500)); await new Promise(resolve => setTimeout(resolve, 500));
console.log('测试推送:', method, content); logger.log('测试推送:', method, content);
// 模拟推送成功 // 模拟推送成功
return { success: true, message: '测试推送成功' }; return { success: true, message: '测试推送成功' };

@ -0,0 +1,150 @@
// 日志工具类
/**
*
* @returns
*/
function getCallerInfo() {
const error = new Error();
const stack = error.stack || '';
const stackLines = stack.split('\n');
// 跳过前两行Error和getCallerInfo本身的调用
let callerIndex = 2;
// 找到第一个不是logger.ts的调用者
while (callerIndex < stackLines.length) {
const line = stackLines[callerIndex].trim();
if (!line.includes('logger.ts') && !line.includes('logger.js')) {
break;
}
callerIndex++;
}
if (callerIndex < stackLines.length) {
const callerLine = stackLines[callerIndex];
// 提取文件路径和行号
let filePath = 'unknown';
let lineNumber = 0;
let functionName = 'anonymous';
// 1. 处理包含文件路径的情况
if (callerLine.includes('(')) {
// 格式1: at functionName (filePath:line:column)
const match1 = callerLine.match(/at\s+(.*?)\s+\((.*?):(\d+):(\d+)\)/);
if (match1) {
functionName = match1[1] || 'anonymous';
filePath = match1[2];
lineNumber = parseInt(match1[3], 10);
}
} else {
// 格式2: at filePath:line:column
const match2 = callerLine.match(/at\s+(.*?):(\d+):(\d+)/);
if (match2) {
filePath = match2[1];
lineNumber = parseInt(match2[2], 10);
}
}
// 2. 提取文件名
const fileName = filePath.split('\\').pop() || filePath.split('/').pop() || 'unknown';
// 3. 特殊处理async函数和箭头函数
if (functionName === 'anonymous' && callerLine.includes('async')) {
functionName = 'async';
}
return {
functionName,
fileName,
lineNumber
};
}
return {
functionName: 'anonymous',
fileName: 'unknown',
lineNumber: 0
};
}
/**
*
* @returns
*/
function getTimestamp() {
const now = new Date();
return now.toISOString();
}
/**
*
*/
export const logger = {
/**
*
* @param message
* @param data
*/
log(message: string, data?: any) {
const callerInfo = getCallerInfo();
const timestamp = getTimestamp();
const logMessage = `[${timestamp}] [${callerInfo.fileName}:${callerInfo.functionName}:${callerInfo.lineNumber}] ${message}`;
if (data) {
console.log(logMessage, data);
} else {
console.log(logMessage);
}
},
/**
*
* @param message
* @param data
*/
warn(message: string, data?: any) {
const callerInfo = getCallerInfo();
const timestamp = getTimestamp();
const logMessage = `[${timestamp}] [${callerInfo.fileName}:${callerInfo.functionName}:${callerInfo.lineNumber}] ${message}`;
if (data) {
console.warn(logMessage, data);
} else {
console.warn(logMessage);
}
},
/**
*
* @param message
* @param data
*/
error(message: string, data?: any) {
const callerInfo = getCallerInfo();
const timestamp = getTimestamp();
const logMessage = `[${timestamp}] [${callerInfo.fileName}:${callerInfo.functionName}:${callerInfo.lineNumber}] ${message}`;
if (data) {
console.error(logMessage, data);
} else {
console.error(logMessage);
}
},
/**
*
* @param message
* @param data
*/
info(message: string, data?: any) {
const callerInfo = getCallerInfo();
const timestamp = getTimestamp();
const logMessage = `[${timestamp}] [${callerInfo.fileName}:${callerInfo.functionName}:${callerInfo.lineNumber}] ${message}`;
if (data) {
console.info(logMessage, data);
} else {
console.info(logMessage);
}
}
};
export default logger;
Loading…
Cancel
Save