20.3. 记录应用程序互动
应用程序的可执行代码与操作系统和共享库的代码交互。记录这些交互的活动日志可在不调试实际应用程序代码的情况下充分洞察应用的行为。另外,分析应用程序的交互可帮助确定存在错误清单的条件。
20.3.1. 记录应用程序交互的有用工具
红帽企业 Linux 提供用于分析应用程序的交互的多种工具。
- strace
strace
工具可跟踪(和修改)应用程序与 Linux 内核之间的交互:系统调用、信号发送和进程状态更改。-
strace
输出的详细内容,并说明调用良好,因为strace
解释底层内核代码的参数和结果。将数字转换为对应的常数名称、对标记列表扩展的位明组合标志,指向字符数组的指针以提供实际字符串,等等。但是,对最新内核功能的支持可能会缺乏。 -
使用
strace
不需要任何特定设置,除了设置日志过滤器外。 - 使用 strace 跟踪应用代码可能会导致应用程序的执行速度显著下降。因此,strace 不适用于很多生产部署。作为替代方案,在这样的情形中使用 SystemTap。
- 您可以限制 traced 系统调用和信号列表,以减少捕获的数据量。
- strace 仅捕获内核用户空间交互,而不 trace 库调用,例如:考虑对追踪库调用使用 ltrace。
-
- ltrace
ltrace
工具支持将应用的用户空间调用记录到共享对象(动态库)。-
ltrace
可启用对任何库的追踪调用。 - 您可以过滤跟踪的调用来减少捕获的数据量。
-
使用
ltrace
不需要任何特定设置,除了设置日志过滤器外。 -
ltrace
是轻量级而快速的,为strace
提供替代 strace 的替代方案:可以使用ltrace
追踪库中的对应
接口,而不是通过strace
跟踪内核功能。但请注意,ltrace
在 syscall 跟踪时可能不太精确。 -
ltrace
能够对有限库调用集进行解码参数:相关配置文件中定义了原型的调用。作为ltrace
软件包的一部分,提供了一些libacl
、libc
和libm
调用和系统调用的原型。ltrace
输出主要仅包含原始数字和指针。ltrace
输出的解释通常需要咨询输出中存在的库的实际接口声明。
-
- SystemTap
SystemTap 是一个检测平台,用于在 Linux 系统上探测运行中的进程和内核活动。SystemTap 使用自己的脚本语言来编程自定义事件处理程序。
-
与使用
strace
和ltrace
相比,编写日志意味着在初始设置阶段有更多工作。但是,该脚本功能将 SystemTap 的用处扩展至生成日志之外。 - SystemTap 通过创建和插入内核模块来工作。SystemTap 的使用效率更高,不会自行造成系统或应用执行的显著下降。
- SystemTap 附带了一组使用示例。
-
与使用
- GDB
GNU Debugger 主要用于调试,而不是日志记录。但是,其某些功能即使在应用程序交互是关注的主要活动的情况下也使其有用。
- 借助 GDB,可以将交互事件的捕获和后续执行路径的即时调试轻松结合在一起。
- 在其他工具的初始识别问题后,GDB 最适合分析对非经常性或具体事件的响应。在任何有频繁事件的情况下使用 GDB 都会变得效率低下甚至不可能。
其它资源
20.3.2. 通过 strace 监控应用程序的系统调用
strace
工具可跟踪(和可选修改)与 Linux 内核之间的交互:系统调用、信号发送和进程状态更改。
先决条件
strace
安装在系统中要安装
strace
,以 root 用户身份运行:# yum install strace
步骤
请注意,strace
的追踪规格语法提供正则表达式和 syscall 类,以帮助识别系统调用。
运行 或附加到您想要监控的进程。
如果您要监控的程序没有运行,请启动
追踪
并指定 程序 :$ strace -fvttTyy -s 256 -e trace=call program
上述示例中使用的选项不是强制性的。在需要时使用:
-
f 选项是
"跟进分叉"的缩写。这个选项跟踪由 fork、vfork 和克隆系统调用创建的子项。 -
v 或
-e abbrev=none
选项可禁用输出的缩写,省略了各种结构字段。 -
tt
选项是
选项的一个变体,使用绝对时间戳为每一行加上前缀。通过-
t-tt
选项,打印的时间包括 microseconds。 -
t
选项打印行末尾的每个系统调用所花费的时间长度。 -
yy 选项是
选项的一个变体,它可以打印与文件描述符编号关联的路径。yy 选项不仅打印路径,还打印与套接字文件描述符和设备描述符关联的协议特定信息,或者与设备文件描述符关联的字符设备编号。-y
-
s
选项控制
要打印的最大字符串大小。请注意,文件名不被视为字符串,并且始终全部打印。 -e trace
控制追踪的系统调用集合。使用要显示的系统调用列表替换 call。如果缺少 调用,
strace
将显示所有系统调用。strace(1) 手册页中提供了部分系统调用的 Shorthands。
-
如果程序已在运行,找到其进程 ID(pid),并为它附加
strace
:$ ps -C program (...) $ strace -fvttTyy -s 256 -e trace=call -ppid
-
如果您不想跟踪任何已分叉的进程或线程,请不要使用
-f
选项。
strace
显示由应用发出的系统调用及其详细信息。在大多数情况下,如果未设置系统调用过滤器,应用及其库都会立即发出大量调用和
strace
输出。当所有 traced 进程退出时,
strace
会退出。要在跟踪程序退出前终止监控,请按 。-
如果
strace
启动 程序,它将向正在启动的程序发送终止信号(SIGINT)。但请注意,该程序依次可能忽略该信号。 -
如果您
将 trace 附加到
已在运行的程序,程序会一起终止。
-
如果
分析应用执行的系统调用列表。
- 当调用返回错误时,日志中会出现与资源访问或可用性相关的问题。
- 传递给系统调用和调用序列模式的值可让您了解应用程序的原因。
- 如果应用程序崩溃,重要信息可能是在日志的末尾。
- 输出中包含大量额外的信息。但是,您可以构建一个更精确的过滤器并重复该过程。
备注
益处是查看输出并将其保存到文件中。要做到这一点,请运行
tee
命令:$ strace ...-o |tee your_log_file.log>&2
要查看与不同进程对应的独立输出,请运行:
$ strace ... -ff -o your_log_file
带有进程 ID 的进程的输出(pid)将保存在 your_log_file.pid 中。
其它资源
- strace(1) 手册页。
- 知识库文章 - 如何使用 strace 跟踪命令发出的系统调用?
- Red Hat Developer Toolset User Guide - strace
20.3.3. 通过 ltrace 监控应用程序的库函数调用
ltrace
工具支持对应用所进行的调用的监控到库中可用的功能(共享对象)。
先决条件
步骤
- 识别感兴趣的库和功能(如果可能)。
如果您要监控的程序没有运行,请启动
ltrace
并指定 程序 :$ ltrace -f -l library -e function program
使用
-e
和-l
选项过滤输出:-
请提供函数名称,使其显示为 函数。
e 函数
选项可多次使用。如果左侧,l
trace 将显示所有功能的调用。 -
您可以使用
-l 库
选项指定整个库,而不是指定函数。这个选项的行为与-e 函数
选项类似。
如需更多信息,请参阅 ltrace(1)_ 手册页。
如果程序已在运行,请查找其进程 ID(pid)并附加
ltrace
到其中:$ ps -C program (...) $ ltrace ... -ppid
如果您不想跟踪任何已分叉的进程或线程,请离开
-f
选项。-
请提供函数名称,使其显示为 函数。
ltrace
显示应用发出的库调用。在大多数情况下,如果没有设置过滤器,应用程序将产生大量调用,如果未设置过滤器,则立即出现
ltrace
输出。当程序
退出时,ltrace 会退出。要在 traced 程序退出前终止监控,请按 enter
。-
如果
ltrace
启动了程序,程序会一起使用ltrace
终止。 -
如果您将
ltrace
附加到已在运行的程序,程序会一起终止ltrace
。
-
如果
分析应用执行的库调用列表。
- 如果应用程序崩溃,重要信息可能是在日志的末尾。
- 输出中包含大量不必要的信息。但是,您可以构建一个更精确的过滤器并重复该过程。
益处是查看输出并将其保存到文件中。使用 tee
命令实现这一点:
$ ltrace ... |& tee your_log_file.log
其它资源
- strace(1) 手册页
- Red Hat Developer Toolset User Guide - ltrace
20.3.4. 使用 SystemTap 监控应用程序的系统调用
SystemTap 工具支持为内核事件注册自定义事件处理程序。与 strace 相比,使用起来更难于使用,但 SystemTap 效率更高,并启用更复杂的处理逻辑。
先决条件
步骤
使用以下内容创建
my_script.stp
文件:probe begin { printf("waiting for syscalls of process %d \n", target()) } probe syscall.* { if (pid() == target()) printf("%s(%s)\n", name, argstr) } probe process.end { if (pid() == target()) exit() }
查找您要监控的进程的进程 ID(pid):
$ ps -aux
使用脚本运行 SystemTap :
# stap my_script.stp -x pid
pid 的值是进程 ID。
脚本编译到之后载入的内核模块。这在输入命令和获取输出之间引入了一些延迟。
- 当进程执行系统调用时,调用名称及其参数将打印到终端。
-
当进程终止或按
Ctrl+C
时,脚本将退出。
其它资源
- SystemTap 入门指南
- SystemTap Tapset 参考
一个大型 SystemTap 脚本(约roximates strace 功能)作为
/usr/share/systemtap/examples/process/strace.stp
可用。要运行脚本:# stap --example strace.stp -x pid
或
# stap --example strace.stp -c "cmd args …"
20.3.5. 使用 GDB 互动应用程序系统调用
GDB 启用在执行程序的过程中停止各种情况的执行。要在程序执行系统调用时停止执行,请使用 GDB 捕获点。
先决条件
使用 GDB 在系统调用时停止程序执行
设置捕获点:
(gdb) catch syscall syscall-name
命令
catch syscall
设置一个特殊类型的断点,在程序执行系统调用时停止执行。syscall-name
选项指定调用的名称。您可以为各种系统调用指定多个捕获点。退出syscall-name
选项会导致 GDB 在任何系统调用时停止。如果程序还没有开始执行,请启动它:
(gdb) r
如果程序执行只停止,请恢复它:
(gdb) c
- GDB 在程序执行任何指定系统调用后停止执行。
其它资源
20.3.6. 使用 GDB 通过应用程序中断信号
GDB 启用在执行程序的过程中停止各种情况的执行。要在程序收到操作系统信号时停止执行,请使用 GDB 捕获点。
先决条件
使用 GDB 停止接收信号的程序执行
设置捕获点:
(gdb) catch signal signal-type
命令
catch signal
会设置一个特殊类型的断点,从而在收到程序收到信号时停止执行。signal-type
选项指定信号的类型。使用特殊值"all"
来捕获所有信号。如果程序还没有开始执行,请启动它:
(gdb) r
如果程序执行只停止,请恢复它:
(gdb) c
- GDB 会在程序收到任何指定的信号后停止执行。