レタスのかわをぜんぶむく

ぜんぶむきます

CloudWatch Logs Insightsのみで指定期間について日付を無視した時間帯毎の頻度をグラフ化する

久々に技術ネタ(小粒)。

CloudWatch Logs Insightsでは指定したロググループのログイベントを専用のクエリ言語で検索したり視覚化することができる。
検索結果は明示的に可視化を利用しなくとも、時系列順に下図のような形でヒストグラムで表示される。
(データは適当に生成した雑なデータ)

f:id:uskey:20220125222632p:plain
3日分のログの発生分布

stats句を利用したクエリでは簡単な集計を行うことが可能で、ドキュメント内でもbin関数を利用した時系列データの視覚化
フィールド別にグループ化されたログデータの視覚化が取り上げられている。

これらの機能は直感的で利用しやすく強力で、例えばアクセスログを対象とした視覚化の場合
前者では例えばAPIに対する5分毎アクセス数を視覚化したり、後者ではHTTPステータス毎の割合を視覚化したりなどが行える。

一方で少し加工した時間情報を利用した集計を行いたい時はひと手間が必要になる。
時系列データの集計に利用されるbin関数では対象とする値は@timestamp固定となっているため、例えばタイトルで示したような指定期間について日付を無視した時間帯ごとの頻度を見たい、といった場合には自前でstats句に渡すfieldを定義する必要がある。

生の@timestampTimeStamp型として扱われており、そこから日や時間や分などのフィールドを指定して取り出すことはできないため、stats句に渡すfieldとしてtoMillis関数でエポックミリ秒に変換して1日のミリ秒数で剰余を取ったものを1時間のミリ秒数で割り、最後にfloor関数で切り下げたものをhourとして定義する。

fields floor((toMillis(@timestamp) + 9 * 3600000) % 86400000 / 3600000) as hour , @message
| stats count(*) as access by hour
| sort by hour asc

(JST変換のために 9 * 3600 * 1000を加えている。)

f:id:uskey:20220125222727p:plain
3日分のデータを日付を無視して1時間毎にまとめた

下記は15分単位の棒グラフとして出力したケース。
アプローチとしては大きく変わらないが、hhmmを4桁の数字として扱うために時と分で分けて計算した上で加算している。

fields (floor((toMillis(@timestamp) + 9 * 3600000) % 86400000 / 3600000) * 100 + 
floor((toMillis(@timestamp) + 9 * 3600000) % 86400000 / 36000 % 100 / 25) * 15) as hhmm , @message
| stats count(*) as access by hhmm
| sort by hhmm asc

f:id:uskey:20220125222759p:plain
3日分のデータを日付を無視して15分毎にまとめた

stats句での視覚化で使える棒グラフでは表示数の上限が100件のためこの用途だと24*4=96でこれが最大の分解能。
この用途において、これ以上細かな単位で見たい場合はCloudWatch Logs Insights上の視覚化は利用できないため
素直にデータを吐き出して別で視覚化する必要がある。

また、追加の注意点として対応する単位時間にデータが存在しない範囲については棒が表示されない。
そのため、例えばアプリケーションログを対象としてシステムの動作時間帯を把握する用途か、最低でも15分に1度はアクセスがあるようなシステムのアクセスログを対象として利用するなどの前提が必要。
(後者はヘルスチェックがあるようなシステムであればクリアできるはず)


書いててかなり限定的な用途っぽいことに気づいたものの、誰か使うかもしれないので放流