我正在编写一个简单的日志嗅探器,它将搜索日志以查找指示我支持的软件问题的特定错误。它允许用户指定日志的路径并指定他们想要搜索的天数。
如果用户关闭了日志滚动,则日志文件有时会变得非常大。目前我正在做以下事情(虽然尚未完成):
File.open(@log_file, "r") do |file_handle|
file_handle.each do |line|
if line.match(/\d+++-\d+-\d+/)
etc...
line.match显然会查找我们在日志中使用的日期格式,其余逻辑将在下面。但是,有没有更好的方法来搜索没有.each_line的文件?如果没有,我对此完全没问题。我只是想确保我使用的是最好的资源。
由于
答案 0 :(得分:5)
fgrep
作为独立版或从system('fgrep ...')
调用可能是更快的解决方案file.readlines
速度可能更好,但这是一个时空权衡答案 1 :(得分:2)
以下是一些编码提示......
而不是:
File.open(@log_file, "r") do |file_handle|
file_handle.each do |line|
使用:
File.foreach(@log_file) do |line|
next unless line[/\A\d+++-\d+-\d+/]
foreach
简化了文件的打开和循环。
next unless...
制作一个紧密循环,跳过不以目标字符串开头的每一行。在确定你是否有一条好线之前你做的越少,你的代码运行得越快。
在模式的开头使用锚点,例如\A
为正则表达式引擎提供了关于在该行中查找位置的主要提示,并允许它在线路不匹配时快速拯救。此外,使用line[/\A\d+++-\d+-\d+/]
更简洁一点。
答案 2 :(得分:1)
如果日志文件按日期排序,则可以避免通过二进制搜索搜索整个文件。在这种情况下你要:
我认为你的文件需要非常大才能使上述内容有意义。
修改强>
以下是一些显示基本概念的代码。它找到一行包含搜索日期,而不是第一行。这可以通过更多二进制搜索或从最后一个中间点(不包含日期)进行线性搜索来解决。如果日期不在文件中,也没有终止条件。这些小小的补充,留给读者练习: - )
require 'date'
def bin_fsearch(search_date, file)
f = File.open file
search = {min: 0, max: f.size}
while true
# go to file midpoint
f.seek (search[:max] + search[:min]) / 2
# read in until EOL
f.gets
# record the actual mid-point we are using
pos = f.pos
# read in next line
line = f.gets
# get date from line
line_date = Date.parse(line)
if line_date < search_date
search[:min] = f.pos
elsif line_date > search_date
search[:max] = pos
else
f.seek pos
return
end
end
end
bin_fsearch(Date.new(2013, 5, 4), '/var/log/system.log')
答案 3 :(得分:0)
试试这个,它会一次搜索一次&amp;应该很快&amp;占用更少的内存。
File.open(file, 'r') do |f|
f.each_line do |line|
# do stuff here to line
end
end
另一个更快的选择是将整个文件读入一个数组。它会很快,但需要很多记忆。
File.readlines.each do |line|
#do stuff with each line
end
此外,如果您需要内存最少的最快方法,请尝试grep
专门用于搜索大文件。所以应该快速和记忆反应
`grep -e regex bigfile`.split(/\n/).each do |line|
# ... (called on each matching line) ...
end
答案 4 :(得分:0)
比逐行更快地读取行:
File.open('file.txt') do |f|
buff = f.read(10240)
# ...
end
但是你使用regexp来匹配日期,你可能会得到不完整的行。你必须在你的逻辑中处理它。
此外,如果性能非常重要,请考虑编写一个非常简单的C扩展。
答案 5 :(得分:0)
如果日志文件变得庞大,那么您可能会担心,那么您可以考虑将错误保存在数据库中。然后,您将获得更快的响应。