- LocalStack上で動くAmazon CloudWatch LogsのログイベントをAWS SAM CLIで動くLambdaから取得する方法をメモする。
構成
LocalStack 準備
-
docker-compose.yml
version: "3.8" networks: container-link: name: docker.internal services: localstack: container_name: "${LOCALSTACK_DOCKER_NAME-localstack_main}" image: localstack/localstack ports: - "127.0.0.1:53:53" # only required for Pro - "127.0.0.1:53:53/udp" # only required for Pro - "127.0.0.1:443:443" # only required for Pro - "127.0.0.1:4510-4530:4510-4530" # only required for Pro - "127.0.0.1:4566:4566" - "127.0.0.1:4571:4571" environment: - SERVICES=${SERVICES- } - DEBUG=${DEBUG- } - DATA_DIR=${DATA_DIR- } - LAMBDA_EXECUTOR=${LAMBDA_EXECUTOR- } - LOCALSTACK_API_KEY=${LOCALSTACK_API_KEY- } # only required for Pro - HOST_TMP_FOLDER=${TMPDIR:-/tmp/}localstack - DOCKER_HOST=unix:///var/run/docker.sock volumes: - "${TMPDIR:-/tmp}/localstack:/tmp/localstack" - "/var/run/docker.sock:/var/run/docker.sock" networks: - container-link
-
起動
docker-compose up
Cloudwatch logs準備
- AWS CLIを使用し、ロググループを作成する。
1. ロググループを作成する
- ロググループ
test-log-group
を作成する。
$ aws logs create-log-group --log-group-name test-log-group --endpoint-url=http://localhost:4566 --profile localstack
2. ログストリームを作成する
- ロググループ
test-log-group
にログストリームtest-log-stream
を作成する。
$ aws logs create-log-stream --log-group-name test-log-group --log-stream-name test-log-stream --endpoint-url=http://localhost:4566 --profile localstack
3. ログイベントをPUTする
初回PUT時
- ログストリーム
test-log-stream
にログイベントをPUTする
$ aws logs put-log-events --log-group-name test-log-group --log-stream-name test-log-stream --log-events timestamp=1635589048,message='LOG EVENTS 1' --endpoint-url=http://localhost:4566 --profile localstack
2回目以降のPUT時
- トークンを取得してから、ログイベントをPUTする。
$ TOKEN=$(aws logs describe-log-streams --log-group-name test-log-group --query 'logStreams[].uploadSequenceToken' --endpoint-url=http://localhost:4566 --profile localstack --output text)
$ aws logs put-log-events \
--log-group-name test-log-group \
--log-stream-name test-log-stream \
--log-events timestamp=1635589048,message='LOG EVENTS 2' \
--sequence-token ${TOKEN} --endpoint-url=http://localhost:4566 --profile localstack
4. ログイベントを確認する
$ aws logs get-log-events --log-group-name test-log-group --log-stream-name test-log-stream --endpoint-url=http://localhost:4566 --profile localstack
{
"events": [
{
"timestamp": 1635589048,
"message": "LOG EVENTS 1",
"ingestionTime": 1635591467580
},
{
"timestamp": 1635589048,
"message": "LOG EVENTS 2",
"ingestionTime": 1635591480764
}
],
"nextForwardToken": "f/00000000000000000000000000000000000000000000000000000001",
"nextBackwardToken": "b/00000000000000000000000000000000000000000000000000000000"
}
Lambda準備
Lambda
-
ひな形作成
sam init
※ランタイムはPython3.8を選択。
-
template.yml
- Hello World Exampleを利用する。
-
requrements.txt
requests boto3
※CloudWatch logsアクセス用にboto3追加
-
Lambda処理(
app.py
)修正import json from boto3.session import Session from datetime import datetime # Cloudwatch logs 接続設定 session = Session( aws_access_key_id='dummy', aws_secret_access_key='dummy', region_name='ap-northeast-1' ) client = session.client( service_name='logs', endpoint_url='http://localstack:4566' ) def lambda_handler(event, context): # ロググループ名 group_name="test-log-group" # ログストリーム取得 streams = client.describe_log_streams( logGroupName="test-log-group", orderBy='LastEventTime', descending=True ) response = {} response["group"] = group_name response["streams"]=[] for stream in streams['logStreams']: stream_name = stream['logStreamName'] stream_response = {} stream_response["stream_name"] = stream_name # ログ取得 logs = client.get_log_events( logGroupName=group_name, logStreamName=stream_name, startFromHead=True ) body = logs['events'] stream_response["logs"]=[] for line in body: message = '[{}] {}'.format(datetime.fromtimestamp(int(str(line['timestamp'])[:10])), line['message']) stream_response["logs"].append(message) response["streams"].append(stream_response) return { "statusCode": 200, "body": json.dumps(response), }
動作確認
-
ビルド
sam build
-
実行
sam local start-api --docker-network docker.internal
-
リクエスト
GET /hello HTTP/1.1 Host: localhost:3000 Content-Type: application/json
-
レスポンス
{ "group": "test-log-group", "streams": [ { "stream_name": "test-log-stream", "logs": [ "[2021-10-30 10:17:28] LOG EVENTS 1", "[2021-10-30 10:17:28] LOG EVENTS 2" ] } ] }