2013年6月27日木曜日

RubyでRDSのログをログの監視用にダウンロード

スズキです。

以前、下記でRubyのSDKを利用したRDSのログのダウンロード方法を紹介しました。
RubyでRDSのログ(すべてのファイル)をダウンロード
今回は(似てるのですが)、下記のログのチェックという観点でスクリプトを作ってみました。
  • RDS側のログが更新された時のみ最新のログファイル("mysql-general.log"など)を
    ダウンロードする。
  • ログの更新の判断は"last_written"の時刻を比較する。
  • RDS側のログのローテーションのタイミングとダウンロードのタイミングで
    抜けてしまうログをフォローするために、ログローテーション時には
    一世代前のログ("mysql-general.old"など)もダウンロードする。
  • 最新のはログのサイズが減少したらローテーションしたと判断する。

作成したスクリプトは下記の通りです。
#!/usr/bin/ruby

require 'rubygems'
require 'aws-sdk'

# 初期設定
AWS.config({ :region => 'ap-northeast-1' })
db_instance_identifier = 'suzlab'
filename               = 'general/mysql-general.log'
file_prefix            = '/tmp/general_mysql-general'

# 最新のログファイルの"last_written"を保存するファイルの作成
if !File.exists?(file_prefix + '.last_written') then
    open(file_prefix + '.last_written', 'w').write('0')
end
# 最新のログファイルの"size"を保存するファイルの作成
if !File.exists?(file_prefix + '.size') then
    open(file_prefix + '.size', 'w').write('0')
end

client = AWS::RDS.new.client

# 前回チェック時から更新された最新のログファイルを取得
log_files = client.describe_db_log_files({
    :db_instance_identifier => db_instance_identifier,
    :filename_contains      => filename,
    :file_last_written      => open(file_prefix + '.last_written', 'r').read.to_i + 1
})

# 該当ログファイルが無ければ終了
if log_files.describe_db_log_files.size == 0 then
    exit
end

# 最新のログファイルのダウンロードと更新
additional_data_pending = true
marker                  = '0:0'
while additional_data_pending do
    log = client.download_db_log_file_portion({
        :db_instance_identifier => db_instance_identifier,
        :log_file_name          => filename,
        :marker                 => marker
    })
    File.open(file_prefix + '.log.tmp', "a") do |io|
        if !log.log_file_data.nil? then
            io.print(log.log_file_data)
        end
    end
    additional_data_pending = log.additional_data_pending
    marker                  = log.marker
end
File.rename(file_prefix + '.log.tmp', file_prefix + '.log')

# ローテーションのチェック
if open(file_prefix + '.size', 'r').read.to_i > log_files.describe_db_log_files[0].size then

    # 一世代前のログファイルを取得
    log_files = client.describe_db_log_files({
        :db_instance_identifier => db_instance_identifier,
        :filename_contains      => filename,
    })
    log_files.describe_db_log_files.sort! { |a, b| a.last_written <=> b.last_written }
    log_files.describe_db_log_files.reverse!

    # 一世代前のログファイルのダウンロードと更新
    additional_data_pending = true
    marker                  = '0:0'
    while additional_data_pending do
        log = client.download_db_log_file_portion({
            :db_instance_identifier => db_instance_identifier,
            :log_file_name          => log_files.describe_db_log_files[1].log_file_name,
            :marker                 => marker
        })
        File.open(file_prefix + '.old.tmp', "a") do |io|
            if !log.log_file_data.nil? then
                io.print(log.log_file_data)
            end
        end
        additional_data_pending = log.additional_data_pending
        marker                  = log.marker
    end
    File.rename(file_prefix + '.old.tmp', file_prefix + '.old')

end

# "last_written"と"size"を更新(ファイルに出力)
open(file_prefix + '.last_written', 'w').write(log_files.describe_db_log_files[0].last_written)
open(file_prefix + '.size', 'w').write(log_files.describe_db_log_files[0].size)

実行すると、下記のようにログなどのファイルが出力されます。
# ll /tmp/
-rw-r--r-- 1 root root    13  6月 27 13:44 2013 general_mysql-general.last_written
-rw-r--r-- 1 root root 55086  6月 27 13:44 2013 general_mysql-general.log
-rw-r--r-- 1 root root 75503  6月 27 13:00 2013 general_mysql-general.old
-rw-r--r-- 1 root root     5  6月 27 13:44 2013 general_mysql-general.size

あとは、このログをNagiosで監視すれば...
(ログチェックのポジションのリセットなどは改めて考えないといけないけど...)
--------
http://www.suz-lab.com

0 コメント: