[アップデート] CloudWatch Logs Insightsがスケジュールされたクエリをサポートしたので試してみた
はじめに
みなさんこんにちは、クラウド事業本部コンサルティング部の浅野です。
Amazon CloudWatch LogsのLogs Insightsに定期的なクエリ実行機能が追加されました。
以前はログを定期的に確認するためにLambda関数を作成したり、別システムでAPIを定期的に呼び出してロググループ内のログを確認したりする必要がありましたが、今回のアップデートにより別途システムを構築せずに、簡単にCloudWatch Logs内のログを定期的にS3やEventBridgeに配信できるようになりました。
以下は公式ドキュメントから抜粋した文章です。
スケジュールされたクエリを使用すると、CloudWatch Logs Insights クエリを定期的に自動実行できます。ログデータを分析するために手動でクエリを実行する代わりに、スケジュールされたクエリを自動的に実行し、結果を Amazon S3 バケットや Amazon EventBridge イベントバスなどの宛先に送信するように設定できます。この自動化は、定期的なレポートの生成、傾向のモニタリング、ログ分析結果に基づく下流プロセスのトリガーなどに最適です。
仕様確認
スケジュールされたクエリはLogs Insightsで対応している言語をすべてサポートしています。
- Logs Insights クエリ言語 (Logs Insights QL)
- OpenSearch サービス パイプ処理言語 (PPL)
- OpenSearch サービス構造化クエリ言語 (SQL)
同時実行数の確認
同時に実行できるクエリはダッシュボードを含めてアカウント毎に合計30個です。
スケジュール設定する際は気をつけましょう。
ベストプラクティス
また、設定に関するベストプラクティスと注意事項に関しても以下の記載があります。これらの点に注意して設計する必要があります。
信頼性が高く効率的なスケジュールされたクエリ操作を確実に実行するには、次のベストプラクティスに従ってください。
クエリの最適化
- スケジュールを設定する前にクエリを手動でテストし、パフォーマンスと結果を確認します。
- クエリの早い段階でフィルタインデックスを使用してデータ処理を削減する
- 大量のロググループによるタイムアウトを回避するために時間範囲を制限する
- クエリの複雑さと実行時間の制限を考慮する
スケジュール計画
- 次回のスケジュールされた実行前にクエリが完了するようにすることで、重複実行を回避します。
- 時間範囲を設定するときは、ログ取り込みの遅延を考慮する
- 特定の時間にcron式を使用する
- クエリの同時実行制限に達しないようにスケジュールを分散させる
監視とメンテナンス
- 実行履歴を定期的に監視して、障害やパフォーマンスの問題を特定します。
- セキュリティを維持するために、IAM ロールを定期的に確認して更新します。
- 本番環境にデプロイする前に宛先のアクセシビリティをテストする
承認
- スケジュールされたクエリ用のすべてのAPIは、スケジュールされたクエリのリソースに対して承認を行い、ロググループなどの入力として受け取るリソースに対しては承認を行いません。それに応じてIAMポリシーを設定してください。
- API で渡された実行ロールを使用してログ グループの承認を管理する
参考:
やってみた
構成
今回は下記の構成にてスケジュールされたクエリを試してみました。

