CloudWatch Logs Insightsに追加された新コマンド・関数23個を検証してみた(2026年6月版)

CloudWatch Logs Insightsに追加された新コマンド・関数23個を検証してみた(2026年6月版)

2026年6月にCloudWatch Logs Insightsへ追加された新コマンド・関数23個を検証しました。ハッシュ関数、IP判定、型変換、CSV/XMLパース、histogram、statsの多段パイプなどを実際のクエリで試し、確認できた挙動と注意点をまとめます。
2026.06.10

はじめに

2026年6月8日、Amazon CloudWatch Logs Insightsに23個の新コマンド・関数が追加されました。

https://aws.amazon.com/jp/about-aws/whats-new/2026/06/amazon-cloudwatch-logs-insights-new/

前回の記事では5月21日発表の13個を紹介しましたが、わずか1か月足らずで更に大幅な追加です。

https://dev.classmethod.jp/articles/cloudwatch-logs-insights-new-commands-functions-2026/

発表日 追加数 主なカテゴリ
5/21 13個 文字列操作、エンコード/デコード、logfmt パース、座標計算
6/8 23個 ハッシュ、IP判定、型変換、時系列分析、CSV/XMLパース、コマンド拡張

5月と6月で追加された機能の傾向を比較すると、クエリ言語としての方向性が見えてきます。

5月(13個) 6月(23個)
性格 ログ閲覧・整形ツール ログ分析基盤
主な作業 「読む・探す」 「集計する・判定する」
代替していたもの 目視確認、手動デコード Athena/pandas/Splunk での後処理
典型ユースケース 障害時の初動調査 セキュリティ監査、トラフィック分析、SLO集計

5月が「ログを読みやすくする」機能群だったのに対し、6月は「ログから答えを出す」機能群と言えます。

今回追加された新機能の一覧は以下のとおりです。

分類 項目
Hash functions md5, sha256
String functions strcontains(case-insensitive対応), split
Conditional logic if
Conversion functions toNumber, toInt, toLong, toDouble
IP functions ipv4ToNumber, isPrivateIP, isPublicIP, isReservedIP
Analytics functions rate, count_over_time, sum_over_time, offset, histogram
Parse functions parse CSV, parse XML, parse multi, values, addtotals
その他 limit any N, statsコマンド最大10段

※ 公式は「23 new query commands and functions」としています。上記はparse CSV/XML/multi等を個別に展開しているため項目数が前後します。公式は構文拡張等をまとめてカウントしており、本記事では公式の「23」をそのまま使用します。

本記事ではこれらを実際に動かし、動作結果を確認していきます。

検証環境

  • リージョン: us-east-1
  • ロググループ: /test/insights-new-2026-06
  • テストデータ: JSON形式、CSV形式、XML形式、時系列データ。架空のユーザーID・サービス名・IPアドレスを使用しています(IPはRFC 5737 TEST-NET、RFC 1918プライベート範囲、8.8.8.8等の公知アドレスで構成)

ハッシュ関数(md5, sha256)

md5sha256 はフィールドの値からハッシュ値を生成する関数です。ログ内のユーザーIDなどをハッシュ化して表示したい場合に使えます。

fields user_id, md5(user_id) as md5_hash, sha256(user_id) as sha256_hash
| limit 3
user_id md5_hash sha256_hash
usr_010 2fb6c8adce410db19ed04a7157b1ebd0 34f0365ae65242b4664ad6a1e4fe941c77caf56d7bd5aca88f1e9c6927012207
usr_009 3b24508aecac732b2dbf6d4e4bf9c4c2 8c231f143bc453047665350be67bc92029fe34375ddd45bee71164fcb278315c
usr_008 136ea0f2a0158fcbbd873dead2d60963 a8d79cc679fa29d08b483641f5d4b01faea2e81aa44edc7684fc2b936f32437c

md5は128bit(16進32文字)、sha256は256bit(16進64文字)の文字列が返されました。

文字列関数(strcontains, split)

split

split は文字列を指定した区切り文字で配列に分割します。

