6

サポートしているソフトウェアの問題を示す特定のエラーをログから検索する単純なログ スニファーを作成しています。これにより、ユーザーはログへのパスを指定し、何日前に検索するかを指定できます。

ユーザーがログのロールオーバーをオフにしている場合、ログ ファイルが非常に大きくなることがあります。現在、私は次のことを行っています(まだ完了していませんが):

File.open(@log_file, "r") do |file_handle|
    file_handle.each do |line|
        if line.match(/\d+++-\d+-\d+/)
          etc...

line.match は明らかに、ログで使用する日付形式を探します。残りのロジックは以下のとおりです。ただし、.each_line なしでファイルを検索するより良い方法はありますか? そうでなければ、私はそれでまったく問題ありません。利用可能な最高のリソースを使用していることを確認したかっただけです。

ありがとう

4

6 に答える 6

4

ログ ファイルが日付順に並べ替えられている場合は、バイナリ検索を実行することで、ファイル全体を検索する必要がなくなります。この場合、次のようにします。

  1. あなたがやっているようにファイルを開きます
  2. lineo=を使用して、ファイルの途中まで早送りします。
  3. ラインの始まりの日付が、探している日付よりも高いか低いかを確認します。
  4. 必要なものが見つかるまで、ファイルを半分に分割し続けます。

ただし、上記を理解するには、ファイルを非常に大きくする必要があると思います。

編集

基本的な考え方を示すコードを次に示します。最初の行ではなく、検索日を含む行を見つけます。これは、バイナリ検索を追加するか、日付を含まない最後の中間点から線形検索を実行することで修正できます。日付がファイルにない場合の終了条件もありません。これらの小さな追加は、読者への演習として残されています :-)

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')
于 2013-05-06T13:56:52.353 に答える
1

これを試してみてください。一度に 1 つずつ検索され、非常に高速で、メモリの消費量が少なくなります。

File.open(file, 'r') do |f|
  f.each_line do |line|
    # do stuff here to line
  end
end

もう 1 つのより高速なオプションは、ファイル全体を 1 つの配列に読み込むことです。高速ですが、大量のメモリが必要になります。

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
于 2013-05-06T13:52:25.740 に答える
0

ログ ファイルが大きくなる可能性があり、それが懸念事項である場合は、エラーをデータベースに保存することを検討してください。その後、より迅速な応答が得られます。

于 2013-05-06T14:16:46.307 に答える
0

行ごとにチャンクごとに読み取るよりも高速です。

File.open('file.txt') do |f|
  buff = f.read(10240)
  # ...
end

ただし、正規表現を使用して日付を一致させているため、行が不完全になる可能性があります。ロジックで処理する必要があります。

また、パフォーマンスがそれほど重要な場合は、本当に単純な C 拡張機能を作成することを検討してください。

于 2013-05-06T14:03:22.377 に答える