@wu529778790/open-im 1.10.7-beta.5 → 1.10.8-beta.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/logger.js
CHANGED
|
@@ -4,7 +4,7 @@ import { finished } from 'node:stream/promises';
|
|
|
4
4
|
import { sanitize } from './sanitize.js';
|
|
5
5
|
import { APP_HOME } from './constants.js';
|
|
6
6
|
import { sanitizeTelemetryData } from './telemetry/telemetry-sanitize.js';
|
|
7
|
-
import { enqueueTelemetryLine, initTelemetryUpload, shutdownTelemetryUpload, } from './telemetry/telemetry-upload.js';
|
|
7
|
+
import { enqueueTelemetryLine, getTelemetryUploadStats, initTelemetryUpload, shutdownTelemetryUpload, } from './telemetry/telemetry-upload.js';
|
|
8
8
|
const DEFAULT_LOG_DIR = join(APP_HOME, 'logs');
|
|
9
9
|
const MAX_LOG_FILES = 10;
|
|
10
10
|
const LOG_LEVELS = { DEBUG: 0, INFO: 1, WARN: 2, ERROR: 3 };
|
|
@@ -13,6 +13,9 @@ let minLevel = LOG_LEVELS.DEBUG;
|
|
|
13
13
|
let logStream;
|
|
14
14
|
let eventsStream;
|
|
15
15
|
let telemetryEnabled = false;
|
|
16
|
+
let telemetryStatsTimer = null;
|
|
17
|
+
let lastTelemetryStatsSignature = '';
|
|
18
|
+
const TELEMETRY_STATS_INTERVAL_MS = 5 * 60_000;
|
|
16
19
|
function pad(n) {
|
|
17
20
|
return String(n).padStart(2, '0');
|
|
18
21
|
}
|
|
@@ -75,6 +78,11 @@ export function initLogger(dirOrOpts, level, telemetry) {
|
|
|
75
78
|
rotateOldLogs();
|
|
76
79
|
logStream = createWriteStream(join(logDir, getLogFileName()), { flags: 'a' });
|
|
77
80
|
telemetryEnabled = !!tel?.enabled;
|
|
81
|
+
if (telemetryStatsTimer) {
|
|
82
|
+
clearInterval(telemetryStatsTimer);
|
|
83
|
+
telemetryStatsTimer = null;
|
|
84
|
+
}
|
|
85
|
+
lastTelemetryStatsSignature = '';
|
|
78
86
|
if (eventsStream) {
|
|
79
87
|
eventsStream.end();
|
|
80
88
|
eventsStream = undefined;
|
|
@@ -87,11 +95,24 @@ export function initLogger(dirOrOpts, level, telemetry) {
|
|
|
87
95
|
url: tel?.url,
|
|
88
96
|
token: tel?.token,
|
|
89
97
|
});
|
|
98
|
+
telemetryStatsTimer = setInterval(() => {
|
|
99
|
+
emitTelemetryUploadStats(false);
|
|
100
|
+
}, TELEMETRY_STATS_INTERVAL_MS);
|
|
90
101
|
}
|
|
91
102
|
else {
|
|
92
103
|
initTelemetryUpload({ enabled: false });
|
|
93
104
|
}
|
|
94
105
|
}
|
|
106
|
+
function emitTelemetryUploadStats(force) {
|
|
107
|
+
if (!telemetryEnabled)
|
|
108
|
+
return;
|
|
109
|
+
const stats = getTelemetryUploadStats();
|
|
110
|
+
const signature = JSON.stringify(stats);
|
|
111
|
+
if (!force && signature === lastTelemetryStatsSignature)
|
|
112
|
+
return;
|
|
113
|
+
lastTelemetryStatsSignature = signature;
|
|
114
|
+
emitStructuredEvent('Telemetry', 'telemetry.upload.stats', stats);
|
|
115
|
+
}
|
|
95
116
|
function write(level, tag, msg, ...args) {
|
|
96
117
|
if (LOG_LEVELS[level] < minLevel)
|
|
97
118
|
return;
|
|
@@ -131,6 +152,11 @@ export function emitStructuredEvent(tag, event, data, level = 'INFO', msg = '')
|
|
|
131
152
|
enqueueTelemetryLine(line);
|
|
132
153
|
}
|
|
133
154
|
export async function shutdownLoggerTelemetry() {
|
|
155
|
+
emitTelemetryUploadStats(true);
|
|
156
|
+
if (telemetryStatsTimer) {
|
|
157
|
+
clearInterval(telemetryStatsTimer);
|
|
158
|
+
telemetryStatsTimer = null;
|
|
159
|
+
}
|
|
134
160
|
await shutdownTelemetryUpload();
|
|
135
161
|
}
|
|
136
162
|
export async function closeLogger() {
|
package/dist/shared/ai-task.js
CHANGED
|
@@ -261,6 +261,16 @@ export function runAITask(deps, ctx, prompt, toolAdapter, platformAdapter) {
|
|
|
261
261
|
taskState = {
|
|
262
262
|
handle: {
|
|
263
263
|
abort: () => {
|
|
264
|
+
if (!settled) {
|
|
265
|
+
emitStructuredEvent('AITask', 'ai.task.error', {
|
|
266
|
+
platform: ctx.platform,
|
|
267
|
+
taskKey: ctx.taskKey,
|
|
268
|
+
userKey: hashUserId(ctx.userId),
|
|
269
|
+
toolId: aiCommand,
|
|
270
|
+
durationMs: Date.now() - taskState.startedAt,
|
|
271
|
+
errorSnippet: 'aborted',
|
|
272
|
+
});
|
|
273
|
+
}
|
|
264
274
|
activeHandle?.abort();
|
|
265
275
|
cleanup();
|
|
266
276
|
settle();
|
|
@@ -1,3 +1,11 @@
|
|
|
1
|
+
interface TelemetryUploadStats {
|
|
2
|
+
postedBatches: number;
|
|
3
|
+
postedLines: number;
|
|
4
|
+
retryableFailures: number;
|
|
5
|
+
dropped4xxBatches: number;
|
|
6
|
+
dropped4xxLines: number;
|
|
7
|
+
networkFailures: number;
|
|
8
|
+
}
|
|
1
9
|
export declare function initTelemetryUpload(opts: {
|
|
2
10
|
enabled: boolean;
|
|
3
11
|
url?: string;
|
|
@@ -9,3 +17,5 @@ export declare function initTelemetryUpload(opts: {
|
|
|
9
17
|
*/
|
|
10
18
|
export declare function enqueueTelemetryLine(line: string): void;
|
|
11
19
|
export declare function shutdownTelemetryUpload(): Promise<void>;
|
|
20
|
+
export declare function getTelemetryUploadStats(): Readonly<TelemetryUploadStats>;
|
|
21
|
+
export {};
|
|
@@ -18,6 +18,22 @@ let uploadEnabled = false;
|
|
|
18
18
|
let endpoint;
|
|
19
19
|
let bearer;
|
|
20
20
|
let flushing = false;
|
|
21
|
+
const stats = {
|
|
22
|
+
postedBatches: 0,
|
|
23
|
+
postedLines: 0,
|
|
24
|
+
retryableFailures: 0,
|
|
25
|
+
dropped4xxBatches: 0,
|
|
26
|
+
dropped4xxLines: 0,
|
|
27
|
+
networkFailures: 0,
|
|
28
|
+
};
|
|
29
|
+
function resetStats() {
|
|
30
|
+
stats.postedBatches = 0;
|
|
31
|
+
stats.postedLines = 0;
|
|
32
|
+
stats.retryableFailures = 0;
|
|
33
|
+
stats.dropped4xxBatches = 0;
|
|
34
|
+
stats.dropped4xxLines = 0;
|
|
35
|
+
stats.networkFailures = 0;
|
|
36
|
+
}
|
|
21
37
|
function clearIdleTimer() {
|
|
22
38
|
if (idleTimer) {
|
|
23
39
|
clearTimeout(idleTimer);
|
|
@@ -58,9 +74,22 @@ async function postBatch(lines) {
|
|
|
58
74
|
catch {
|
|
59
75
|
/* ignore body read errors */
|
|
60
76
|
}
|
|
61
|
-
|
|
77
|
+
if (res.ok) {
|
|
78
|
+
stats.postedBatches += 1;
|
|
79
|
+
stats.postedLines += lines.length;
|
|
80
|
+
return true;
|
|
81
|
+
}
|
|
82
|
+
// 4xx(除 408/429)通常是请求本身不可恢复(鉴权/格式错误),不应无限重试。
|
|
83
|
+
if (res.status >= 400 && res.status < 500 && res.status !== 408 && res.status !== 429) {
|
|
84
|
+
stats.dropped4xxBatches += 1;
|
|
85
|
+
stats.dropped4xxLines += lines.length;
|
|
86
|
+
return true;
|
|
87
|
+
}
|
|
88
|
+
stats.retryableFailures += 1;
|
|
89
|
+
return false;
|
|
62
90
|
}
|
|
63
91
|
catch {
|
|
92
|
+
stats.networkFailures += 1;
|
|
64
93
|
return false;
|
|
65
94
|
}
|
|
66
95
|
}
|
|
@@ -116,6 +145,7 @@ export function initTelemetryUpload(opts) {
|
|
|
116
145
|
endpoint = opts.url;
|
|
117
146
|
bearer = opts.token;
|
|
118
147
|
backoffMs = INITIAL_BACKOFF_MS;
|
|
148
|
+
resetStats();
|
|
119
149
|
if (!uploadEnabled) {
|
|
120
150
|
queue = [];
|
|
121
151
|
}
|
|
@@ -172,10 +202,32 @@ export async function shutdownTelemetryUpload() {
|
|
|
172
202
|
if (br)
|
|
173
203
|
headers.authorization = `Bearer ${br}`;
|
|
174
204
|
const res = await fetch(ep, { method: 'POST', headers, body });
|
|
175
|
-
|
|
205
|
+
try {
|
|
206
|
+
if (typeof res.text === 'function') {
|
|
207
|
+
await res.text();
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
catch {
|
|
211
|
+
/* ignore body read errors */
|
|
212
|
+
}
|
|
213
|
+
if (res.ok) {
|
|
214
|
+
stats.postedBatches += 1;
|
|
215
|
+
stats.postedLines += batch.length;
|
|
216
|
+
}
|
|
217
|
+
else if (res.status >= 400 && res.status < 500 && res.status !== 408 && res.status !== 429) {
|
|
218
|
+
stats.dropped4xxBatches += 1;
|
|
219
|
+
stats.dropped4xxLines += batch.length;
|
|
220
|
+
}
|
|
221
|
+
else {
|
|
222
|
+
stats.retryableFailures += 1;
|
|
223
|
+
}
|
|
176
224
|
}
|
|
177
225
|
catch {
|
|
226
|
+
stats.networkFailures += 1;
|
|
178
227
|
/* best effort,静默 */
|
|
179
228
|
}
|
|
180
229
|
}
|
|
181
230
|
}
|
|
231
|
+
export function getTelemetryUploadStats() {
|
|
232
|
+
return { ...stats };
|
|
233
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@wu529778790/open-im",
|
|
3
|
-
"version": "1.10.
|
|
3
|
+
"version": "1.10.8-beta.0",
|
|
4
4
|
"description": "Multi-platform IM bridge for AI CLI tools (Claude, Codex, CodeBuddy)",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -28,6 +28,7 @@
|
|
|
28
28
|
"lint": "eslint src",
|
|
29
29
|
"web:build": "npm --prefix web run build",
|
|
30
30
|
"web:dev": "npm --prefix web run dev",
|
|
31
|
+
"telemetry:report": "node scripts/telemetry-health-report.mjs",
|
|
31
32
|
"prepublishOnly": "npm run build"
|
|
32
33
|
},
|
|
33
34
|
"keywords": [
|