CloudWatch Logs Insightsに追加された新コマンド・関数25個を検証してみた(2026年7月版)
はじめに
2026年7月15日、CloudWatch Logs Insights に25個の新しいコマンド・関数が追加されました。
5月版(13個)、6月版(23個)に続く第3弾で、3か月の累計は61個になります。今回は行単位のシーケンス操作、セッション化、外れ値検出、CIDR ルックアップなど、分析寄りの機能が中心です。
追加された機能の一覧です。
| カテゴリ | 関数・コマンド名 | 用途 |
|---|---|---|
| 型変換 | hexToAscii | 16進文字列をASCIIへ変換 |
| 型変換 | hexToDec | 16進文字列を10進数へ変換 |
| 型変換 | decToHex | 10進数を16進文字列へ変換 |
| 日時 | parseDate | 日付文字列をエポックミリ秒へパース |
| 日時 | formatDate | タイムスタンプをstrftime形式で整形 |
| 日時 | queryStartTime | クエリウィンドウ開始時刻を返す |
| 日時 | queryEndTime | クエリウィンドウ終了時刻を返す |
| 日時 | queryTimeRange | クエリウィンドウ幅をミリ秒で返す |
| 行シーケンス | autoregress | 前行の値をラグフィールドとして生成 |
| 行シーケンス | accum | 数値フィールドの累積合計を計算 |
| 行シーケンス | filldown | 直前のnon-null値で欠損を前方補完 |
| 行シーケンス | fillmissing | 空の時間ビンに指定値を挿入 |
| セッション | sessionize | アイデンティティ+非活動ギャップでセッション化 |
| 統計 | variance | 母分散を計算 |
| 統計 | topk | 上位k個の頻出値を返す |
| 統計 | countFrequent | フィールド値の近似カウントを降順で返す |
| 文字列 | messageSize | フィールドのバイト長を返す |
| JSON | jsonArraySize | JSON配列文字列の要素数を返す |
| JSON | jsonArrayContains | JSON配列に指定値が含まれるか判定 |
| 条件 | isNumeric | フィールド値が数値かどうか判定 |
| クエリ合成 | where | filterコマンドのエイリアス |
| 分析 | outlier | IQRベースの外れ値検出 |
| 時間比較 | logcompare | 現在と過去の時間ウィンドウを比較 |
| クエリ合成 | appendcols | サブクエリのカラムを行位置で結合 |
| ルックアップ | cidrlookup | IPをCIDR範囲でlookup tableとマッチ |
3か月の追加傾向を比較すると、月ごとに機能の方向性が異なっています。
| 時期 | 追加数 | 傾向 |
|---|---|---|
| 2026年5月 | 13個 | 読む・整形(parse拡張、display、文字列関数) |
| 2026年6月 | 23個 | 集計・判定(条件分岐、統計関数、IP判定) |
| 2026年7月 | 25個 | 分析・セッション化・結合(行操作、outlier、lookup) |
本記事では、これら25個をリージョン us-east-1 のロググループ /test/insights-new-2026-07(テストデータ60件)に対して実際に実行しました。確認できた挙動と実用上の注意点をまとめます。検証日は 2026-07-17 です。
検証内容
型変換・エンコーディング
16進数と ASCII 文字列・10進数を相互変換する hexToAscii、hexToDec、decToHex の3関数です。
filter ispresent(hex_ascii)
| display hex_ascii, hexToAscii(hex_ascii) as ascii_text, hex_num, hexToDec(hex_num) as dec_val, decimal, decToHex(decimal) as hex_out
| hex_ascii | ascii_text | hex_num | dec_val | decimal | hex_out |
|---|---|---|---|---|---|
| 436c6f7564576174636820496e736967687473 | CloudWatch Insights | 7fff | 32767 | 32767 | 0x7fff |
| 576f726c64 | World | 1a | 26 | 26 | 0x1a |
| 48656c6c6f | Hello | ff | 255 | 255 | 0xff |
hexToAscii は16進数文字列を ASCII 文字列へ変換します。38桁(19バイト)の入力から "CloudWatch Insights" が復元でき、可変長の入力に対応していました。hexToDec は 0x プレフィックスなしの小文字16進を入力として受け付け、10進数を返します。逆方向の decToHex は、出力に 0x プレフィックス付きの小文字16進を返しました。
日時関数
日付文字列とタイムスタンプの相互変換を担う parseDate・formatDate と、クエリウィンドウ自体の時刻を参照する queryStartTime・queryEndTime・queryTimeRange が追加されました。計5関数をまとめて検証します。
parseDate と formatDate の検証結果です。
filter ispresent(date_str)
| display event, date_str, parseDate(date_str, "yyyy-MM-dd", "UTC") as parsed, formatDate(@timestamp, "%Y-%m-%d %H:%M:%S", "UTC") as fmt
| event | date_str | parsed | fmt |
|---|---|---|---|
| rollback | 2026-07-01 | 2026-07-01 00:00:00.000 | 2026-07-16 18:09:23 |
| release | 2026-07-10 | 2026-07-10 00:00:00.000 | 2026-07-16 18:09:18 |
| deploy | 2026-07-15 | 2026-07-15 00:00:00.000 | 2026-07-16 18:09:13 |
parseDate は Java の DateTimeFormatter パターンを第2引数に取り、第3引数でタイムゾーンを指定します。返却値はエポックミリ秒ですが、Logs Insights コンソール上ではタイムスタンプ形式で描画されます。formatDate は strftime 形式のフォーマット文字列を使用し、公式ドキュメントではエイリアス strftime でも呼び出せると記載されています。
続いて、クエリウィンドウの時刻を返す3関数です。
fields queryStartTime() as qst, queryEndTime() as qet, queryTimeRange() as qtr | limit 1
| qst | qet | qtr |
|---|---|---|
| 2026-07-16 16:13:38.000 | 2026-07-16 18:14:38.999 | 7260999 |
queryTimeRange はクエリウィンドウの幅をミリ秒で返します。約2時間のウィンドウに対して 7260999ms が返っており、集計や正規化の基準値としてクエリ内で利用できます。
行シーケンス・null処理
行の並び順に依存する操作として autoregress、accum、filldown が、時間ビンの欠損を補う操作として fillmissing が追加されました。前者3コマンドでは、パイプラインの前段で sort @timestamp asc を指定する必要があります(検証で確認した動作)。
autoregress は前行の値をラグフィールドとして新規カラムに展開します。
filter ispresent(metric) | sort @timestamp asc | fields @timestamp, value | autoregress value p=1-2
| @timestamp | value | value_p1 | value_p2 |
|---|---|---|---|
| 2026-07-16 18:09:43.682 | 10 | ||
| 2026-07-16 18:09:48.682 | 12 | 10 | |
| 2026-07-16 18:09:53.682 | 11 | 12 | 10 |
| 2026-07-16 18:09:58.682 | 13 | 11 | 12 |
| 2026-07-16 18:10:03.682 | 12 | 13 | 11 |
p=1-2 を指定すると、1行前の値を持つ value_p1 と、2行前の値を持つ value_p2 が自動生成されます。先頭行はラグ未満のため空になります。前行の値が参照可能になるため、value - value_p1 で差分を取るような派生カラムの作成にも使えます。
accum は数値フィールドの累積合計を計算します。
filter ispresent(metric) | sort @timestamp asc | fields @timestamp, value | accum value AS running_total
| @timestamp | value | running_total |
|---|---|---|
| 2026-07-16 18:09:43.682 | 10 | 10 |
| 2026-07-16 18:09:48.682 | 12 | 22 |
| 2026-07-16 18:09:53.682 | 11 | 33 |
| 2026-07-16 18:09:58.682 | 13 | 46 |
| 2026-07-16 18:10:03.682 | 12 | 58 |
filldown は直前の non-null 値で欠損を前方補完します。
filter ispresent(sensor) | sort @timestamp asc | fields @timestamp, sensor, region, reading | filldown region
| @timestamp | sensor | region | reading |
|---|---|---|---|
| 2026-07-16 18:11:23.682 | temp-1 | us-east-1 | 22.5 |
| 2026-07-16 18:11:28.682 | temp-1 | us-east-1 | 23.1 |
| 2026-07-16 18:11:33.682 | temp-1 | us-east-1 | 22.8 |
| 2026-07-16 18:11:38.682 | temp-1 | eu-west-1 | 19.2 |
| 2026-07-16 18:11:43.682 | temp-1 | eu-west-1 | 19.5 |
元データでは2・3・5行目の region が欠損していましたが、filldown により直前の non-null 値で補完されました。センサーデータやイベントログで、コンテキスト情報が一部のレコードにしか記録されない場合に有効です。
fillmissing は stats ... by bin() の後に使用し、データの無い時間ビンに指定値を挿入します。
filter metric = "cpu_usage" | stats avg(value) as avg_val by bin(10s) | fillmissing with 0 for avg_val
| bin(10s) | avg_val |
|---|---|
| 2026-07-16 18:27:50.000 | 0 |
| 2026-07-16 18:27:40.000 | 0 |
| 2026-07-16 18:27:30.000 | 0 |
表示された3行はいずれもデータの無いビンで、fillmissing により 0 が挿入されました。今回の検証データでは表示範囲内に実データのあるビンが含まれなかったため、すべて 0 になっています。
セッション化
sessionize は、アイデンティティフィールドと非活動ギャップ(maxspan)をもとに、イベント列をセッションへ分割するコマンドです。
filter ispresent(userId) | sort @timestamp asc | fields @timestamp, userId, action, deviceId | sessionize userId, deviceId maxspan 20s
| @timestamp | userId | action | deviceId | session_id |
|---|---|---|---|---|
| 2026-07-16 18:11:48.682 | user-A | login | mobile | user-A\x1fmobile-1 |
| 2026-07-16 18:11:53.682 | user-A | view_page | mobile | user-A\x1fmobile-1 |
| 2026-07-16 18:11:58.682 | user-B | login | desktop | user-B\x1fdesktop-1 |
| 2026-07-16 18:12:03.682 | user-A | click | mobile | user-A\x1fmobile-1 |
| 2026-07-16 18:12:08.682 | user-B | view_page | desktop | user-B\x1fdesktop-1 |
| 2026-07-16 18:12:13.682 | user-B | logout | desktop | user-B\x1fdesktop-1 |
| 2026-07-16 18:12:18.682 | user-A | login | mobile | user-A\x1fmobile-1 |
| 2026-07-16 18:12:23.682 | user-A | purchase | mobile | user-A\x1fmobile-1 |
userId と deviceId の組み合わせをアイデンティティとして、maxspan 20s 以内に連続するイベントを同一セッションへまとめました。session_id フィールドが自動生成されます。今回の検証では user-A\x1fmobile-1 のように、識別子フィールドの値が制御文字 \x1f(Unit Separator)で連結され、末尾に連番が付与される形式で表示されました。この形式は公式ドキュメントに明記されていないため、実装依存の可能性があります。maxspan のデフォルト値は公式ドキュメントによれば30分です。ユーザー行動のセッション分析を Logs Insights 単体で行えるようになりました。
統計コマンド
統計系として variance(母分散)、topk(上位k頻出値)、countFrequent(近似頻度カウント)が追加されています。
variance を、既存の stddev・avg と並べて確認しました。
filter ispresent(response_time) | stats variance(response_time) as v, stddev(response_time) as sd, avg(response_time) as avg_rt
| v | sd | avg_rt |
|---|---|---|
| 4788776.5156 | 2188.3273 | 1017.4667 |
variance は母分散(population variance)を返します。stddev の値を2乗するとほぼ variance に一致し(2188.3273² ≒ 4788776)、標準偏差と整合していました。
topk は上位k個の頻出値とその出現回数を返します。
filter ispresent(status) | stats topk(3, status)
| status | count |
|---|---|
| 200 | 10 |
| 403 | 2 |
| 500 | 2 |
公式ドキュメントでは by 句との併用は不可と記載されています。
countFrequent はフィールド値の組み合わせごとに近似カウントを算出し、降順で返します。
filter ispresent(method) | countFrequent method, status
| method | status | _approxcount |
|---|---|---|
| GET | 200 | 5 |
| POST | 200 | 5 |
| GET | 500 | 2 |
| GET | 403 | 2 |
| POST | 401 | 1 |
_approxcount フィールドが自動生成されます。
文字列関数
messageSize はフィールドのバイト長を返す関数です。
fields messageSize(@message) as sz, @message | sort sz desc | limit 5
| sz | @message (抜粋) |
|---|---|
| 147 | {"level": "INFO", "service": "payment-service"...} |
| 146 | {"level": "INFO", "service": "payment-service"...} |
| 145 | {"level": "INFO", "service": "payment-service"...} |
JSON関数
jsonArraySize と jsonArrayContains は、JSON配列文字列を対象にした関数です。
filter ispresent(role_list)
| display user, role_list, jsonArraySize(role_list) as role_count, jsonArrayContains(role_list, "admin") as is_admin
| user | role_list | role_count | is_admin |
|---|---|---|---|
| charlie | ["admin","viewer"] | 2 | 1 |
| bob | ["viewer"] | 1 | 0 |
| alice | ["admin","editor","viewer"] | 3 | 1 |
jsonArraySize は配列の要素数を、jsonArrayContains は指定値を含めば 1、含まなければ 0 を返しました。これらの関数は自動パースで roles.0 のように展開された配列には使えず、文字列のまま保持されたフィールドに適用する必要があります。
条件バリデーション
isNumeric はフィールド値が数値として解釈できるかを判定します。
filter ispresent(field_a)
| display field_a, isNumeric(field_a) as a_num, field_b, isNumeric(field_b) as b_num
| field_a | a_num | field_b | b_num |
|---|---|---|---|
| 0 | 1 | 99.9 | 1 |
| not_number | 0 | 100 | 1 |
| 42 | 1 | hello | 0 |
クエリ合成(where)
where は filter コマンドのエイリアス(公式ドキュメントでは "grammar alias for the filter command")で、SQL に慣れたユーザー向けです。
where response_time > 1000 | display service, response_time
| service | response_time |
|---|---|
| notification | 1100 |
| notification | 2045 |
| api-gateway | 8901 |
| auth-service | 1523 |
データ分析(outlier)
outlier は、IQR(四分位範囲)にもとづく統計的な外れ値検出コマンドです。公式ドキュメントでは "Detects statistical outliers based on the interquartile range (IQR)" と説明されています。
filter metric = "cpu_usage" | sort @timestamp asc | fields @timestamp, value | outlier mark=true param=1.5 value
コマンドは受け付けられ matched=20 となりましたが、出力が1件に限定される挙動を確認しました。原因は未確認です。実用時はより大きなデータセットでの再検証を推奨します。公式ドキュメントによれば、mark=true を指定すると外れ値の判定結果を示す真偽値のマーカーフィールドが追加されます。今回の検証環境では、このフィールドは _is_outlier として表示されました。オプションとして action=remove/transform、mark=true、param(IQR係数)が用意されています。
logcompare
logcompare は、現在の時間ウィンドウと過去のウィンドウを比較するコマンドです。
クエリウィンドウ2時間、timeshift 1h の条件で検証しました。"Diff doesn't support overlap between two time ranges we compare" エラーが発生します。timeshift がクエリウィンドウの幅未満だと比較対象の時間範囲が重なり、このエラーになります。検証で確認した動作であり、参照した公式ドキュメントではこの制約条件の明記は見当たりませんでした。正常動作にはクエリウィンドウよりも大きい timeshift を指定する必要があります。
appendcols
appendcols は、サブクエリの結果カラムをメインクエリに行位置で結合するコマンドです。
filter ispresent(service)
| stats count(*) as cnt by service
| appendcols ( SOURCE '/test/insights-new-2026-07' | filter ispresent(response_time) | stats avg(response_time) as avg_rt by service )
| service | cnt | avg_rt |
|---|---|---|
| notification | 3 | 1070.6667 |
| search-service | 3 | 212.6667 |
| api-gateway | 3 | 3145 |
| payment-service | 3 | 84.3333 |
| auth-service | 3 | 574.6667 |
サブクエリには SOURCE 句が必須です。SOURCE を省略すると MalformedQueryException が発生します。結合はキーマッチではなく行位置(positional row matching)で行われます。今回の検証では、メインクエリとサブクエリの結果が同じ順序で返り、対応する値が正しく結合されました。実用時はメインクエリとサブクエリの双方で sort を指定し、行順序を明示的に揃えることを推奨します。
cidrlookup
cidrlookup は、IP アドレスを CIDR 範囲で lookup table とマッチさせ、対応する値を取得するコマンドです。
事前に lookup table を作成する必要があります。CloudWatch コンソールの Settings → Logs タブ → Lookup tables → Create lookup table から作成できます。CreateLookupTable API で CSV を直接アップロードする方法もあります。
今回使用した CSV は以下のとおりです。掲載している IP アドレスは RFC 5737 で定義されたドキュメンテーション用アドレスを含む検証用のダミー値です。
cidr,region,owner,network_type
198.51.100.0/24,us-west-2,external,public
10.0.0.0/8,us-east-1,internal,private
172.16.0.0/12,ap-northeast-1,internal,private
192.168.0.0/16,eu-west-1,internal,private
203.0.113.0/24,documentation,example,reserved
filter ispresent(ip)
| fields @timestamp, ip, service
| cidrlookup net_table ip AS cidr OUTPUT region, owner, network_type
| display ip, region, owner, network_type
| ip | region | owner | network_type |
|---|---|---|---|
| 198.51.100.10 | us-west-2 | external | public |
| 10.0.2.101 | us-east-1 | internal | private |
| 192.168.1.11 | eu-west-1 | internal | private |
| 172.16.0.6 | ap-northeast-1 | internal | private |
| 203.0.113.50 | documentation | example | reserved |
AS cidr で lookup table 内の CIDR カラム名を指定し、OUTPUT で取得するカラムを列挙します。結果を表示するには display で OUTPUT カラムを明示的に指定する必要がありました。
まとめ
2026年7月に追加された25個のコマンド・関数により、CloudWatch Logs Insights で扱えるログ分析の幅がさらに広がりました。
特に、autoregress・accum・filldown・fillmissing による時系列データの加工、sessionize によるユーザー行動のセッション化、outlier による外れ値検出は、障害調査や傾向分析に活用できそうです。さらに、logcompare では過去の時間帯との比較、cidrlookup ではIPアドレスへの属性付与、appendcols では複数の集計結果を横に並べた分析が可能になりました。
これらは、従来であればログをデータベースや外部の分析サービスへ転送して処理することもあった内容です。今回の機能追加によって、その一部を Logs Insights のクエリ内で実行できるようになりました。たとえば、次のようなログ調査に活用できます。
- メトリクス値の前回値との差分や累積値を確認する
- 欠損した時系列データやコンテキスト情報を補完する
- ユーザーやデバイス単位で一連の操作をセッション化する
- 応答時間や処理量の外れ値を抽出する
- 現在のログ傾向を過去の時間帯と比較する
- IPアドレスにネットワークや管理区分などの情報を付与する
行位置や時間範囲に依存するコマンドなど利用時に注意が必要な機能もありますが、調査途中の集計・加工を Logs Insights 内で完結できる場面が増えるアップデートです。
テストデータの構成と投入例(抜粋)
検証に使ったロググループとテストデータの投入方法を示します。以下は構成の抜粋であり、本文で使用した60件すべてを生成する完全なコードではありません。リージョンは us-east-1 を使用しました。
ロググループとログストリームを作成します。
aws logs create-log-group --log-group-name /test/insights-new-2026-07 --region us-east-1
aws logs create-log-stream --log-group-name /test/insights-new-2026-07 --log-stream-name test-stream --region us-east-1
以下は、60件のJSONログを生成したコードのうち、時系列メトリクスとhex変換用データの部分を抜粋したものです。
import json, time
now = int(time.time() * 1000)
events = []
# 例: 時系列メトリクス(20件)
for i, v in enumerate([10, 12, 11, 13, 12]): # 抜粋
events.append({
"timestamp": now + i * 5000,
"message": json.dumps({"metric": "cpu_usage", "value": v})
})
# 例: hex変換用
events.append({
"timestamp": now,
"message": json.dumps({
"hex_ascii": "436c6f7564576174636820496e736967687473",
"hex_num": "7fff", "decimal": 32767
})
})
# 以降、日付・JSON配列・セッション・CIDR用のログを同様に追加
with open("events.json", "w") as f:
json.dump(events, f)
生成したログを put-log-events で投入します。
aws logs put-log-events \
--log-group-name /test/insights-new-2026-07 \
--log-stream-name test-stream \
--log-events file://events.json \
--region us-east-1