fields tags, split(tags, ',') as tag_array
| limit 3
tags tag_array
prod,warning,us-east-1 ["prod","warning","us-east-1"]
prod,normal,ap-northeast-1 ["prod","normal","ap-northeast-1"]
prod,critical,ap-northeast-1 ["prod","critical","ap-northeast-1"]

カンマ区切りのタグ文字列が配列形式(["prod","warning","us-east-1"])で展開されました。

strcontains

strcontains は文字列に特定の部分文字列が含まれるかを判定します。ドキュメントでは第3引数に true を指定するとcase-insensitive(大文字小文字を区別しない)検索になるとされています。

fields service,
  strcontains(service, 'auth') as has_auth_lower,
  strcontains(service, 'AUTH') as has_AUTH_upper,
  strcontains(service, 'AUTH', true) as has_AUTH_ci
| filter ispresent(service)
| sort service
| limit 5
service has_auth_lower has_AUTH_upper has_AUTH_ci
api-gateway 0 0 0
auth-service 1 0 0
cdn-edge 0 0 0
data-pipeline 0 0 0
geo-service 0 0 0

基本動作(第1・第2引数のみ)は正常です。auth-service に対して strcontains(service, 'auth')1 を返しています。

しかし、筆者環境では第3引数 true(case-insensitive モード)の効果を確認できませんでしたstrcontains(service, 'AUTH', true)auth-service に対して 0 を返しており、大文字小文字を区別したまま動作しているように見えました。引数自体はシンタックスエラーにならず受け付けられましたが、指定しても結果は変わりませんでした。

条件ロジック(if)

if は条件に基づいて値を返す関数です。if(条件, 真の場合の値, 偽の場合の値) の構文で、三項演算子のように使えます。

fields service, response_time,
  if(toNumber(response_time) > 1000, 'slow', 'fast') as speed
| limit 5
service response_time speed
queue-worker 2045 slow
search-service 156 fast
auth-service 8901 slow
notification 67 fast
geo-service 312 fast

レスポンスタイムが1000msを超えるリクエストを slow と分類できました。

前回(5月)追加の case 関数との使い分けとしては、if は単一条件の二択、case は多分岐に適しています。

変換関数(toNumber, toInt, toLong, toDouble)

文字列フィールドを数値型に変換する関数が4種類追加されました。それぞれの型変換の違いを確認します。

整数値の変換

fields response_time,
  toInt(response_time) as rt_int,
  toLong(response_time) as rt_long,
  toDouble(response_time) as rt_double,
  toNumber(response_time) as rt_number
| filter ispresent(response_time)
| limit 5
response_time rt_int rt_long rt_double rt_number
234 234 234 234 234
89 89 89 89 89
1523 1523 1523 1523 1523
5002 5002 5002 5002 5002
not_a_number (null) (null) (null) (null)

整数値の場合は4関数とも同じ結果でした。変換に失敗した場合(not_a_number)はエラーにならずnullが返ります。

小数値の変換(型の違いが顕著)

parse @message /latency=(?<lat_val>[\d.]+)/
| display lat_val,
    toInt(lat_val) as lat_int,
    toLong(lat_val) as lat_long,
    toDouble(lat_val) as lat_double,
    toNumber(lat_val) as lat_number
| filter ispresent(lat_val)
lat_val lat_int lat_long lat_double lat_number
890.12 890 890 890.12 890.12
45.7 45 45 45.7 45.7
123.456 123 123 123.456 123.456

小数を含む値で違いが現れました。

  • toInt / toLong: 小数点以下を切り捨てました(正の値のみ検証。負数でのfloor vs truncateの挙動は未確認です)
  • toDouble / toNumber: 小数点以下を保持し、今回の検証範囲では同様の結果でした
  • 型名からは、toIntとtoLongの差は32bit整数の範囲(約21億)を超える値などで現れる可能性がありますが、今回のテストデータでは差を確認できませんでした

用途としては、小数精度が不要な集計には toInt/toLong、小数を保持したい計算には toDouble/toNumber を使い分けることになります。

IP関数(ipv4ToNumber, isPrivateIP, isPublicIP, isReservedIP)

IPアドレスの数値変換と分類判定を行う4つの関数が追加されました。VPCフローログやALBアクセスログの分析に便利です。

