这是一个深奥的请求,对我来说只是理论上的兴趣(换句话说,我没有在生产代码中使用它)。我想知道是否可以找出运行 ruby 程序时涉及的所有文件。也就是说,文件在执行过程中被所述程序编辑(或涉及其他方式,例如在程序中途由 Rails 编辑)。
我知道可以使用
require
并循环遍历对象,排除除 autoload
及其后代之外的所有对象,并且当我禁用垃圾收集时,我使用此方法取得了部分成功(否则列表会随机收缩,这是可以理解的) 。但是,在程序开始时执行此操作会忽略中间所需的那些文件,因此我可以在最后运行相同的代码,并获取所述文件的并集?
几个月前我也做了同样的事情。这是我的肮脏的小程序:
然后运行你的程序:
File
lsof
REQUIRE_FILE = ENV.fetch('REQUIRE_FILE', '/tmp/requires.txt')
File.open(REQUIRE_FILE, 'w')
Kernel.module_eval do
alias_method :require_without_benchmark, :require
def require(name)
start = Time.now
begin
require_without_benchmark(name)
ensure
time = Time.now - start
File.write(REQUIRE_FILE, [name, time.to_f].join(',').concat("\n"), mode: 'a')
end
end
end
ruby -r ./require-benchmark.rb program.rb
它为您提供当前进程打开的文件held。
但是,该列表还远未完成:一旦执行此行,许多文件已被读取、解析、执行和关闭。 当
lsof
扫描打开的文件时,它们不再出现在列表中。
追踪
puts `lsof -a -p #{Process.pid}`
(也在 Linux 上)是一个很好的工具,可以实现您想要实现的目标(请参阅此 thread
)。它会提供很多(可能太多)信息:
lsof
strace
现在开始于:
strace -e trace=open -o opened_files.txt ruby hello_world.rb
#=> Hello world
“Hello World”脚本有 571 行,“rails runner hello_world.rb”脚本有 112302 (!) 行。
输出文件有许多“ENOENT(没有这样的文件或目录)”行,因此您可能需要解析和过滤它。
对于 macOS 和其他 *nix,应该有
opened_files.txt
常量 open("/home/ricou/.rvm/rubies/ruby-2.3.1/lib/tls/x86_64/libruby.so.2.3", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
open("/home/ricou/.rvm/rubies/ruby-2.3.1/lib/tls/libruby.so.2.3", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
open("/home/ricou/.rvm/rubies/ruby-2.3.1/lib/x86_64/libruby.so.2.3", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
open("/home/ricou/.rvm/rubies/ruby-2.3.1/lib/libruby.so.2.3", O_RDONLY|O_CLOEXEC) = 3
open("/home/ricou/.rvm/rubies/ruby-2.3.1/lib/libc.so.6", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
open("/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3
open("/lib/x86_64-linux-gnu/libc.so.6", O_RDONLY|O_CLOEXEC) = 3
open("/home/ricou/.rvm/rubies/ruby-2.3.1/lib/libpthread.so.0", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
open("/lib/x86_64-linux-gnu/libpthread.so.0", O_RDONLY|O_CLOEXEC) = 3
open("/home/ricou/.rvm/rubies/ruby-2.3.1/lib/libgmp.so.10", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
....
保存所有文件的数组,其中包含通过 require 加载的路径,不仅是 gem 本身,还包括所有涉及的文件。
在脚本末尾尝试
dtrace
。
对于 File 打开的普通文件,您可以覆盖
$LOADED_FEATURES
和/或 $LOADED_FEATURES.dup.uniq
以及姊妹方法 read、binread 等,如 KARASZI 在他的答案中所示。
基于 KARAZI 的答案,这是一个显示文件路径的版本:
然后运行你的程序:
File.open