💡

ECS内部からCloudWatch LogsのURLを生成する

2024/01/17に公開

経緯

Step Functionsのフローで、FargateなECSを用いて実行しているPythonの結果によって

  1. pass
  2. lambda経由でslackにアラート

という分岐をさせているのですが、2で流すメッセージの中にアラート元のECSコンテナに紐づくCloudWatch LogsのURLを含めたいと思っていました。含まれていると嬉しい為。

例:右側$.result_status == falseの際のlambda payloadにcloudwatch URLも含めたい


現在のCloudWatch LogsのURL構成は以下になっているので......

# NOTE: {project_name}周りは実際の設定によって異なるためご自身の環境で改めてURL構成を確認してください
https://{region}.console.aws.amazon.com/cloudwatch/home?/region={region}#logsV2:log-groups/log-group/$252Faws$252Fecs$252F{project_name}/log-events/ecs$252F{task_name}$252F{TASK_ARN}

regionやtask_nameの様な固定値と合わせて、末尾のTASK_ARNの値が実行中のコンテナ内部から取得できればログに紐づくURLが自動的に生成できるようになります。

...

実行中にTASK_ARNってどこから取るの?(StepFunctionsだとoutputとかに出てるけど)boto3/ecsでdescribe_tasksとかから取るの?しんどくない?

等と思い、色々探してたら結構時間を食っていたのですぐ思い出せるように記します。

...

ECS内部からCloudWatch LogsのURLを生成する

ECSタスクでの各コンテナ内部の環境変数

に設定されているメタデータ取得用のendpointからタスクのメタデータを取得して、ほぐした値でURLをフォーマットしてあげて下さい。

import json
import os

import requests

ECS_CONTAINER_METADATA_URI_V4 = os.environ["ECS_CONTAINER_METADATA_URI_V4"]

res = requests.get(f"{metadata_url}/task")

if res.status_code == 200:
	metadata = json.loads(res.text)
        region = metadata["Containers"][0]["LogOptions"]["awslogs-region"]
        task_arn = metadata["TaskARN"].split("/")[-1]
        cloudwatch_url = f"https://{region}.console.aws.amazon.com/cloudwatch/home?region={region}#logsV2:log-groups/log-group/$252Faws$252Fecs$252F{project_name}$252Fcluster/log-events/ecs$252F{task_name}$252F{task_arn}"
else:
    cloudwatch_url = None

コレで生成したURLを、Pythonタスクのreturn時に

sfn.send_task_success(
	taskToken = TASK_TOKEN,
	output=json.dumps({
		"result_status": result_status,
		 "cloudwatch_url": cloudwatch_url
	})
)

return None

等として次のlambda stepに渡してあげて下さい。

Discussion