【问题标题】:spawn strace command with Node.js child_process使用 Node.js child_process 生成 strace 命令
【发布时间】:2020-12-12 08:35:51
【问题描述】:

由于我对this approach 不满意并且没有得到任何答案,我正在尝试另一种方法来跟踪已经运行的程序的输出。我将此代码基于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

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

【问题讨论】:

标签: javascript node.js linux logging child-process


【解决方案1】:

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

您在data 事件中从 strace 获得的输出不能保证在换行符边界上进行拆分。当你得到缓慢的输出时,它只会发生正常工作。更快的输出会将多行聚集在一起,并可能在非换行符边界处拆分行。为了快速修复,将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)
  }
})

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

这也假设 strace 输出中的双引号将输出为\",但我不知道是否真的如此。

【讨论】:

  • 天啊!我被这个问题困扰了很多时间,而这个readline() 的技巧就成功了。非常感谢您提供如此详尽的答案!我不是正则表达式的专家,这当然也更适合
  • 如果我想在一开始只接受write(1,而不是所有数字,我应该做些什么改变?
  • 将正则表达式更改为/^write\(1,\s*"(?&lt;data&gt;(?:[^"]|\\")*)",\s*(?&lt;len&gt;\d+)\)\s*=\s*(?&lt;written&gt;\d+)/,因此您将(?&lt;fd&gt;\d+) 替换为1,以匹配一个文字字符。 \d 表示“任何数字,0-9”。
猜你喜欢
  • 1970-01-01
  • 2014-07-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-08-24
  • 1970-01-01
相关资源
最近更新 更多