|
|
@@ -6,18 +6,21 @@ import packageJson from "./package.json";
|
|
|
import * as Rx from "rxjs";
|
|
|
|
|
|
import { hideBin } from "yargs/helpers";
|
|
|
-import { map, pluck, takeUntil } from "rxjs/operators";
|
|
|
+import { map, pluck, takeUntil, filter, window, mergeAll, buffer } from "rxjs/operators";
|
|
|
|
|
|
|
|
|
const args = yargs(hideBin(process.argv))
|
|
|
.scriptName(Object.keys(packageJson.bin)[0])
|
|
|
- .usage("Usage: $0 logfile")
|
|
|
+ .usage(`Usage:
|
|
|
+ $0 logfile`)
|
|
|
.option("files", {
|
|
|
boolean: true,
|
|
|
- describe: "Strip out and save the embedded files from the log file"
|
|
|
+ describe: "Extract and save the embedded files from the log file"
|
|
|
})
|
|
|
.argv;
|
|
|
|
|
|
+const argsParam0 = args._[0]?.toString();
|
|
|
+
|
|
|
type LogLine = {
|
|
|
log: string;
|
|
|
stream: string;
|
|
|
@@ -25,18 +28,55 @@ type LogLine = {
|
|
|
};
|
|
|
|
|
|
const rl = readline.createInterface({
|
|
|
- input: fs.createReadStream(args._[0]?.toString())
|
|
|
+ input: fs.createReadStream(argsParam0)
|
|
|
});
|
|
|
|
|
|
-Rx.fromEvent<string>(rl, "line")
|
|
|
+const readlineObservable = Rx.fromEvent<string>(rl, "line")
|
|
|
+ .pipe(
|
|
|
+ takeUntil(Rx.fromEvent(rl, "close"))
|
|
|
+ );
|
|
|
+
|
|
|
+const fileWindowStartObservable = readlineObservable
|
|
|
+ .pipe(
|
|
|
+ filter(rawLine => rawLine.includes("Dumping image"))
|
|
|
+ );
|
|
|
+
|
|
|
+const fileWindowStopObservable = readlineObservable
|
|
|
+ .pipe(
|
|
|
+ filter(rawLine => rawLine.includes("\\u003c\\u003c\\u003c\\u003c"))
|
|
|
+ );
|
|
|
+
|
|
|
+const logObservable = readlineObservable
|
|
|
.pipe(
|
|
|
- takeUntil(Rx.fromEvent(rl, "close")),
|
|
|
+ window(Rx.merge(fileWindowStartObservable, fileWindowStopObservable)),
|
|
|
+ filter((_, i) => i % 2 === (args.files ? 1 : 0)), //keep every second observable for the files stream
|
|
|
+ mergeAll(),
|
|
|
+ filter(rawLine => !rawLine.includes("\\u003c\\u003c\\u003c\\u003c")),
|
|
|
map<string, LogLine>(line => JSON.parse(line)),
|
|
|
pluck("log"),
|
|
|
map(log => log.replace(/\n$/, ""))
|
|
|
- )
|
|
|
- .subscribe({
|
|
|
+ );
|
|
|
+
|
|
|
+if (args.files) {
|
|
|
+ logObservable
|
|
|
+ .pipe(
|
|
|
+ buffer(fileWindowStopObservable),
|
|
|
+ map(fileLines => ({ name: fileLines.shift()?.substring(10), content: fileLines.join() }))
|
|
|
+ )
|
|
|
+ .subscribe({
|
|
|
+ next: file => {
|
|
|
+ const filename = `${argsParam0}.${file.name}`;
|
|
|
+ fs.writeFile(filename, Buffer.from(file.content, "base64"), () => {
|
|
|
+ console.log(`File ${filename} is saved.`)
|
|
|
+ });
|
|
|
+ },
|
|
|
+ error: console.error,
|
|
|
+ complete: () => rl.close()
|
|
|
+ });
|
|
|
+} else {
|
|
|
+ logObservable.subscribe({
|
|
|
next: console.log,
|
|
|
error: console.error,
|
|
|
complete: () => rl.close()
|
|
|
});
|
|
|
+}
|