ログ記録システムの用意
まずはログを記録する用のLambda関数を作成します。
ログを見やすくするために「Powertools for AWS Lambda(Python)」レイヤーを追加してランダム値をログに出力するように記述しました。
- 名前: sequence-log-group-test-function
- ランタイム: python3.12
- アーキテクチャ: x86_64
- 実行用ロール: デフォルトで新規作成
- タイムアウト: 1分
- レイヤー : Powertools for AWS Lambda(Python) 公式レイヤー
arn:aws:lambda:{region}:017000801446:layer:AWSLambdaPowertoolsPythonV3-{python_version}-x86_64:18
import random
from aws_lambda_powertools import Logger, Tracer, Metrics
from aws_lambda_powertools.utilities.typing import LambdaContext
logger = Logger(service="demo_sequence_logging_app")
@logger.inject_lambda_context
def lambda_handler(event: dict, context: LambdaContext) -> dict:
# ランダム値の生成
random_value = random.randint(1, 100)
logger.info("Processing request", extra={
"random_value": random_value
})
return {
'statusCode': 200,
'body': f'Success - Random value: {random_value}'
}
{
"level": "INFO",
"location": "lambda_handler:12",
"message": "Processing request",
"timestamp": "2025-11-25 06:37:24,105+0000",
"service": "demo_sequence_logging_app",
"cold_start": true,
"function_name": "sequence-log-group-test-function",
"function_memory_size": "128",
"function_arn": "arn:aws:lambda:ap-northeast-1:************:function:sequence-log-group-test-function",
"function_request_id": "e069254e-86f1-4f75-8163-********",
"random_value": 94,
"xray_trace_id": "1-69254ea3-3bfeed1e************"
}
続いてLambda関数を定期的(10分に一回)実行するためのEventBridge Schedulerを以下の設定で作成しました。
- 名前: demo-sequence-logging-lambda-scheduler
- グループ名: default
- スケジュール式: rate(10 minutes)(10分ごと)
- タイムゾーン: Asia/Tokyo
- フレキシブルタイムウィンドウ: OFF
- 完了後のアクション: NONE
- ターゲット:
- Lambda関数ARN:
arn:aws:lambda:ap-northeast-1:************:function:sequence-log-group-test-function - 実行ロール: デフォルトの新規作成ロール
- リトライポリシー:
- 最大リトライ回数: 0
- 最大イベント保持時間: 86400秒(24時間)
作成後、ロググループを確認すると10分ごとに関数が実行されて、上記ログが記録されました。

ログ解析システムの用意
今回アップデート機能であるLogs Insightsの画面を確認してみます。

画面のように「Schedule query」ボタンが追加されていますね。下記のようにロググループとクエリを設定して選択してみます。
ロググループ: /aws/lambda/sequence-log-group-test-function
設定クエリ:
fields @timestamp, random_value, if(random_value >= 50, "HIGH", "LOW") as category
| filter ispresent(random_value)
| stats count() by category
このクエリは、ログ内に含まれる 各レコードのrandom_value の値を基に「50以上」なら「HIGH」、「50未満」なら「LOW」 の 2 つのカテゴリーに分類し、それぞれの件数を集計する処理を行います。
出力される値は以下2つです。
- category : 「HIGH」 or 「LOW」
- count() : カテゴリそれぞれの集計数
「Schedule query」を選択すると以下の画面になりました。

以下2つを画面の通りに設定しました。
- スケジュール名: test-insights-logs-query
- スケジュールの説明(オプション): 任意

定期的な時間の選択ですが、「Cron」か「カレンダー」ベースで設定できるようです。
カレンダーベースでの日時選択画面は以下のようになりました。

今回はスケジュールとして以下の設定を行いました。
- 「Query time range and timezone」: 「UTC時刻で直近1時間」(どこからどこまでのロググループをクエリ対象に設定するかの項目)
- 設定モード: cron式
- 設定式:
0 */1 ? * *(毎日1時間毎) - 開始日時(オプション) : 「なし」(記述しない場合は作成時から有効)
- 終了日時(オプション) : 「なし」(記述しない場合は無期限に有効)
続いて下に行くと「スケジュールされたクエリ実行のIAMロール」が必要でした。またクエリ結果を配信するためのS3バケットと配信用のIAMロールもここで設定可能です。

クエリ実行用IAMロールは公式ドキュメントに従い、以下のように設定しました。
-
ロール名: demo-sequence-logs-query-role
-
信頼ポリシー:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"Service": "logs.amazonaws.com"
},
"Action": "sts:AssumeRole"
}
]
}
- インラインポリシー: cloudwatch-logs-query-policy
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"logs:StartQuery",
"logs:StopQuery",
"logs:GetQueryResults",
"logs:DescribeLogGroups"
],
"Resource": "*"
}
]
}

