😽

CloudWatch Logs Insights を使って SlowQuery ログの検索をする

2024/09/03に公開

CloudWatchLogs にだけログが存在しているケースというのはままあります。
e.g. RDS の SlowQuery Log を CloudWatchLogs に保存。お金の節約のため S3 には保存しない。

そういう場合には、CloudWatch Logs Insights という機能を使うことで、SQLライク(といえるかわかりませんが)な構文で検索を行なうことができます。

https://docs.aws.amazon.com/ja_jp/AmazonCloudWatch/latest/logs/AnalyzingLogData.html

ここでは簡潔に、MySQL の SlowQuery Log を検索するための構文について記載します。

SlowQuery Log format

# Time: 2024-09-03T03:10:54.745582Z
# User@Host: sada[sada] @  [xxx.xxx.xxx.xxx]  Id: 1234567890
# Query_time: 0.518726  Lock_time: 0.000040 Rows_sent: 0  Rows_examined: 1493362
SET timestamp=1725333054;
select * from `sada`;

構造的ログとは言えない独特のフォーマットになっています。

単純にログの件数をカウント

以下は CloudWatch Logs Insights の Web Console からの操作を想定しています。
画面上では、対象となるデータの期間を指定できるようになっているので、ここで指定した範囲のデータが検索対象になります。

クエリーは以下。

stats count()

LogStream を指定

複数の条件がある場合は、| でつなぎます。

@logStream = 'sada'
 | stats count()

Query_time が一定の値より遅いものを検索

以下では1.0 秒以上かかった SQL を取得します。

fields @timestamp, @message
| parse @message /Query_time:\s*(?<Query_time>[0-9]+(?:\.[0-9]+)?)\s*[\s\S]*?;/
| filter Query_time >= 1.0
| stats count()

CloudWatch Logs Insights では正規表現を用いてログの中の特定の条件の文字列を抽出することができます。
上記では parse Syntax を使用して、ログから Query_time の条件に合致するデータを抽出しています。

抽出したデータは、filter Syntax を使って検索対象にすることができます。

詳しい Syntax は以下。

https://docs.aws.amazon.com/ja_jp/AmazonCloudWatch/latest/logs/CWL_QuerySyntax.html

AWS CLI からの実行

start-query コマンドを実行して query_id を取得。
取得した query_id を条件にして get-query-results コマンドを実行すると現在のステータスが取得できます。クエリーが実行完了(Complete)すると結果が取得できます。

# query_id=$(aws logs start-query \
  --log-group-name "sada" \
  --start-time $(date -v -1H +%s) \
  --end-time $(date +%s) \
  --query-string "stats count()" \
  --region "ap-northeast-1" \
  --query "queryId" \
  --output text)

# echo $query_id
3697ad4a-9b70-48a7-ae01-4e433a57e3dc

# query_status=$(aws logs get-query-results --query-id $query_id --region ap-northeast-1 --query "status" --output text)

# echo $query_status
Complete

# aws logs get-query-results --query-id $query_id --region ap-northeast-1
{
    "results": [
        [
            {
                "field": "count()",
                "value": "2487"
            }
        ]
    ],
    "statistics": {
        "recordsMatched": 2487.0,
        "recordsScanned": 2533.0,
        "bytesScanned": 2813186.0
    },
    "status": "Complete"
}

プログラムからの実行

各 AWS SDK からももちろん実行可能です。
以下は JavaScript SDK での実行例。
@aws-sdk/client-cloudwatch-logs の import 記述は割愛。

  const client = new CloudWatchLogsClient({ region: 'ap-northeast-1' });
  const now = Math.floor(Date.now() / 1000);
  const params = {
    logGroupName: 'sada',
    startTime: now - 3600,
    endTime: now,
    queryString: 'stats count()',
  };

  const startQueryCommand = new StartQueryCommand(params);
  const queryResponse = await client.send(startQueryCommand);
  const { queryId } = queryResponse;
  let status = 'Scheduled';
  let results;

  while (status === 'Running' || status === 'Scheduled') {
    const getQueryResultsCommand = new CloudWatchLogs.GetQueryResultsCommand({ queryId });
    const getQueryResultsResponse = await client.send(getQueryResultsCommand);
    ({ status, results } = getQueryResultsResponse);

    if (status === 'Complete') {
      break;
    } else {
      await new Promise(resolve => setTimeout(resolve, 1000));
    }
  }

  console.log(results)

IAM Role

CLI や SDK などから実行する際は以下の権限が必要です。

  • logs:StartQuery
  • logs:GetQueryResults

費用

1GBあたりUSD 0.005とのことです。
https://aws.amazon.com/jp/cloudwatch/pricing/

Discussion