fields ip,
  ipv4ToNumber(ip) as ip_num,
  isPrivateIP(ip) as is_private,
  isPublicIP(ip) as is_public,
  isReservedIP(ip) as is_reserved
| limit 10
ip ip_num is_private is_public is_reserved
10.255.255.1 184549121 1 0 0
52.194.x.x 885131796 0 1 0
192.0.2.1 3221225985 0 0 1
169.254.169.254 2852039166 0 0 1
100.64.0.1 1681915905 0 0 1
8.8.8.8 134744072 0 1 0
172.16.0.10 2886729738 1 0 0
10.0.0.55 167772215 1 0 0
203.0.113.50 3405803826 0 0 1
192.168.1.100 3232235876 1 0 0

※ パブリックIPの一部は下位オクテットをマスクしています(実際の検証では完全なIPアドレスを使用)。

今回用意したIPアドレスについては、期待した分類結果になることを確認できました。結果から読み取れる分類基準は以下のとおりです。

  • Private(isPrivateIP = 1): RFC 1918で定義されたプライベートアドレス範囲
    • 10.0.0.0/8、172.16.0.0/12、192.168.0.0/16
  • Reserved(isReservedIP = 1): 特殊用途に予約されたアドレス範囲
    • 169.254.0.0/16(リンクローカル)、100.64.0.0/10(CGN / Shared Address)
    • 192.0.2.0/24(TEST-NET-1)、203.0.113.0/24(TEST-NET-3)
  • Public(isPublicIP = 1): 今回試した範囲では、Private / Reservedに該当しない一般的なパブリックIPアドレスが 1 と判定されました

今回検証したIPv4アドレスの範囲では、3つの分類のいずれか1つだけが 1 になり、排他的な関係でした。ipv4ToNumber はIPアドレスを32bit整数に変換する関数です。IPレンジによるフィルタリング(ipv4ToNumber(ip) >= X and ipv4ToNumber(ip) <= Y)に活用できます。

分析関数(rate, count_over_time, sum_over_time, offset, histogram)

時系列データの分析に関連する5つの機能が追加されました。

count_over_time

count_over_time は時間範囲ごとのレコード数をカウントします。

filter metric = 'cpu_usage'
| stats count_over_time(*) as cot by bin(2m)
bin(2m) cot
2026-06-09 16:20:00.000 3
2026-06-09 16:18:00.000 4
2026-06-09 16:16:00.000 4
2026-06-09 16:14:00.000 4
2026-06-09 16:12:00.000 4
2026-06-09 16:10:00.000 1

今回のbin集計条件では count(*) と同等の結果でした。

sum_over_time

sum_over_time は時間範囲ごとの合計値を算出します。

filter metric = 'cpu_usage'
| stats sum_over_time(value) as sot by bin(2m)
bin(2m) sot
2026-06-09 16:20:00.000 277
2026-06-09 16:18:00.000 447
2026-06-09 16:16:00.000 383
2026-06-09 16:14:00.000 408
2026-06-09 16:12:00.000 384
2026-06-09 16:10:00.000 143

こちらも sum(value) と同等の結果でした。count_over_time/sum_over_time は時系列分析向けの命名と見られます。ただし今回のbin集計条件では count(*)/sum() との動作の違いを確認できず、完全に同じ動作かどうかは断定できません。

histogram

histogramby 句のグルーピング関数として使い、数値フィールドをバケットに分けて集計します。

filter metric = 'cpu_usage'
| stats count(*) as cnt by histogram(value, 50)
histogram(value, 50) cnt
50 10
100 10

第2引数がバケット幅で、結果にはバケットの下限値が表示されます。バケット幅を25に変更すると、より細かい分布が見えます。

filter metric = 'cpu_usage'
| stats count(*) as cnt by histogram(value, 25)
histogram(value, 25) cnt
50 2
75 8
100 6
125 4

histogramstats の集計関数ではなく by 句のグルーピング関数である点に注意してください。bin が時間軸のバケット化なのに対し、histogram は数値軸のバケット化です。

offset

