coderail-watch 0.1.3 → 0.1.5
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/README.md +12 -0
- package/bin/coderail-watch.js +119 -7
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -8,6 +8,18 @@ Usage:
|
|
|
8
8
|
npx coderail-watch --session-id <session_id> --project-key <project_public_id> --base-url http://localhost:8000
|
|
9
9
|
```
|
|
10
10
|
|
|
11
|
+
Switch base URL by env:
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
npx coderail-watch --session-id <session_id> --project-key <project_public_id> --env staging
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
Watch a log file instead of stdin:
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
npx coderail-watch --session-id <session_id> --project-key <project_public_id> --base-url http://localhost:8000 --log-path /path/to/logfile
|
|
21
|
+
```
|
|
22
|
+
|
|
11
23
|
Publish (npm):
|
|
12
24
|
|
|
13
25
|
```bash
|
package/bin/coderail-watch.js
CHANGED
|
@@ -1,9 +1,15 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
"use strict";
|
|
3
3
|
|
|
4
|
+
const fs = require("fs");
|
|
4
5
|
const readline = require("readline");
|
|
5
6
|
|
|
6
7
|
const DEFAULT_BASE_URL = "http://localhost:8000";
|
|
8
|
+
const ENV_BASE_URLS = {
|
|
9
|
+
local: "http://localhost:8000",
|
|
10
|
+
staging: "https://api.dev-coderail.local",
|
|
11
|
+
production: "https://api.coderail.local",
|
|
12
|
+
};
|
|
7
13
|
const DEFAULT_RETRY_WAIT_MS = 2000;
|
|
8
14
|
const ALERT_PREFIX = "[[CODERAIL_ERROR]] ";
|
|
9
15
|
const ERROR_PATTERN = /(^|[\s:])(?:error|exception|traceback|panic|fatal)(?=[\s:])/i;
|
|
@@ -65,15 +71,26 @@ const buildWsUrl = (baseUrl, sessionId, projectKey, token) => {
|
|
|
65
71
|
const args = parseArgs(process.argv.slice(2));
|
|
66
72
|
const sessionId = args["session-id"];
|
|
67
73
|
const projectKey = args["project-key"];
|
|
68
|
-
const
|
|
74
|
+
const env = args["env"];
|
|
75
|
+
const baseUrl =
|
|
76
|
+
args["base-url"] ||
|
|
77
|
+
(env && ENV_BASE_URLS[env] ? ENV_BASE_URLS[env] : DEFAULT_BASE_URL);
|
|
69
78
|
const token = args["token"];
|
|
70
79
|
const retryWaitMs = Number(args["retry-wait"] || DEFAULT_RETRY_WAIT_MS);
|
|
80
|
+
const logPath = args["log-path"];
|
|
71
81
|
|
|
72
82
|
if (!sessionId || !projectKey) {
|
|
73
83
|
log("Missing required args: --session-id and --project-key");
|
|
74
84
|
process.exit(1);
|
|
75
85
|
}
|
|
76
86
|
|
|
87
|
+
if (env && !ENV_BASE_URLS[env]) {
|
|
88
|
+
log(
|
|
89
|
+
`Unknown env '${env}'. Use one of: ${Object.keys(ENV_BASE_URLS).join(", ")}`,
|
|
90
|
+
);
|
|
91
|
+
process.exit(1);
|
|
92
|
+
}
|
|
93
|
+
|
|
77
94
|
const wsUrl = buildWsUrl(baseUrl, sessionId, projectKey, token);
|
|
78
95
|
let socket = null;
|
|
79
96
|
let isOpen = false;
|
|
@@ -179,7 +196,7 @@ const enqueueOrSend = (payload) => {
|
|
|
179
196
|
queue.push(payload);
|
|
180
197
|
};
|
|
181
198
|
|
|
182
|
-
|
|
199
|
+
const handleLine = (line) => {
|
|
183
200
|
const payload = JSON.stringify({
|
|
184
201
|
type: "log",
|
|
185
202
|
content: line,
|
|
@@ -194,10 +211,105 @@ rl.on("line", (line) => {
|
|
|
194
211
|
});
|
|
195
212
|
enqueueOrSend(alertPayload);
|
|
196
213
|
}
|
|
197
|
-
}
|
|
214
|
+
};
|
|
215
|
+
|
|
216
|
+
const startFileTailer = (targetPath) => {
|
|
217
|
+
let fileOffset = 0;
|
|
218
|
+
let remainder = "";
|
|
219
|
+
|
|
220
|
+
const initializeOffset = () => {
|
|
221
|
+
try {
|
|
222
|
+
const stats = fs.statSync(targetPath);
|
|
223
|
+
fileOffset = stats.size;
|
|
224
|
+
return true;
|
|
225
|
+
} catch (error) {
|
|
226
|
+
log(`log-path not found: ${targetPath} (retrying...)`);
|
|
227
|
+
return false;
|
|
228
|
+
}
|
|
229
|
+
};
|
|
230
|
+
|
|
231
|
+
const flushChunk = (chunk) => {
|
|
232
|
+
const text = `${remainder}${chunk}`;
|
|
233
|
+
const lines = text.split(/\r?\n/);
|
|
234
|
+
remainder = lines.pop() ?? "";
|
|
235
|
+
lines.forEach((line) => {
|
|
236
|
+
if (line.length > 0) {
|
|
237
|
+
handleLine(line);
|
|
238
|
+
}
|
|
239
|
+
});
|
|
240
|
+
};
|
|
241
|
+
|
|
242
|
+
const readNewData = () => {
|
|
243
|
+
fs.stat(targetPath, (error, stats) => {
|
|
244
|
+
if (error) {
|
|
245
|
+
log(`log-path read error: ${error.message || String(error)}`);
|
|
246
|
+
return;
|
|
247
|
+
}
|
|
248
|
+
if (stats.size < fileOffset) {
|
|
249
|
+
fileOffset = 0;
|
|
250
|
+
}
|
|
251
|
+
if (stats.size === fileOffset) {
|
|
252
|
+
return;
|
|
253
|
+
}
|
|
254
|
+
const stream = fs.createReadStream(targetPath, {
|
|
255
|
+
start: fileOffset,
|
|
256
|
+
end: stats.size - 1,
|
|
257
|
+
encoding: "utf8",
|
|
258
|
+
});
|
|
259
|
+
stream.on("data", flushChunk);
|
|
260
|
+
stream.on("end", () => {
|
|
261
|
+
fileOffset = stats.size;
|
|
262
|
+
});
|
|
263
|
+
stream.on("error", (streamError) => {
|
|
264
|
+
log(
|
|
265
|
+
`log-path stream error: ${
|
|
266
|
+
streamError.message || String(streamError)
|
|
267
|
+
}`,
|
|
268
|
+
);
|
|
269
|
+
});
|
|
270
|
+
});
|
|
271
|
+
};
|
|
272
|
+
|
|
273
|
+
const startWatcher = () => {
|
|
274
|
+
try {
|
|
275
|
+
fs.watch(targetPath, { persistent: true }, (eventType) => {
|
|
276
|
+
if (eventType === "change") {
|
|
277
|
+
readNewData();
|
|
278
|
+
}
|
|
279
|
+
});
|
|
280
|
+
} catch (error) {
|
|
281
|
+
log(`log-path watch error: ${error.message || String(error)}`);
|
|
282
|
+
}
|
|
283
|
+
};
|
|
198
284
|
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
285
|
+
if (!initializeOffset()) {
|
|
286
|
+
const retryTimer = setInterval(() => {
|
|
287
|
+
if (initializeOffset()) {
|
|
288
|
+
clearInterval(retryTimer);
|
|
289
|
+
startWatcher();
|
|
290
|
+
}
|
|
291
|
+
}, retryWaitMs);
|
|
292
|
+
return;
|
|
202
293
|
}
|
|
203
|
-
|
|
294
|
+
|
|
295
|
+
startWatcher();
|
|
296
|
+
};
|
|
297
|
+
|
|
298
|
+
if (logPath) {
|
|
299
|
+
startFileTailer(logPath);
|
|
300
|
+
} else {
|
|
301
|
+
const rl = readline.createInterface({
|
|
302
|
+
input: process.stdin,
|
|
303
|
+
crlfDelay: Infinity,
|
|
304
|
+
});
|
|
305
|
+
|
|
306
|
+
rl.on("line", (line) => {
|
|
307
|
+
handleLine(line);
|
|
308
|
+
});
|
|
309
|
+
|
|
310
|
+
rl.on("close", () => {
|
|
311
|
+
if (socket) {
|
|
312
|
+
socket.close();
|
|
313
|
+
}
|
|
314
|
+
});
|
|
315
|
+
}
|