- 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"
]
}
]
}