【CloudWatchLogs】nextTokenについて

#はじめに
Boto3でCloudWatchLogsを触ろうと思った時、**nextToken**の意味が分からず理解にかなり時間がかかったため、もし同じような人がいればお役に立てればと思いまとめてみます。

#nextToken？
こちらの[Boto3の公式ドキュメント](https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/logs.html#CloudWatchLogs.Client.describe_log_groups)をみてみると、**nextToken**をキーに指定するメソッドが多くあります。

例えば、**describe_log_groups**でロググループの詳細情報を取得する時、公式では使い方は以下のように書かれています。

```Python:
import boto3
client = boto3.client('cloudwatch')

response = client.describe_log_groups(
    logGroupNamePrefix='string',
    nextToken='string',
    limit=123
)
```
一つずつみていくと、
logGroupNamePrefix：ロググループ名のPrefixを指定するんだな〜
limit：取得するロググループの個数の上限を設定するんだな〜
ということはざっくり理解できました。

では、nextTokenとは。
これは、ロググループを50個以上取得したい場合に指定するキーです。逆に言えば、取得したいロググループの個数が50以下の場合は指定しなくてOK。
上のlimitは最大値50までしか指定できず、このままでは51個以上のロググループを取得できません。それ以上のロググループを取得するには**nextTokenが鍵を握っています**。

上述した通り、デフォルトの状態だとロググループは50個までしか取得することはできません。なので、51個以上取得する場合、処理を繰り返す必要があります。その際、2回目以降の処理で「前回の処理ではここまで取得したよ」っていう情報を伝えるためのパラメータがnextTokenです。

実際に見てみましょう。Lambdaで行なっています。
以下の、nextTokenの値を取得するための簡単なLambda関数を実行しました。

```Python:lambda_function.py
import boto3
client = boto3.client('logs')

def lambda_handler(event, context):
    response = client.describe_log_groups(limit=50)
    print(response)
```
出力結果の後半を取り出したものがこちらです。(分かりやすいよう改行入れています。)

```js:出力結果
{'logGroupName': 'ww', 'creationTime': 1566816334747, 'metricFilterCount': 0, 'arn': 'arn:aws:logs:ap-northeast-1:xxxxxxxxxx:log-group:ww:*', 'storedBytes': 0},
{'logGroupName': 'xx', 'creationTime': 1566816200848, 'metricFilterCount': 0, 'arn': 'arn:aws:logs:ap-northeast-1:xxxxxxxxxx:log-group:x:*', 'storedBytes': 0}], 
'nextToken': 'xx', 'ResponseMetadata': {'RequestId': '88694680-6bc4-4c49-a498-587201a3ed19', 'HTTPStatusCode': 200, 'HTTPHeaders': {'x-amzn-requestid': '88694680-6bc4-4c49-a498-587201a3ed19', 'content-type': 'application/x-amz-json-1.1', 'content-length': '7824', 'date': 'Mon, 26 Aug 2019 11:05:56 GMT'}, 'RetryAttempts': 0}}
```

分かりにくいので説明すると、ロググループの詳細情報(describe)を50個取得しています。
今回、49番目にロググループ名'ww'の情報を、**50番目**にロググループ名**'xx'**の情報を取得しています。
そして**'nextToken': 'xx'**となっています。
２回目以降の処理(51番目以降も取得する処理)を行う場合、以下を実行することで前回の処理の続きのロググループ(51番目のロググループ)から処理を行うことができます。

```
client.describe_log_groups(limit=50, nextToken='xx')
```
このように、ロググループに関する処理を複数回に分けて実行する場合、
2回目以降の処理を1回目の処理の続きから正確に実行するために、nextTokenの値は不可欠なのです。

#コード例
以下に、全てのロググループの詳細情報を出力するコード例を載せておきます。

```Python:コード例
import boto3
client = boto3.client('logs')

def lambda_handler(event, context):
    next_token = None  
    for log_group_des in get_log_group_des(next_token=None):
        print(log_group_des)
    
def get_log_group_des(next_token):
    if next_token is not None and next_token != '':
        response = client.describe_log_groups(
            limit=50,
            nextToken=next_token
        )
    else:
        response = client.describe_log_groups(limit=50)
    if 'logGroups' in response:
        yield from response['logGroups']
    # ロググループが多くて50件(最大)を超えるようなら再帰呼出し
    if 'nextToken' in response:
        yield from get_log_group_des(next_token=response['nextToken'])
```



#まとめ
nextTokenとは

* ロググループを51個以上扱う際に使う
* その際、**前回の処理でどこまで処理したか**を次の処理に伝えるための値

少しでも誰かの役に立てれば幸いです。
最後までお読みいただきありがとうございます。


#参考文献
[Boto 3 Documentation](https://boto3.amazonaws.com/v1/documentation/api/latest/index.html?id=docs_gateway)
[Step FunctionsでCloudWatch LogsのロググループをS3へエクスポートする](https://www.soudegesu.com/aws/export-cloudwatchlogs-to-s3/)