AWS RDSのログファイルをダウンロードするPythonとRubyのスクリプト
以前、AWS RDS PostgreSQLのクエリログをawscliで取得するワンライナーという記事で、RDSのインスタンスにあるログファイルを一括で取得する方法を書きました。しかしこのワンライナーでは、1MBを超えるログですと先頭の1MBしか取得できず、途切れてしまいました。
そこで、PythonとRubyでdownload_db_log_file_portionというAPIを使ってログをダウンロードするスクリプトを書きました。
行数を指定することで、その行数分の取得を繰り返し全部ダウンロードすることができます。しかし、行数指定が難しいです。
行数を大きくしすぎて一度に取得する大きさが1MBを超えてしまうと、そこで途切れてしまって、後続のログが取得できません。
逆に行数を小さくしすぎると、ダウンロードの回数が増えてしまい、トータルのログサイズが大きい場合にとてつもなく時間がかかってしまう問題があります。
この方法は他にも問題がありました。ログに日本語の含まれる場合に ?
に置き換えられてしまいます。文字化けの問題は以前の記事のワンライナーでも同じでした。
解決策は次の改良版の記事に書きましたが、ここまで試行した過程として、PythonとRubyでのスクリプトを残しておきます。
改良版:AWS RDSのログファイルを高速にダウンロードするスクリプト
Python
import sys import boto3 profile = "default" instance_id = "foo" session = boto3.session.Session(profile_name = profile) rds_client = session.client('rds') files = rds_client.describe_db_log_files(DBInstanceIdentifier = instance_id) for file in files["DescribeDBLogFiles"]: file_name = file["LogFileName"] if not file_name.startswith("error/"): continue sys.stderr.write("{}\n".format(file_name)) number_of_lines = 1000 # 大きすぎると一度に取得するサイズが1MBを超えてしまい、 # ページネーションが途切れてしまう marker = "0" while(marker): sys.stderr.write("{} {}\n".format(file_name, marker)) log = rds_client.download_db_log_file_portion( DBInstanceIdentifier = instance_id, LogFileName = file_name, Marker = marker, NumberOfLines = number_of_lines ) sys.stdout.write(log["LogFileData"]) if log["AdditionalDataPending"]: marker = log["Marker"] else: marker = False break
バージョン情報
$ pip list | grep boto boto3 1.14.63 botocore 1.17.63
ダウンロード結果を標準出力しますので、以下のように実行します。
$ python download-rds-log.py > log.txt
Ruby
RubyのAWS SDKは初めて触りましたが、ページネーションがenumerableになっており、Rubyらしく使いやすいです。
Gemは以下をインストールしておきます。
$ gem install aws-sdk-core aws-sdk-rds
require 'aws-sdk-core' require 'aws-sdk-rds' require 'yaml' require 'pp' profile = "default" instance_id = "foo" Aws.config[:credentials] = Aws::SharedCredentials.new(profile_name: profile) rds_client = Aws::RDS::Client.new() rds_client.describe_db_log_files(db_instance_identifier: instance_id).each do |files| files.describe_db_log_files.each do |file| file_name = file.log_file_name next if file_name !~ /\Aerror/ STDERR.puts("%s %d" % [file_name, file.size]) number_of_lines = 1000 # 大きすぎると一度に取得するサイズが1MBを超えてしまい、 # ページネーションが途切れてしまう i = 0 rds_client.download_db_log_file_portion( db_instance_identifier: instance_id, log_file_name: file_name, marker: "0", number_of_lines: number_of_lines).each_page do |data| STDERR.puts("%s %s" % [file_name, i]) STDOUT.print(data.log_file_data) i += 1 end end break end
バージョン情報
$ gem list | grep aws aws-eventstream (1.1.0) aws-partitions (1.385.0) aws-sdk-core (3.109.1) aws-sdk-rds (1.104.0) aws-sigv4 (1.2.2)
ダウンロード結果を標準出力しますので、以下のように実行します。
$ ruby download-rds-log.rb > log.txt