offsetbin() の修飾子で、bin境界のアライメント(開始位置)をずらします。

filter metric = 'cpu_usage'
| stats count(*) as cnt by bin(5m) offset 5m
bin(5m) cnt
2026-06-09 16:20:00.000 3
2026-06-09 16:15:00.000 10
2026-06-09 16:10:00.000 7

構文は by bin(5m) offset 5m のようにbinの後ろに付けます。関数ではなく修飾子です。offset を使うとbin境界の開始位置をずらせるため、業務時間帯に合わせた集計区切りを設定できます。

rate

rate はbin内の数値フィールドの変化率を算出する関数です。rate(field, period) の構文で、第2引数に時間単位(1s, 1m, 2m 等)を指定します。

filter metric = 'cpu_usage'
| stats rate(value, 1s) as rate_1s, rate(value, 1m) as rate_1m, rate(value, 2m) as rate_2m by bin(5m)
bin(5m) rate_1s rate_1m rate_2m
2026-06-09 18:35:00.000 20 0.3333 0.1667
2026-06-09 18:30:00.000 20 0.3333 0.1667
2026-06-09 18:25:00.000 20 0.3333 0.1667

テストデータは2分間隔で値が+10ずつ増加する時系列です。結果から、periodによる値の比率は rate_1s : rate_1m : rate_2m = 60 : 1 : 0.5 でした。rate はbin内のフィールド値の合計変化量をperiodの秒数で割った値を返しています。periodが短いほど大きい値になります。

なお、第2引数に数値(60)を指定するとエラーになります。1m のような時間単位で指定する必要があります。

パース構文(parse CSV, parse XML, parse multi, values, addtotals)

ログのパース機能が大幅に拡張されました。CSV、XML、複数マッチの3つの新しいパースモードと、集計補助の valuesaddtotals が追加されています。

parse CSV

parse @message CSV as alias1, alias2, ... の構文でCSV形式のログを列ごとに分割します。

filter @logStream = 'test-csv-stream'
| parse @message CSV as ts, lvl, svc, val
| display ts, lvl, svc, val
ts lvl svc val
2026-06-10T00:04:00Z DEBUG cache 10
2026-06-10T00:03:00Z INFO search 50
2026-06-10T00:02:00Z WARN payment 175
2026-06-10T00:01:00Z ERROR auth-service 250

カンマ区切りの各値が順番にエイリアスへ格納されました。ヘッダー行とデータ行の区別はなく、全行がパース対象です。

parse XML

XML形式のログは、XPath風のパス式でフィールドを抽出します。

filter @message like /<event>/
| parse @message XML '/event/level' as xlevel
| parse @message XML '/event/service' as xsvc
| parse @message XML '/event/code' as xcode
| display xlevel, xsvc, xcode
xlevel xsvc xcode
WARN payment 429
INFO api-gw 200
ERROR auth 401

構文は parse @message XML '/要素/パス' as alias です。今回確認した範囲では /event/level のような単純な要素パスで値を取得できました。parse @message XML as doc のようなドキュメントオブジェクト全体の取得やドット記法でのアクセスはエラーになりました。複数フィールドを抽出する場合は、上記のように parse を複数回パイプして使用します。

parse multi

parse multi は正規表現の1行内の全マッチを個別レコードに展開します。key=value形式のログパースに威力を発揮します。

filter @message like /^level=/
| parse @message /(?<kname>\w+)=(?<kval>\S+)/ multi
| stats count(*) by kname
kname count(*)
level 3
service 3
latency 3
request_id 3

元データは3行で、各行に4つのkey=valueペアがあります。multi を付けることで3行 × 4ペア = 12レコードに展開され、キー名ごとの集計ができました。

multi なしの場合は1行につき最初のマッチのみが抽出されます。

parse @message /(?<kname>\w+)=(?<kval>\S+)/
| display kname, kval
kname kval
level WARN
level INFO
level ERROR

今回試した正規表現ベースの parse multi では、名前付きキャプチャグループ (?<name>...) を使うことで期待通りに抽出できました。一方、ドキュメントに記載のある as alias multi 構文は筆者環境ではシンタックスエラーになりました。

values

