Linux 程序启动异常时,可以先用 strace 看文件访问

63 次浏览6 条回复

遇到程序提示找不到配置、动态库或证书时,先看它实际访问了哪些路径,通常比猜配置位置快。环境:Linux,strace 5.5+。

strace -f -e trace=file -o trace.log ./app

然后搜失败的打开操作:

grep -E 'ENOENT|EACCES' trace.log

-f 会跟踪子进程,-e trace=file 只保留文件相关系统调用,输出不会像完整 syscall 日志那么吵。程序参数或环境变量里有敏感值时,记得先检查日志再分享;排查结束后也可以去掉 -o 直接在终端看。

这个思路挺实用。补一个容易忽略的点:如果服务是 systemd 或容器启动,命令里的相对路径是相对它自己的工作目录,不一定是 shell 当前目录。看到 ENOENT 时可以顺手对照进程的工作目录和完整路径;排权限问题也尽量用同一个运行用户复现,避免 root 运行把问题掩掉。日志里如果带了 token 或密码,贴出来前记得先脱敏。

MukiLv1#1

这个思路挺实用。补一个容易忽略的点:如果服务是 systemd 或容器启动,命令里的相对路径是相对它自己的工作目录,不一定是 shell 当前目录。看到 ENOENT 时可以顺手对照进程的工作目录和完整路径;排权限问题也尽量用同一个运行用户复现,避免 root 运行把问题掩掉。日志里如果带了 token 或密码,贴出来前记得先脱敏。

还可以加一个小过滤:只想看真正失败的文件调用时,grep -E 'ENOENT|EACCES' trace.log 之后最好再看一下调用者是哪个进程。-f 跟踪子进程时,主进程和 worker 混在一起,单看路径容易误判。systemd 场景也可以对照 WorkingDirectory 和服务实际用户,通常比直接改文件权限更快定位。

Ryan小满Lv1#2

还可以加一个小过滤:只想看真正失败的文件调用时,grep -E 'ENOENT|EACCES' trace.log 之后最好再看一下调用者是哪个进程。-f 跟踪子进程时,主进程和 worker 混在一起,单看路径容易误判。systemd 场景也可以对照 WorkingDirectory 和服务实际用户,通常比直接改文件权限更快定位。

如果子进程较多,-ff -o trace.%p 会按 PID 分开写文件,后面把失败路径和具体进程对应起来更直观:

strace -ff -e trace=file -o trace.%p ./app
grep -H -E 'ENOENT|EACCES' trace.*

再结合 ps 或服务配置确认这个 PID 对应的 worker,能少把主进程和子进程的问题混在一起。

如果程序已经在跑,也可以临时附加到现有 PID:

strace -fp <PID> -e trace=file -o trace.log

复现一次后尽快停掉,避免把正常运行期间的调用全记下来。权限不足时要用能查看该进程的用户;线上服务还得留意短时间的性能开销。

HosuLv1#4

如果程序已经在跑,也可以临时附加到现有 PID:

strace -fp <PID> -e trace=file -o trace.log

复现一次后尽快停掉,避免把正常运行期间的调用全记下来。权限不足时要用能查看该进程的用户;线上服务还得留意短时间的性能开销。

如果程序不是直接按路径打开文件,而是先拿到文件描述符再操作,-y 也挺有帮助:

strace -f -y -e trace=file -o trace.log ./app

它会尽量把文件描述符对应的路径显示出来,和 -ff -o trace.%p 搭配时,定位具体 worker 会更直观。输出里仍可能有权限限制或匿名文件,不能把没显示路径直接当成不存在。

再补一个判断性能问题的小技巧:可以加 -ttt -T,前者给系统调用打时间戳,后者显示每次调用耗时。这样除了看 ENOENT、EACCES,也能发现某个文件调用是不是卡得特别久:

strace -f -ttt -T -e trace=file -o trace.log ./app

不过 strace 本身会放大调用开销,适合短时间复现和定位,别把这份耗时直接当成程序的真实基线。