Quantcast
Channel: func09 » linux
Viewing all articles
Browse latest Browse all 5

CakePHPのログをローテートするバッチファイル in Ruby

$
0
0

CakePHPのログファイルを、ローテートするバッチを作った。

Cakeのログクラスってシンプルすぎて、どうなのかな? 変数とかをログに送ると改行されてログとっちゃうんだけど普通か? すごく扱いづらいので、ソースを書き換えた。

ソース読んでてびっくりしたんだけど Objectクラスっていうかなり下のレイヤーのクラスに logっていうメソッドがあって、そこでCakeLogクラスを使っているんだけど 設計おかしくないか?オブジェクトクラスにログなんてメソッドが本当に必要? 必要な時だけシングルトンで取得して使えばいいんじゃねーの?

$logger = CakeLog::getInstance();
$logger->info('message');

こんな感じで。

ともあれ、最近PHPを書く事が多くて、AttackingPHP曰く、壊れたオブジェクト機構でもなんとかできるようになってきた。 その代わり他の言語で、頭が腐ってきてる。害悪だなぁ。

そんなこんなで、すでに取ってしまったログ(しかも変な改行もはいってる)を奇麗に整形しつつ、ローテートする必要があったので作ろうと思った。

最初はシェルスクリプトにしようと思ったが、わからなすぎてやめた。

次にsedとかsortとかgrepを使ってなんとかしようと思った。 どうしても複数行の正規表現が難しくてやめた。 http://www.kabipan.com/computer/sed/index.html が参考になった。 簡単な検索置換なら覚えたから、良しとしよう。

次にperl。すぐ諦める。

結局Rubyで書いた。 こういったテキストファイル操作なんてもんは、オブジェクト指向しない方が早いだろう事はわかってるから、Rubyじゃなくてもいいと思うけど、Rubyしか書けない。

無駄に対話式にしてみたりした。 出来上がって、結構満足の行くものになったが ソースを後から読んでも絶対にわからんってくらい、気持ちの悪いソースになった。

書いている時は気持ちいいんだけどねぇ。。

ファイルロックの機構とか入れてないんだけど 入れた方がいいのかな? 昔Perlでカウンタとか、そういう類いのあれで 良くファイルロックとか使ったような。

#!/usr/bin/env ruby

def number_with_delimiter(number, delimiter=",", separator=".")
  begin
    parts = number.to_s.split('.')
    parts[0].gsub!(/(¥d)(?=(¥d¥d¥d)+(?!¥d))/, "¥¥1#{delimiter}")
    parts.join separator
  rescue
    number
  end
end

def confirm( mes )
  #exit unless block_given?
  puts "#{mes} (yes/no)"
  ARGF.each do |input|
    input.chop!
    if input =~ /^no$/i
    elsif input =~ /^yes$/i
      yield input if block_given?
      break
    else
      puts "input text [yes] or [no] and enter."
    end
  end
end

# welcome message
puts "Welcome to LogRotator for CakePHP logfiles."
confirm('Are you ok?')

targets = Dir.glob("*.log").select{|f|f=~/^([a-z]+)¥.log/}

if targets.empty?
  puts "log files are not found in current directory."
  exit
end

datelogs = {}

# read and flatten lines
targets.each do |filename|
  fullfilename = "#{Dir::pwd}/#{filename}"
  start_time = Time.now
  puts %Q(Open "#{fullfilename}")
  puts " => #{number_with_delimiter(File::size(filename))}KB"
  lines = []
  File.open(filename).each do |line|
    if line =~ /^¥d{4}-¥d{2}-¥d{2}/
      lines << line.chop
      ( datelogs[$&.gsub(/-/,'')] ||= Array.new ) << lines.last
    else
      lines.last << line.chop.gsub(/¥s{2,}/,'') unless lines.last.nil?
    end
  end
  puts %Q( => #{number_with_delimiter(lines.size)} lines in "#{fullfilename}".)
  puts %Q! => read time: #{Time.now-start_time}sec!
  puts ""
  lines = nil
end

puts datelogs.keys.sort.map{|e|" => will create #{e}.log"}
puts ""
confirm("create #{datelogs.size}files. Are you ok?")

datelogs.each do |key,item|
  filename = "#{key}.log"
  start_date = Time.now
  begin
    file = File.new(filename,"w")
    file.puts(item.sort.join("¥n"))
    file.close
  rescue=>e
    puts e
  else
    puts " => write #{filename} [#{number_with_delimiter(File.size(filename))}KB] (#{Time.now-start_date}sec)"
  end
end

targets.each do |filename|
  newname = filename + Time.now.strftime("%Y%m%d")
  begin
    File::rename( filename, newname  )
  rescue=>e
    puts e
  else
    puts "rename #{filename} to #{newname}."
  end
end

puts "CakePHP logfiles were rotated."

Viewing all articles
Browse latest Browse all 5

Trending Articles