【发布时间】:2010-11-20 14:10:52
【问题描述】:
我有一个不断增长的日志文件。如何通过 Ruby 脚本查看和解析它?
脚本将在写入文件时解析每个新行,并在新行包含字符串 'ERROR' 时将内容输出到屏幕
【问题讨论】:
我有一个不断增长的日志文件。如何通过 Ruby 脚本查看和解析它?
脚本将在写入文件时解析每个新行,并在新行包含字符串 'ERROR' 时将内容输出到屏幕
【问题讨论】:
def watch_for(file, pattern)
f = File.open(file,"r")
f.seek(0,IO::SEEK_END)
while true do
select([f])
line = f.gets
puts "Found it! #{line}" if line=~pattern
end
end
watch_for("g.txt",/ERROR/)
感谢ezpz的想法,使用select方法你得到你想要的。 select 方法正在监听 IO 的流,读取“迟到”的字节。
【讨论】:
select 在文件流上使用时总是立即返回:您始终可以从该文件流中读取 EOF,因此您的 ruby 进程在等待文件更新时最终会旋转。不同的操作系统倾向于提供不同的文件等待工具,Linux 有 inotify,OS X 有 fsevents - 也有方便的 ruby gem 封装它们。
if line=~pattern 的行,即使没有新的更新,它也只会返回空行。我不确定如何自己解决,因为我也偶然发现了这个问题。
您可以通过以下方式使用Kernel#select:
def watch_for(file,pattern)
f = File.open(file,"r")
# Since this file exists and is growing, seek to the end of the most recent entry
f.seek(0,IO::SEEK_END)
while true
select([f])
puts "Found it!" if f.gets =~ pattern
end
end
然后这样称呼它:
watch_for("some_file", /ERROR/)
我已经省略了所有的错误检查等等——你会希望拥有它,并且可能需要一些机制来打破循环。但是基本的想法就在那里。
【讨论】:
select 将在文件末尾立即返回 true,因为 read() 将读取 EOF(感谢 @antifuchs)。跨度>
有两种方法:
sleep)这是我写的一篇文章:Ruby for Admins: Reading Growing Files。所以结合事件子系统和轮询的程序如下所示:
def tail_dash_f(filename)
open(filename) do |file|
file.read
case RUBY_PLATFORM # string with OS name, like "amd64-freebsd8"
when /bsd/, /darwin/
require 'rb-kqueue'
queue = KQueue::Queue.new
queue.watch_file(filename, :extend) do
yield file.read
end
queue.run
when /linux/
require 'rb-inotify'
queue = INotify::Notifier.new
queue.watch(filename, :modify) do
yield file.read
end
queue.run
else
loop do
changes = file.read
unless changes.empty?
yield changes
end
sleep 1.0
end
end
end
end
tail_dash_f ARGV.first do |data|
print data
if data =~ /error/i
# do something else, for example send an email to administrator
end
end
【讨论】:
如果您使用的是 Linux...
tail -f log/development.log | grep "ERROR"
除非您出于某种原因真的希望它是一个 Ruby 脚本。
【讨论】:
查看file-tailgem
【讨论】:
穷人的快捷方式:
一个 Ruby 脚本
ARGF.each do |line|
...
运行屏幕:
tail -f file | ruby script
【讨论】:
处理@Qianjigui 的想法,但不使用 100% CPU:
def watch_for(file, pattern)
# Replace -n0 with -n+1 if you want to read from the beginning of file
f = IO.popen(%W[tail -f -n0 #{file}])
while line = f.gets
puts "Found it! #{line}" if line =~ pattern
end
end
watch_for('g.txt', /ERROR/)
【讨论】:
select 将在文件末尾立即返回 true,因为 read() 将读取 EOF(感谢 @antifuchs)。跨度>
tail 管道而不是文件读取,所以tail -f 负责等待并且不会返回EOF(可能直到错误或中断)。我还重新检查了代码,看起来 loop 和 select 也不需要