线上某个业务java进程出了一些麻烦,去诊断的时候发现jstack无法输出,可能是jdk或os版本的问题。这时还可以尝试一下kill -3
,它默认会输出到进程的标准输出。如果不幸这个进程的标准输出被重定向到了 /dev/null
或者重定向到某个文件,但却因为很多其他日志也在大量的输出,导致日志文件过大,要从中找出线程栈相关的日志,还要耗点时间;这个时候,可以通过strace
来跟踪一个进程的标准输入。
strace
输出的信息需要一些处理,可以通过管道与其他命令组合(通过-o参数或-ff参数)
这里 -o 参数后边是一个字符串表示输出文件,如果字符串开头是一个"|"会被strace识别为管道
$ strace -f -e trace=write -e verbose=none -e write=1,2 -q -p $pid -o "| grep '^ |' | cut -c11-60 | sed -e 's/ //g' | xxd -r -p"
或者 -ff 参数,用管道与其他命令组合,注意strace的错误输出也要重定向
$ strace -ff -e trace=write -e write=1,2 -s 1024 -q -p $pid 2>&1 | cut -c11-60 | sed -e 's/ //g' | xxd -r -p
不过这两种方式都遇到一个问题,因为buffer的问题导致管道后边的命令没能完全处理strace跟踪到的数据(要等到后续的数据塞满buffer),有点像grep
需要--line-buffer
解决缓冲区问题,但不知道这里有什么方式,尝试过stdbuf
也没有解决。最后只能分两步,先把strace的内容输出到文件,然后再对内容解析:
$ strace -f -e trace=write -e write=1,2 -q -p $pid -o /tmp/slog
$ grep " |" /tmp/slog | cut -c11-60 | sed -e 's/ //g' | xxd -r -p