coderail-watch 0.1.3 → 0.1.4
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 +6 -0
- package/bin/coderail-watch.js +103 -6
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -8,6 +8,12 @@ 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
|
+
Watch a log file instead of stdin:
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
npx coderail-watch --session-id <session_id> --project-key <project_public_id> --base-url http://localhost:8000 --log-path /path/to/logfile
|
|
15
|
+
```
|
|
16
|
+
|
|
11
17
|
Publish (npm):
|
|
12
18
|
|
|
13
19
|
```bash
|
package/bin/coderail-watch.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
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";
|
|
@@ -68,6 +69,7 @@ const projectKey = args["project-key"];
|
|
|
68
69
|
const baseUrl = args["base-url"] || DEFAULT_BASE_URL;
|
|
69
70
|
const token = args["token"];
|
|
70
71
|
const retryWaitMs = Number(args["retry-wait"] || DEFAULT_RETRY_WAIT_MS);
|
|
72
|
+
const logPath = args["log-path"];
|
|
71
73
|
|
|
72
74
|
if (!sessionId || !projectKey) {
|
|
73
75
|
log("Missing required args: --session-id and --project-key");
|
|
@@ -179,7 +181,7 @@ const enqueueOrSend = (payload) => {
|
|
|
179
181
|
queue.push(payload);
|
|
180
182
|
};
|
|
181
183
|
|
|
182
|
-
|
|
184
|
+
const handleLine = (line) => {
|
|
183
185
|
const payload = JSON.stringify({
|
|
184
186
|
type: "log",
|
|
185
187
|
content: line,
|
|
@@ -194,10 +196,105 @@ rl.on("line", (line) => {
|
|
|
194
196
|
});
|
|
195
197
|
enqueueOrSend(alertPayload);
|
|
196
198
|
}
|
|
197
|
-
}
|
|
199
|
+
};
|
|
200
|
+
|
|
201
|
+
const startFileTailer = (targetPath) => {
|
|
202
|
+
let fileOffset = 0;
|
|
203
|
+
let remainder = "";
|
|
204
|
+
|
|
205
|
+
const initializeOffset = () => {
|
|
206
|
+
try {
|
|
207
|
+
const stats = fs.statSync(targetPath);
|
|
208
|
+
fileOffset = stats.size;
|
|
209
|
+
return true;
|
|
210
|
+
} catch (error) {
|
|
211
|
+
log(`log-path not found: ${targetPath} (retrying...)`);
|
|
212
|
+
return false;
|
|
213
|
+
}
|
|
214
|
+
};
|
|
215
|
+
|
|
216
|
+
const flushChunk = (chunk) => {
|
|
217
|
+
const text = `${remainder}${chunk}`;
|
|
218
|
+
const lines = text.split(/\r?\n/);
|
|
219
|
+
remainder = lines.pop() ?? "";
|
|
220
|
+
lines.forEach((line) => {
|
|
221
|
+
if (line.length > 0) {
|
|
222
|
+
handleLine(line);
|
|
223
|
+
}
|
|
224
|
+
});
|
|
225
|
+
};
|
|
226
|
+
|
|
227
|
+
const readNewData = () => {
|
|
228
|
+
fs.stat(targetPath, (error, stats) => {
|
|
229
|
+
if (error) {
|
|
230
|
+
log(`log-path read error: ${error.message || String(error)}`);
|
|
231
|
+
return;
|
|
232
|
+
}
|
|
233
|
+
if (stats.size < fileOffset) {
|
|
234
|
+
fileOffset = 0;
|
|
235
|
+
}
|
|
236
|
+
if (stats.size === fileOffset) {
|
|
237
|
+
return;
|
|
238
|
+
}
|
|
239
|
+
const stream = fs.createReadStream(targetPath, {
|
|
240
|
+
start: fileOffset,
|
|
241
|
+
end: stats.size - 1,
|
|
242
|
+
encoding: "utf8",
|
|
243
|
+
});
|
|
244
|
+
stream.on("data", flushChunk);
|
|
245
|
+
stream.on("end", () => {
|
|
246
|
+
fileOffset = stats.size;
|
|
247
|
+
});
|
|
248
|
+
stream.on("error", (streamError) => {
|
|
249
|
+
log(
|
|
250
|
+
`log-path stream error: ${
|
|
251
|
+
streamError.message || String(streamError)
|
|
252
|
+
}`,
|
|
253
|
+
);
|
|
254
|
+
});
|
|
255
|
+
});
|
|
256
|
+
};
|
|
257
|
+
|
|
258
|
+
const startWatcher = () => {
|
|
259
|
+
try {
|
|
260
|
+
fs.watch(targetPath, { persistent: true }, (eventType) => {
|
|
261
|
+
if (eventType === "change") {
|
|
262
|
+
readNewData();
|
|
263
|
+
}
|
|
264
|
+
});
|
|
265
|
+
} catch (error) {
|
|
266
|
+
log(`log-path watch error: ${error.message || String(error)}`);
|
|
267
|
+
}
|
|
268
|
+
};
|
|
198
269
|
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
270
|
+
if (!initializeOffset()) {
|
|
271
|
+
const retryTimer = setInterval(() => {
|
|
272
|
+
if (initializeOffset()) {
|
|
273
|
+
clearInterval(retryTimer);
|
|
274
|
+
startWatcher();
|
|
275
|
+
}
|
|
276
|
+
}, retryWaitMs);
|
|
277
|
+
return;
|
|
202
278
|
}
|
|
203
|
-
|
|
279
|
+
|
|
280
|
+
startWatcher();
|
|
281
|
+
};
|
|
282
|
+
|
|
283
|
+
if (logPath) {
|
|
284
|
+
startFileTailer(logPath);
|
|
285
|
+
} else {
|
|
286
|
+
const rl = readline.createInterface({
|
|
287
|
+
input: process.stdin,
|
|
288
|
+
crlfDelay: Infinity,
|
|
289
|
+
});
|
|
290
|
+
|
|
291
|
+
rl.on("line", (line) => {
|
|
292
|
+
handleLine(line);
|
|
293
|
+
});
|
|
294
|
+
|
|
295
|
+
rl.on("close", () => {
|
|
296
|
+
if (socket) {
|
|
297
|
+
socket.close();
|
|
298
|
+
}
|
|
299
|
+
});
|
|
300
|
+
}
|