values はグループごとの重複なし(distinct)の値をまとめて返す集計関数です。

filter ispresent(service) and ispresent(level)
| stats values(service) as services by level
level services
INFO test-convert, api-gateway, geo-service, notification, search-service
WARN payment-service, queue-worker
ERROR auth-service, cdn-edge
DEBUG data-pipeline

今回のAPI結果ではカンマ区切りの文字列表現として確認できました。グループ内の一意な値を一覧する場合に便利です。

addtotals

addtotals は各行の数値フィールドを合計した列を追加するコマンドです。なお、表示されている列だけでなくクエリ中に存在する全数値フィールドも合算対象になるため、表示列の単純合計と Total の値は一致しないことがあります。

filter ispresent(response_time)
| fields toNumber(response_time) as rt, toNumber(response_time) * 2 as rt2
| addtotals
| limit 5
rt rt2 Total
2045 4090 8180
156 312 624
8901 17802 35604
67 134 268
234 468 936

デフォルトでは Total という列名で行合計が追加されます。addtotals fieldname=RowSum で列名をカスタマイズ可能です。

col=true を指定すると列合計行も追加されるはずですが、get-query-results APIのレスポンスには列合計行は含まれませんでした。コンソールUIでのみ表示される可能性があります。

その他(limit any, statsコマンド最大10段)

limit any

limit any は順序保証なしに任意のN件を返す構文です。通常の limit が直前の sort 順(未指定時はタイムスタンプ降順と見られる動作)で先頭N件を返すのに対し、limit any は順序が不要な場合により早く結果を得られる可能性があります。

fields service, level, ip | limit any 2
service level ip
search-service INFO 10.255.255.1
cdn-edge ERROR 52.194.x.x

大量のログがあるロググループで素早くサンプルを取得したい場合に有用です。

statsコマンド最大10段

stats をパイプで複数回つなげられる範囲が拡張され、Standard log classでは最大10段まで使用できるようになりました。

filter ispresent(service)
| stats count(*) as cnt by service, level
| stats sum(cnt) as level_total by level
| stats max(level_total) as max_level_total, min(level_total) as min_level_total
max_level_total min_level_total
5 1

3段のstatsをパイプで接続しています。1段目でサービス×レベルごとのカウント、2段目でレベルごとの合計、3段目で最大・最小を算出しました。

ドキュメントによると、Standard log classでは最大10段、Infrequent Access log classでは最大2段まで使用可能です。後続の stats では前段で定義したフィールドのみ参照可能で、sortlimit は最後の stats の後に配置する必要があります。

実用的な例として、時間帯ごとのメッセージ文字数の集計から傾向を把握するパターンを紹介します。

fields strlen(@message) as msg_len
| stats sum(msg_len) as total_chars by bin(5m)
| stats max(total_chars) as peak, min(total_chars) as lowest, avg(total_chars) as average
peak lowest average
1586 431 935.5

5分ごとのメッセージ文字数の合計を算出し、その中からピーク・最小・平均を取得しています。ログがASCII中心であれば、おおよそのメッセージサイズ傾向を見る用途にも使えます。このような「集計結果をさらに集計する」パターンが1クエリで完結するようになりました。

まとめ

5月に13個、6月に23個と、CloudWatch Logs Insightsのクエリ言語は短期間で大きく拡充されています。

今回追加された機能では、IP分類、CSV/XMLパース、histogram、複数段の stats などが含まれていました。ログを検索するだけでなく、集計・判定・傾向把握までクエリ内で行いやすくなっています。検証した範囲では、従来Athenaや外部ツールで後処理していたような分析の一部も、Logs Insightsだけで完結できる場面が増えそうです。

一方で、記事執筆時点の筆者環境では、strcontains の第3引数によるcase-insensitive検索は期待通りに動作しませんでした。

CloudWatch Logs Insightsは、「ログを検索・確認するツール」から、より分析用途にも使いやすいクエリ環境へと進化している印象です。今回の追加により、日々の調査や一時分析で使える場面がさらに広がりそうです。

参考リンク

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

この記事をシェアする

AWSのお困り事はクラスメソッドへ

関連記事