【Tips】CloudWatch Logsのロググループを日本時間で範囲指定して絞り込む方法

# はじめに
CloudWatch Logsのログをコンソールで見ていると、キーワードの検索はできるものの、JSONの中身を絞って並べたりできないので、結局CLI経由でjqを使って確認がしたくなる。

というわけで、CLIでサクッと検索する方法を書き残しておこう。

→ (9/22追記)普通にCloudWatch Logs Insights使えばバッチリやりたいことが実現できたので追記した。前半の ```filter-log-events``` の方法はどうしてもCLIでやりたい場合だけ使うということで……。

# 絞り込み
## 方法①：時間帯
さて、だいたいAWSでCLIを使うとなるとEC2を使うことになると思うが、EC2のデフォルトのタイムゾーンはUTCに合わせられているため、日本時間で範囲指定しようとするとひと手間加えてあげる必要がある。

CloudWatch Logsの検索は

```shell-session
$ aws logs filter-log-events --log-group-name [ロググループ]
```

でグループ指定し、そこから ```--filter-pattern``` や ```--start-time``` で絞り込みを行っていくことになる。

そこで、開始日時を指定する場合は

```shell-session
--start-time `TZ=Asia/Tokyo date --date='2020-09-19 19:30:00.000' +%s%3N`
```

とすることで、日本時間からUTCのエポック秒に変換できる。
%3Nは、CloudWatch Logsの精度に合わせてミリ秒にしている。

## 方法②：「~~分前」
こちらはもっと単純。以下のように指定すれば良い。

```shell-session
--start-time `date -d '60 minutes ago' +%s%3N`
```

# jqでの編集
CLIではJSON出力の場合以下のように出力される。

```JSON
{
    "searchedLogStreams": [
        {
            "searchedCompletely": true, 
            "logStreamName": "ログストリーム名"
        },
        … 
    ], 
    "events": [
        {
            "ingestionTime": 1600511663343, 
            "timestamp": 1600511656660, 
            "message": "ログ出力内容", 
            "eventId": "イベントID", 
            "logStreamName": "ログストリーム名"
        },
        … 
    ]
}
```

なので、jqコマンドで

```shell-session
jq -r '.events[].message'
```

な感じでパイプしてあげる。

さらに、Pythonなんかで json.dumps() でdict型をログ出力していると、

```JSON
{
  "ingestionTime": 1600515840844,
  "timestamp": 1600515834171,
  "message": "{\"messageId\": \"xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx\", \"sendDatetime\": \"2020/09/19 11:42:21.746000\", \"receiveDateTime\": \"2020/09/19 11:43:54.171187\"}\n",
  "eventId": "イベントID",
  "logStreamName": "ログストリーム名"
}
```

な感じでエスケープされてしまってキレイにパースできないことがある。
こういう時は

```shell-session
jq -r '.events[].message | fromjson'
```

とすることで、キレイなJSONにすることができる。

定型のmessageの中身をさらに好きなようにjqで編集しよう！

# CloudWatch Logs Insightsを使う場合
## マネージメントコンソールでの検索
そもそもマネージメントコンソール画面であれば、日本時間で表示されているため、あまり考える必要はない。

Cloud Watch Logs Insights はクエリ検索のドキュメントが分かりにくいが、例えば、

```JSON
{
    "request_id": "9f60b4a7be765ba5542bdf3c110c4743",
    "id": "00000002",
    "writeDateTime": "2020-09-22 03:50:55.205087",
    "relayDateTime": "2020-09-22 03:50:56.350505",
    "processedDateTime": "2020-09-22 03:50:58.388614"
}
```

という形式でログの書かれた行をクエリしたい場合は、

```
fields request_id, id, writeDateTime, relayDateTime, processedDateTime
| filter request_id == '9f60b4a7be765ba5542bdf3c110c4743'
| sort id
```

を実行すれば、

![キャプチャ1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/111314/deab1ffb-27f3-5ea0-7810-f512949befcd.png)

といった感じでいい感じの出力を得られるし、右上の「結果をエクスポート」ボタンでCSV形式で取得することもできるので、超絶簡単にデータ編集ができるぞ！

## CLIでの検索
CLIでは以下のようなコマンドで検索をすることになる。
filter-log-events との違いは、```--start-time``` と ```--end-time``` が必須パラメータである点だ。ちなみに、この時刻はエポック秒で渡さなければいけないという微妙仕様なので、↑の絞り込み方法が使える。

```shell-session
$ aws logs start-query \
--log-group-name '/aws/lambda/dynamodb-streams-test-receive-function' \
--start-time `date -d '60 minutes ago' +%s%3N` \
--end-time `date +%s%3N` \
--query-string 'fields request_id, id, writeDateTime, relayDateTime, processedDateTime
| filter request_id == "9f60b4a7be765ba5542bdf3c110c4743"
| sort id'
```

これで出力された

```JSON
{
    "queryId": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
}
```

クエリIDで

```shell-session
$ aws logs get-query-results --query-id 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx'
```

とすると、検索結果が取得できる。

ただし、これで出力される結果が結局独自形式で jq コマンドで編集しないと使い物にならないので、CLI でクエリ検索する意味はあまりないかな……。