logger.js
2.43 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
/**
* Claude Stream 日志记录器
*
* 支持全量消息写入文件,方便调试和问题排查
*/
const fs = require('fs');
const path = require('path');
// 统一日志目录:项目根目录下的 .autodev-logs/
const DEFAULT_LOG_DIR = path.join(__dirname, '../../../../../.autodev-logs');
class StreamLogger {
constructor(options = {}) {
this.logDir = options.logDir || DEFAULT_LOG_DIR;
this.prefix = options.prefix || 'claude-stream';
this.stream = null;
this.filePath = null;
this.messageCount = 0;
}
/**
* 初始化日志文件
*/
init(workDir, agentName = 'unknown') {
try {
// 始终使用统一的日志目录
const absLogDir = path.isAbsolute(this.logDir)
? this.logDir
: DEFAULT_LOG_DIR;
if (!fs.existsSync(absLogDir)) {
fs.mkdirSync(absLogDir, { recursive: true });
}
const timestamp = Date.now();
this.filePath = path.join(absLogDir, `${this.prefix}-${agentName}-${timestamp}.jsonl`);
this.stream = fs.createWriteStream(this.filePath, { flags: 'a' });
console.log(`[StreamLogger] 日志文件: ${this.filePath}`);
return this.filePath;
} catch (e) {
console.error('[StreamLogger] 初始化失败:', e.message);
return null;
}
}
/**
* 记��原始消息(全量)
*/
logRaw(direction, data) {
if (!this.stream) return;
this.messageCount++;
const record = {
seq: this.messageCount,
direction, // 'in' | 'out' | 'internal'
timestamp: Date.now(),
data
};
this.stream.write(JSON.stringify(record) + '\n');
}
/**
* 记录入站消息
*/
logIncoming(msg) {
this.logRaw('in', msg);
}
/**
* 记录出站消息
*/
logOutgoing(msg) {
this.logRaw('out', msg);
}
/**
* 记录内部事件
*/
logInternal(event, data) {
this.logRaw('internal', { event, ...data });
}
/**
* 记录错误
*/
logError(error) {
this.logRaw('internal', {
event: 'error',
message: error.message,
stack: error.stack
});
}
/**
* 关闭日志
*/
close() {
if (this.stream) {
this.logInternal('close', { messageCount: this.messageCount });
this.stream.end();
this.stream = null;
}
}
/**
* 获取统计信息
*/
getStats() {
return {
filePath: this.filePath,
messageCount: this.messageCount
};
}
}
module.exports = { StreamLogger };