AWS Lambdaで独自にログを出力したい(標準のログを出したくない)

#問題
Lambda標準のログを抑止してCloudWatchLogsのコストを節約したい。けど、特定の場合にはログを出力したいといった問題を解決します。

#Lambdaコード
早速ですが、このような関数を用意してlambda_handler内で使用します。
必要な権限(IAMポリシー)は後で解説します。標準のログを出さないようにするのも、IAMポリシーの定義で行います。

```python
import boto3
import time
import datetime

logs_client = boto3.client('logs')
lgn = '/aws/lambda/PutLog'

def lambda_handler(event, context):
    put_log('test')
    put_log('テスト')

def put_log(message):
    
    # ロググループがない場合作成
    res = logs_client.describe_log_groups(
        logGroupNamePrefix=lgn
    )
    if not res['logGroups']:
        res = logs_client.create_log_group(
            logGroupName=lgn
        )
    
    # putするログストリームを取得
    lsn = datetime.datetime.now().strftime("%Y/%m/%d") + '[PutLog]'
    res = logs_client.describe_log_streams(
        logGroupName=lgn,
        logStreamNamePrefix=lsn,
    )
    
    # ログストリームがない場合作成し、取得
    if not res['logStreams']:
        res = logs_client.create_log_stream(
            logGroupName=lgn,
            logStreamName=lsn
        )
        res = logs_client.describe_log_streams(
            logGroupName=lgn,
            logStreamNamePrefix=lsn,
        )
    
    # シーケンストークンがある場合指定する
    if 'uploadSequenceToken' in res['logStreams'][0]:
        seq_token = res['logStreams'][0]['uploadSequenceToken']
        
        res = logs_client.put_log_events(
            logGroupName=lgn,
            logStreamName=lsn,
            logEvents=[
                {
                    'timestamp': int(time.time()) * 1000,
                    'message': message
                },
            ],
            sequenceToken=seq_token
        )
    # ない場合指定しない
    else:
        res = logs_client.put_log_events(
            logGroupName=lgn,
            logStreamName=lsn,
            logEvents=[
                {
                    'timestamp': int(time.time()) * 1000,
                    'message': message
                },
            ]
        )
```
## コード解説
コードはこちらの記事を参考にしました。

https://qiita.com/kter/items/9db2e9d3544681ef2c1c

Lambda標準のログと同じような感覚で使いたかったので、ロググループ作成とログストリーム作成を追加しました。これにより、あらかじめそれらを作成する必要がなくなります。
Lambda内の変数lgnでロググループ名の指定と、変数lsnでログストリーム名の指定をします。ここでは、ロググループ名は標準のログと同じ、ログストリーム名は日付+[PutLog]にしています。ログストリーム名を調整すれば、任意の単位でまとめることができると思います。

そして、少し理解が難しいのがシーケンストークンの指定です。参考記事でも触れられていますが、2回目以降同じログストリームに書き込むためには、シーケンストークンの指定が必要です。

#IAMポリシー
```json
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "logs:CreateLogGroup",
                "logs:DescribeLogGroups",
                "logs:DescribeLogStreams"
            ],
            "Resource": "arn:aws:logs:リージョン名:アカウントID:*"
        },
        {
            "Effect": "Allow",
            "Action": [
                "logs:CreateLogStream",
                "logs:PutLogEvents"
            ],
            "Resource": [
                "arn:aws:logs:リージョン名:アカウントID:log-group:/aws/lambda/PutLog:log-stream:*[PutLog]"
            ]
        }
    ]
}
```
##ポリシー解説
ポリシーの内容も前述の記事を参考にしています。リージョン名とアカウントIDは置き換えてください。

CreateLogStreamおよびPutLogEventsを独自に指定することで、標準のログが出力されるのを回避しています。
ここでは、関数内で指定している日付+[PutLog]に対応させるために*[PutLog]で、ワイルドカードの指定をしています。

#実行結果
通常であればこのような文字列が付与されたログストリームが作成され、開始終了のログやprint等で指定した文字列が出力されます。前述のポリシーを定義することで、このような標準のログ出力を抑止します。
![SnapCrab_NoName_2021-9-10_6-22-15_No-00.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/996764/29d67aa5-063c-7690-21d3-7f765f590d45.png)

こちらがテスト結果です。print等の代わりに、作成したput_log関数で任意の文字列を指定します。
![SnapCrab_NoName_2021-9-10_6-22-24_No-00.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/996764/56ad6cb3-4991-ac89-a482-7c8a2fc6859d.png)