Commit a50f59d5153a2b98845378b4ced1829c5e7ee582

Authored by yibo
1 parent e287643c

perf: billing.log date-sharding - write to billing-YYYY-MM-DD.log, read with 30-…

…day window, skip old files
Showing 1 changed file with 36 additions and 21 deletions
server/routes/agent-chat.js
@@ -791,28 +791,42 @@ router.get('/quota', (req, res) => { @@ -791,28 +791,42 @@ router.get('/quota', (req, res) => {
791 try { 791 try {
792 const DATA_ROOT = path.resolve(__dirname, '../../data'); 792 const DATA_ROOT = path.resolve(__dirname, '../../data');
793 const records = []; 793 const records = [];
  794 + const daysBack = parseInt(String(req.query.days || '30')) || 30; // 默认读最近 30 天
  795 + const cutoff = new Date(Date.now() - daysBack * 86400000).toISOString();
794 796
795 - // 读取所有 billing.log 797 + // 读取 billing 日志(兼容旧 billing.log + 新 billing-YYYY-MM-DD.log)
796 const readBilling = (dir) => { 798 const readBilling = (dir) => {
797 - const p = path.join(dir, 'billing.log');  
798 - if (fs.existsSync(p)) {  
799 - fs.readFileSync(p, 'utf-8').split('\n').forEach(line => {  
800 - line = line.trim();  
801 - if (line.startsWith('{')) {  
802 - try { records.push(JSON.parse(line)); } catch(e) {}  
803 - } else if (line) {  
804 - // 旧的纯文本兼容: 2026-03-28T18:00:00.000Z | Agent: master | Conv: 123 | Cost: $0.123 | Duration: 123ms  
805 - try {  
806 - const parts = line.split('|').map(p => p.trim());  
807 - const ts = parts[0];  
808 - const ai = parts[1].replace('Agent:', '').trim();  
809 - const ci = parts[2].replace('Conv:', '').trim();  
810 - const cost = parseFloat(parts[3].replace('Cost: $', '').trim());  
811 - const dur = parseInt(parts[4].replace('Duration:', '').replace('ms', '').trim());  
812 - records.push({ timestamp: ts, agentId: ai, convId: ci, costUsd: cost || 0, durationMs: dur || 0, usage: { input: 0, output: 0 } });  
813 - } catch(e) {}  
814 - }  
815 - }); 799 + if (!fs.existsSync(dir)) return;
  800 + const files = fs.readdirSync(dir).filter(f => f.startsWith('billing'));
  801 + for (const file of files) {
  802 + // 按日分片优化:跳过超出时间范围的文件
  803 + const dateMatch = file.match(/billing-(\d{4}-\d{2}-\d{2})\.log/);
  804 + if (dateMatch && dateMatch[1] < cutoff.substring(0, 10)) continue;
  805 +
  806 + const p = path.join(dir, file);
  807 + try {
  808 + fs.readFileSync(p, 'utf-8').split('\n').forEach(line => {
  809 + line = line.trim();
  810 + if (line.startsWith('{')) {
  811 + try {
  812 + const rec = JSON.parse(line);
  813 + if (rec.timestamp >= cutoff) records.push(rec);
  814 + } catch(e) {}
  815 + } else if (line) {
  816 + // 旧的纯文本兼容
  817 + try {
  818 + const parts = line.split('|').map(p => p.trim());
  819 + const ts = parts[0];
  820 + if (ts < cutoff) return;
  821 + const ai = parts[1].replace('Agent:', '').trim();
  822 + const ci = parts[2].replace('Conv:', '').trim();
  823 + const cost = parseFloat(parts[3].replace('Cost: $', '').trim());
  824 + const dur = parseInt(parts[4].replace('Duration:', '').replace('ms', '').trim());
  825 + records.push({ timestamp: ts, agentId: ai, convId: ci, costUsd: cost || 0, durationMs: dur || 0, usage: { input: 0, output: 0 } });
  826 + } catch(e) {}
  827 + }
  828 + });
  829 + } catch(e) {}
816 } 830 }
817 }; 831 };
818 832
@@ -2226,7 +2240,8 @@ router.post(&#39;/:agentId/chat&#39;, async (req, res) =&gt; { @@ -2226,7 +2240,8 @@ router.post(&#39;/:agentId/chat&#39;, async (req, res) =&gt; {
2226 durationMs: event.params.duration_ms, 2240 durationMs: event.params.duration_ms,
2227 usage: event.params.usage || { input: 0, output: 0 } 2241 usage: event.params.usage || { input: 0, output: 0 }
2228 }; 2242 };
2229 - fs.appendFileSync(path.join(billingDir, 'billing.log'), JSON.stringify(logEntry) + '\n', 'utf-8'); 2243 + const billingDate = new Date().toISOString().substring(0, 10);
  2244 + fs.appendFileSync(path.join(billingDir, `billing-${billingDate}.log`), JSON.stringify(logEntry) + '\n', 'utf-8');
2230 } catch (err) {} 2245 } catch (err) {}
2231 } 2246 }
2232 if (!fullOutput && event.params?.result) { 2247 if (!fullOutput && event.params?.result) {