Amazon RDSのログファイルをダウンロードする

Amazon Aurora (LTS, MySQL5.7互換)のSQLログをダウンロードしてS3に保存しようと思い調べた内容のメモです。

Arch Amazon Aurora

データベースログファイルのダウンロード

AWSのドキュメントには、次の手順でログファイルのダウンロードが紹介されています。

  1. 管理コンソール
  2. AWS CLI (download-db-log-file-portion)
  3. RDS API (DownloadDBLogFilePortion)

今回はプログラムで扱いたいので、この中ではRDS APIDownloadDBLogFilePortionがよさそうですが、次のように制約があり最大1MBしかダウンロードしてくれないようです。

Downloads all or a portion of the specified log file, up to 1 MB in size.

https://docs.aws.amazon.com/ja_jp/AmazonRDS/latest/APIReference/API_DownloadDBLogFilePortion.html

もう少し調べると、REST APIを用いたもので、downloadCompleteLogFIleという名前から要望通りのAPIが見つかりました。

REST を用いたログファイルの内容の読み取り

GET /v13/downloadCompleteLogFile/DBInstanceIdentifier/LogFileName HTTP/1.1
Content-type: application/json
host: rds.region.amazonaws.com

しかし、このAPIなぜか情報がこれしかないんですよね。IAMポリシーの「読み取り」権限にもあるので、正式なものですが検索しても公式ドキュメントが出てきません。なぜなのか?(もしかして使ってほしくない機能?)

早速、AWS APIの署名の例(Python)を参考にLaravelでも使いたいのでPHPで実装しようと思いましたが、PHPに移植するもの手間なので、一部AWS SDK for PHPを利用して動作するか試してみました。

参考

downloadCompleteLogFileでログファイルをダウンロードして保存する(サンプルコード)

次のように一部AWS SDKを利用して実装してみたところ動作しました。

これにRDSClientdescribeDBLogFilesを組み合わせれば、ログを全て取得することも可能かと思います。

注意事項! AWSではハードコードされた認証情報の使用を推奨していません

use Aws\Credentials\Credentials;
use Aws\Signature\SignatureV4;
use GuzzleHttp\Client;
use GuzzleHttp\Psr7\Request;

// IAM User
$accessKey = '';
$secretAccessKey = '';

// URI
$service = 'rds';
$region = 'ap-northeast-1';
$dbInstanceId = '';
$logFileName = 'general/mysql-general.log';

$uri = 'https://'.
        $service.'.'.
        $region.
        '.amazonaws.com/v13/downloadCompleteLogFile/'.
        $dbInstanceId.'/'.
        $logFileName;

// Request
$request = new Request('GET', $uri);

// Credential
$credential = new Credentials($accessKey, $secretAccessKey);

// SignatureV4
$sigV4 = new SignatureV4($service, $region);
$signRequest = $sigV4->signRequest($request, $credential);

// SendAsync
$client = new Client();
$promise = $client->sendAsync($signRequest)->then(function($response) {
    // Save
    file_put_contents('/tmp/sql.log', $response->getBody());
});
$promise->wait()