我正在尝试了解由我的一个应用程序创建的短期进程的行为。我对这个过程了解如下:
- 进程名称的一部分。
- 将创建此进程的应用程序的名称和 PID。
- 该过程大约开始的时间(5-10 分钟内)。
- 进程退出后,进程的PID。
理想情况下,我想:
- 让内核(或其他东西)通知我的脚本该进程已启动。
- 针对进程运行一堆工具(iostat、strace 等)。
有没有办法让内核通知我某个进程已经启动,以便我可以对其采取一些操作?
运行类似的东西while true; do ps -ef | grep ${MY_PROCESS_NAME}; done
看起来既笨重又糟糕。我希望能够在发生时收到通知,而不是暴力搜索。
或者,我是否只需针对父进程和所有子进程运行这些工具,然后稍后过滤输出?例如,strace -ff -o ./some.trace -p ${PARENT_PID}
。
答案1
您可能想看看执行监听(假设您的内核配置了 CONFIG_FTRACE,通常是这种情况)。这是 Brendan Gregg 跟踪和表演收藏中的众多脚本之一。如果没有参数,它会显示系统上启动时的所有命令,或者您可以给它一个正则表达式来观看。
例如,要查找任何现有的或新的zsh
可能正在启动的命令,请执行以下操作:
sudo /opt/perf-tools-master/bin/execsnoop zsh
当我启动一个新的 zsh 时,它会向我显示以下输出:
Tracing exec()s issued by process name "zsh". Ctrl-C to end.
Instrumenting sys_execve
PID PPID ARGS
21920 21919 /usr/libexec/grepconf.sh -c
21923 21922 /usr/bin/tty -s
21922 21919 /usr/bin/tput colors
21924 21919 /usr/bin/dircolors --sh /etc/DIR_COLORS.256color
21925 21919 /usr/bin/grep -qi ^COLOR.*none /etc/DIR_COLORS.256color
21926 21919 /usr/libexec/grepconf.sh -c
21928 21919 /usr/libexec/grepconf.sh -c
21930 21919 uname -m
21932 21919 /bin/grep -q /usr/lib64/qt-3.3/bin
21934 21933 /usr/bin/id -u
一旦您知道正在运行的程序的全名,通常您会将该文件替换为添加挂钩后运行原始程序的脚本。如果你做不到这一点,你可以使用类似的方法fanotify(7)
让你的窥探程序在每个打开的文件被允许完成之前进行干预。或者也许inotifywatch
足够快,让您可以将其附加strace
到流程中。
答案2
看一眼sysdig
,它是一个可以让您监视系统调用的工具。如果您知道将创建进程的进程的 pid,您可以执行以下操作:
$ sudo sysdig proc.ppid=<PID>
这将为父 pid 为给定 PID 的进程执行的任何系统调用生成输出。如果您知道目标程序的全名,则可以将其包含在过滤器中:
$ sudo sysdig proc.ppid=<PID> and proc.name=<NAME>
这会给你一些可能适合替代的东西strace
。例如,我将使用上面的命令来监视我的 shell 并查找以下命令的执行情况ls
:
$ sudo sysdig proc.ppid=18659 and proc.name=ls
9762 16:07:05.911583406 0 ls (20545) < execve res=0 exe=ls args=-F.--color=auto. tid=20545(ls) pid=20545(ls) ptid=18659(zsh) cwd= fdlimit=1024 pgft_maj=0 pgft_min=69 vm_size=452 vm_rss=16 vm_swap=0 comm=ls cgroups=cpuset=/.cpu=/.cpuacct=/.io=/.memory=/.devices=/.freezer=/.net_cls=/.perf_eve... env=LANG=en_US.utf8.USER=user.LOGNAME=user.HOME=/home/user.PATH=/usr/loc... tty=34818 pgid=20545(ls) loginuid=1000
9763 16:07:05.911608835 0 ls (20545) > brk addr=0
9764 16:07:05.911609493 0 ls (20545) < brk res=557E882FF000 vm_size=452 vm_rss=176 vm_swap=0
9765 16:07:05.911652583 0 ls (20545) > access mode=4(R_OK)
9766 16:07:05.911657425 0 ls (20545) < access res=-2(ENOENT) name=/etc/ld.so.preload
9767 16:07:05.911663159 0 ls (20545) > openat
9768 16:07:05.911686542 0 ls (20545) < openat fd=3(<f>/etc/ld.so.cache) dirfd=-100(AT_FDCWD) name=/etc/ld.so.cache flags=4097(O_RDONLY|O_CLOEXEC) mode=0 dev=800
9769 16:07:05.911688872 0 ls (20545) > fstat fd=3(<f>/etc/ld.so.cache)
9770 16:07:05.911690846 0 ls (20545) < fstat res=0
9771 16:07:05.911691850 0 ls (20545) > mmap addr=0 length=44827 prot=1(PROT_READ) flags=2(MAP_PRIVATE) fd=3(<f>/etc/ld.so.cache) offset=0
9772 16:07:05.911694436 0 ls (20545) < mmap res=7FD38EDE7000 vm_size=496 vm_rss=256 vm_swap=0
9773 16:07:05.911695345 0 ls (20545) > close fd=3(<f>/etc/ld.so.cache)
9774 16:07:05.911695808 0 ls (20545) < close res=0
...
11068 16:07:05.913562304 0 ls (20545) > close fd=1(<f>/dev/pts/2)
11069 16:07:05.913562881 0 ls (20545) < close res=0
11070 16:07:05.913564527 0 ls (20545) > close fd=2(<f>/dev/pts/2)
11071 16:07:05.913564857 0 ls (20545) < close res=0
11072 16:07:05.913572008 0 ls (20545) > exit_group
11073 16:07:05.913622981 0 ls (20545) > procexit status=0
您可以看到用户指南以获取更多选项来配置过滤及其生成的信息。通过它,您可以自定义其打印的内容,让脚本读取该输出,然后执行您可能喜欢的任何其他工具。
答案3
strace
与-f
on一起使用bash
。从 shell 启动短暂的程序。
以下是我如何过滤运行时间超过 0.1 秒的任何系统调用的输出。 32330是我的shell的PID。我忽略“read(0”,因为这些来自我的 shell,并且由于 shell 等待输入,它们已经花费了很长的时间。
$ strace -p 32330 -f -T -tt |&
awk '$2 != "read(0," {
elapsed=$(NF)
l=length(elapsed)
elapsed=substr(elapsed,2,l-2)+0
if (elapsed>0.1) {
print
}
}'
sleep 2
这是我在 shell 中运行时的输出。
[pid 28454] 17:09:34.271522 nanosleep({2, 0}, NULL) = 0 <2.000138>
17:09:36.271900 <... wait4 resumed> [{WIFEXITED(s) && WEXITSTATUS(s) == 0}], WSTOPPED|WCONTINUED, NULL) = 28454 <2.002035>