canary-log-viewer.ts 2.3 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182
  1. import readline from "readline";
  2. import fs from "fs";
  3. import yargs from "yargs";
  4. import packageJson from "./package.json";
  5. import * as Rx from "rxjs";
  6. import { hideBin } from "yargs/helpers";
  7. import { map, pluck, takeUntil, filter, window, mergeAll, buffer } from "rxjs/operators";
  8. const args = yargs(hideBin(process.argv))
  9. .scriptName(Object.keys(packageJson.bin)[0])
  10. .usage(`Usage:
  11. $0 logfile`)
  12. .option("files", {
  13. boolean: true,
  14. describe: "Extract and save the embedded files from the log file"
  15. })
  16. .argv;
  17. const argsParam0 = args._[0]?.toString();
  18. type LogLine = {
  19. log: string;
  20. stream: string;
  21. time: string;
  22. };
  23. const rl = readline.createInterface({
  24. input: fs.createReadStream(argsParam0)
  25. });
  26. const readlineObservable = Rx.fromEvent<string>(rl, "line")
  27. .pipe(
  28. takeUntil(Rx.fromEvent(rl, "close"))
  29. );
  30. const fileWindowStartObservable = readlineObservable
  31. .pipe(
  32. filter(rawLine => rawLine.includes("Dumping image"))
  33. );
  34. const fileWindowStopObservable = readlineObservable
  35. .pipe(
  36. filter(rawLine => rawLine.includes("\\u003c\\u003c\\u003c\\u003c"))
  37. );
  38. const logObservable = readlineObservable
  39. .pipe(
  40. window(Rx.merge(fileWindowStartObservable, fileWindowStopObservable)),
  41. filter((_, i) => i % 2 === (args.files ? 1 : 0)), //keep every second observable for the files stream
  42. mergeAll(),
  43. filter(rawLine => !rawLine.includes("\\u003c\\u003c\\u003c\\u003c")),
  44. map<string, LogLine>(line => JSON.parse(line)),
  45. pluck("log"),
  46. map(log => log.replace(/\n$/, ""))
  47. );
  48. if (args.files) {
  49. logObservable
  50. .pipe(
  51. buffer(fileWindowStopObservable),
  52. map(fileLines => ({ name: fileLines.shift()?.substring(10), content: fileLines.join() }))
  53. )
  54. .subscribe({
  55. next: file => {
  56. const filename = `${argsParam0}.${file.name}`;
  57. fs.writeFile(filename, Buffer.from(file.content, "base64"), () => {
  58. console.log(`File ${filename} is saved.`)
  59. });
  60. },
  61. error: console.error,
  62. complete: () => rl.close()
  63. });
  64. } else {
  65. logObservable.subscribe({
  66. next: console.log,
  67. error: console.error,
  68. complete: () => rl.close()
  69. });
  70. }