LoginSignup
9
9

More than 5 years have passed since last update.

連結されたgzipを1行ずつ見る

Last updated at Posted at 2015-06-26

最近は物騒でして、危ないサイトにアクセスしていないか?って依頼が来ることがあります。そういうことでプロキシのログを見るんですけど、効率よく検索できないと難しいところです。

で、そのプロキシログなんですが、gzip圧縮された状態で100MB以上(展開したら5倍ぐらいになる)のファイルが毎日たまっていっています。こんなの全部展開していたらログサーバはすぐにいっぱいになってしまいます。

ということで、Rubyでgzipを展開しながら見ていけばいいと言うことでこんなメソッドを作りました。

require 'zlib'
def gzip_each_line(filename, &block)
  Zlib::GzipReader.open(filename) do |gz|
    gz.each_line &block
  end
end

これで万事オッケーのはずってやってみたら、なぜか1行だけしか読み取ってくれなかったのです。もしかしてファイル壊れている?と思ってgunzipしたら、ちゃんと展開されました。で、gzipについて調べているととんでもない事実を発見しました。

複数の圧縮ファイルを連結することができる。 この場合、 gunzip はすべての圧縮ファイルを一度に伸長する。たとえば、

gzip -c file1  > foo.gz 
gzip -c file2 >> foo.gz

の後に

gunzip -c foo

とするのは、以下と同じである。

cat file1 file2

え、gzipって単純連結できるの?というより、このログファイルはgzipの単純連結になってるーーー

さすが青いやつ1です。ただのgzipの筈が無かった。ということで何度もGzipReaderに喰わしてあげればいいやと書き直してみました。

require 'zlib'
def gzip_each_line(filename, &block)
  File.open(filename, "rb") do |io|
    until io.eof?
      Zlib::GzipReader.wrap(io) do |gz|
        gz.each_line &block
        gz.finish
      end
    end
  end
end

これでうまくいくはずと思ってやったら、二つ目のgzipでgzipじゃないよってエラーになって終わっちゃいます。どうやら、GzipReaderではioをバッファ単位で取得しているらしく、GzipReaderを閉じても使われなかったバッファが戻ってこないようなのです。つまり、読み込まれなかった分をちゃんと数えてその分戻してやらないといけない・・・となって、こうなりました。

require 'zlib'
def gzip_each_line(filename, &block)
  File.open(filename, "rb") do |io|
    unused_size = 0
    until io.eof?
      Zlib::GzipReader.wrap(io) do |gz|
        gz.each_line &block
        unused_size = gz.unused ? gz.unused.size : 0
        gz.finish
      end
      io.seek(-unused_size, IO::SEEK_CUR)
    end
  end
end

GzipReader#unusedは使われなかったバッファが入っています。そのサイズ分、毎回戻してやれば、次のgzipもうまく見に行けるって方法です。これでやっといろいろ検索ができるようになりました。

というかGzipReaderがはじめから連結されたgzipファイルも対応しておいてくれていれば良かったんだけどなー。なお、単に検索するならzcat | grepとかでいいんじゃね?という指摘は受け付けておりません!


  1. ザクとは違う青いやつではありません。シェアは高いですが、まぁ、いろいろありますね、あの製品は。 

9
9
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
9
9