作成後、以下のように「スケジュールされたクエリ」画面に反映されました。続いて挙動を確認していきます。

動作確認
作成した「test-insights-logs-query」を確認するとクエリがまだ実行されていない状態の画面は以下のようになりました。

クエリが実行されると以下のようにセレクタでどの時点の結果を確認するか選択できます。

「2025-11-25 05:00:00」を選択してみると以下のように結果が出力されました。
- LOW: 4
- HIGH: 2

実際にCloudWatchロググループの値を時系列で集計すると表の結果になり、LOWとHIGHのカウントが正しいことがわかります。
作成した「Query time range and timezone」の値を「1時間」に設定したので「2025-11-25 05:00:00(UTC)」で実行されたクエリの集計は「2025-11-25 04:00:00(UTC)」 ~ 「2025-11-25 04:59:00(UTC)」までの結果が集計されていることがポイントです。
| timestamp(UTC) | random_value | category |
|---|---|---|
| 2025-11-25 04:07:24,067+0000 | 18 | LOW |
| 2025-11-25 04:17:24,084+0000 | 9 | LOW |
| 2025-11-25 04:27:24,040+0000 | 90 | HIGH |
| 2025-11-25 04:37:24,054+0000 | 2 | LOW |
| 2025-11-25 04:47:24,064+0000 | 96 | HIGH |
| 2025-11-25 04:57:24,069+0000 | 28 | LOW |
CLIを使用して操作する(S3配信した場合も確認)
コンソール画面だけでなく以下のAWS CLI v2環境からS3配信設定を施したスケジュールクエリを作成してみました。
- CLIバージョン: 2.32.4
スケジュールクエリ作成コマンド
コマンドリファレンス: https://docs.aws.amazon.com/cli/latest/reference/logs/create-scheduled-query.html
設定内容
- クエリ名: s3-delivery-insights-logs-query
- クエリ言語: CWLI(CloudWatch Logs Insights)
- 状態: ENABLED(有効)
- クエリ文字列: コンソールで作成したものと同じ
- スケジュール式:
cron(*/10 * * * ? *)(10分ごとに実行) - 検索範囲: 過去3600秒(1時間)のログ
- 対象ロググループ:
/aws/lambda/sequence-log-group-test-function - クエリ実行ロール:
arn:aws:iam::************:role/demo-sequence-logs-query-role - 配信先URI:
s3://{バケット名}/cloudwatch-insights-scheduled-query-log/ - 配信用ロール:
arn:aws:iam::************:role/demo-sequence-logs-s3-put-role
aws logs create-scheduled-query \
--name "s3-delivery-insights-logs-query" \
--query-language "CWLI" \
--query-string 'fields @timestamp, random_value, if(random_value >= 50, "HIGH", "LOW") as category | filter ispresent(random_value) | stats count() by category' \
--schedule-expression "cron(*/10 * * * ? *)" \
--execution-role-arn "arn:aws:iam::************:role/demo-sequence-logs-query-role" \
--log-group-identifiers "/aws/lambda/sequence-log-group-test-function" \
--state "ENABLED" \
--start-time-offset 3600 \
--destination-configuration '{
"s3Configuration": {
"destinationIdentifier": "s3://{バケット名}/cloudwatch-insights-scheduled-query-log/",
"roleArn": "arn:aws:iam::************:role/demo-sequence-logs-s3-put-role"
}
}'
出力結果
{
"scheduledQueryArn": "arn:aws:logs:ap-northeast-1:************:scheduled-query:6c19de93-75bb-40a9-921b-eeb34117c8cd",
"state": "ENABLED"
}
S3配信に使用した配信用IAMロールの設定は以下の通りです。
-
demo-sequence-logs-s3-put-roleの内容
-
ロール名: demo-sequence-logs-s3-put-role
-
信頼ポリシー:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"Service": "logs.amazonaws.com"
},
"Action": "sts:AssumeRole"
}
]
}
- インラインポリシー: demo-sequence-logs-s3-put-policy
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"s3:PutObject"
],
"Resource": "arn:aws:s3:::{バケット名}/*"
}
]
}
スケジュールクエリ一覧取得コマンド
コマンドリファレンス: https://docs.aws.amazon.com/cli/latest/reference/logs/list-scheduled-queries.html
aws logs list-scheduled-queries --max-results 10
出力結果
{
"scheduledQueries": [
{
"scheduledQueryArn": "arn:aws:logs:ap-northeast-1:************:scheduled-query:6c19de93-75bb-40a9-921b-eeb34117c8cd",
"name": "s3-delivery-insights-logs-query",
"state": "ENABLED",
"lastTriggeredTime": 1764073200,
"lastExecutionStatus": "Complete",
"scheduleExpression": "cron(*/10 * * * ? *)",
"destinationConfiguration": {
"s3Configuration": {
"destinationIdentifier": "s3://{バケット名}/cloudwatch-insights-scheduled-query-log/",
"roleArn": "arn:aws:iam::************:role/demo-sequence-logs-s3-put-role"
}
},
"creationTime": 1764071887,
"lastUpdatedTime": 1764071887
}
]
}
S3への配信設定や最後にクエリを実行した日時(エポック秒)が表示されました。
スケジュールクエリ実行結果一覧取得コマンド
コマンドリファレンス: https://docs.aws.amazon.com/cli/latest/reference/logs/get-scheduled-query-history.html
START_TIME=$(date -v-20M +%s)
END_TIME=$(date +%s)
aws logs get-scheduled-query-history \
--identifier "s3-delivery-insights-logs-query" \
--start-time $START_TIME \
--end-time $END_TIME \
--max-results 10 \
--profile individual
出力結果
{
"name": "s3-delivery-insights-logs-query",
"scheduledQueryArn": "arn:aws:logs:ap-northeast-1:************:scheduled-query:6c19de93-75bb-40a9-921b-eeb34117c8cd",
"triggerHistory": [
{
"queryId": "6f62802a-82ac-48cc-8777-9d7aa4b1c9a3",
"executionStatus": "Complete",
"triggeredTimestamp": 1764072600,
"destinations": [
{
"destinationType": "S3",
"destinationIdentifier": "s3://{バケット名}/cloudwatch-insights-scheduled-query-log/",
"status": "COMPLETE",
"processedIdentifier": "s3://{バケット名}/cloudwatch-insights-scheduled-query-log/s3-delivery-insights-logs-query/2025/11/25/12/10/6f62802a-82ac-48cc-8777-9d7aa4b1c9a3.json"
}
]
}
]
}
クエリ結果では実行の結果がわかるだけでなく、統合したS3への配信が成功したかどうかも記載されます。今回は成功の結果を載せていますが、失敗の場合はstatus: "ERROR"が出力され、errorMessageにてエラー内容が確認可能です。
S3に配信したログの確認
S3に配信されたクエリ結果のログを確認してみましょう。

「prefix」の末尾に/を設定すると「/」という不要なフォルダが作成されるので、末尾にスラッシュは含めなくて良さそうですね。
"s3Configuration": {
"destinationIdentifier": "s3://{バケット名}/cloudwatch-insights-scheduled-query-log/", //末尾のスラッシュが不要だった
"roleArn": "arn:aws:iam::************:role/demo-sequence-logs-s3-put-role"
}

中身はこのようにJSON形式でログが記録されていました。
最後に
今回はアップデートされたCloudWatch Logsの機能であるスケジュールされたクエリを試してみました。コンソールやCLIを使って簡単に定期的なログ検索が実装できるので、今後活用するシチュエーションは多いのではないでしょうか。
また、クエリの結果をS3にシームレスに配信できるだけでなく、スケジュールクエリを作成したリージョンのEventBridgeの「default」バスに自動でクエリ結果が配信されるので通知やトリガーを組みたい場合にも非常に便利ですね!今回は以上です。







