使用 Node.js child_process 生成 strace 命令

spawn strace command with Node.js child_process

因为我对 this approach and I got no answers, I'm trying another method to track the output of an already running program. I based this code on this Unix Stack Exchange 不满意,我想做的只是检索已经 运行.

的程序的日志信息

Obs:要在没有 sudo 的情况下使用 strace,您需要使用以下命令允许它:

echo kernel.yama.ptrace_scope = 0 > /etc/sysctl.d/10-ptrace.conf

并且可能只有在重启后才能正常工作。

这是我使用 strace linux 命令和节点 child_process 的代码,其中 -p1234 是我们要跟踪的进程数。

  import { spawn } from 'child_process';
  const strace = spawn('strace', [ `-p1234`, '-s9999', '-e', 'write']);

  strace.stdout.on('data', (data) => {
    // I don't know why, but my output is not being returned here
    console.log(`stdout: ${data}`);
  });

  strace.stderr.on('data', (data: any) => {
    // 'data' output is something like: 'write(4, "my real log", 4)                = 4\n',
    // so we need to cleanup a little bit with regex.
    const prefix = /^\write\(1, "/
    const suffix = /", [0-9]\)?\s*=?\s?[0-9]?/
    const raw = `${data}`.trim()

    if (raw.match(prefix) && raw.match(suffix)) {
      // cleaning msg
      let log = raw.replace(prefix, '').trim().replace(suffix, '').trim();
      if (!log.includes('\n')) {
        // showing msg: "my real log"
        console.log(log);
      }
    }
  });

首先: 我不明白为什么我的日志在 stderr 而不是 stdout 上输出,但是好吧,我遵循编码无论如何。

其次:如果我运行的程序输出日志很慢,就像一次打印一张一样,它工作得很好。

但是当我有一系列 2、3 或 4 次打印时,它不起作用。我想我花了太多时间来清理消息,所以当另一个 strace.stderr.on() 出现时,我正处于处理过程中,并且出现了一些问题。在这种情况下,我只能看到序列的第一个 print

我需要清理很多信息,因为消息输出如下:

'write(4, "9883", 4)                     = 4\n'

一团糟。我想也许只打印消息内容的命令也可以解决我的问题。

知道如何获得这些消息的更一致的输出吗?正如我所说,我的唯一目的是检索另一个程序 已经 运行 正在输出的消息。我也尝试遵循 "登录文件并读取文件" 方法,但正如我所说,我有一些 other issues

非常感谢任何建议、改进或完全不同的方法来实现此目标!

首先,我对 strace(1) 手册页的阅读表明 stderr 是该命令的默认值(在该页面中查找 --output)。

您在 data 事件中从 strace 获得的输出不保证在换行符边界上被分割。当您的输出速度变慢时,它会 碰巧 正常工作。更快的输出会将多行聚集在一起,并可能在 non-newline 边界处拆分行。为了快速修复,将 stderr 管道连接到 readline:

的实例
const rl = require('readline').createInterface({input: strace.stderr})

完成后,如果需要进一步帮助解析输出,可以使用更好的正则表达式一次解析整行:

rl.on('line', line => {
  const re = /^write\((?<fd>\d+),\s*"(?<data>(?:[^"]|\")*)",\s*(?<len>\d+)\)\s*=\s*(?<written>\d+)/
  const m = line.match(re)
  if (m) {
    console.log(m.groups.data)
  }
})

它使用了新命名的捕获组,因此如果您使用的是非常旧版本的节点,请删除看起来像 ?<fd> 的部分,而不是 m.groups.data 使用 m[2].

这还假设 strace 输出中的 double-quote 得到输出为 \",但我不知道实际情况是否如此。