使用Node.js child_process生成strace命令

问题描述

由于我对this approach不满意,也没有答案,因此我尝试使用另一种方法来跟踪已经运行的程序的输出。我将这段代码基于this Unix Stack Exchange,而我试图做的只是检索已经运行的程序的日志信息。

提示:要在不使用strace的情况下使用sudo,则需要通过以下命令允许它使用:

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获得的输出不能保证在换行符边界上分割。当输出缓慢时,它会 happen 正常工作。更快的输出会将多行聚集在一起,并可能在非换行边界处分割行。为了快速解决,将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输出中的双引号将输出为\",但我不知道是否确实如此。