0
0

AWS CloudWatch Metricsのグラフ画像をDiscordに送る(全体ソースコードあり)

Posted at

概要

AWS CloudWatch Metrics でいろいろリソースの状況が確認できますが、Discord に送ることができたら、簡単にスマホでリソース監視ができるので、やってみたいと思います。

ステップ

1. Discord Webhook

Discord Webhook の URL 作成、作ったあとに

みたいなリンクが取得できるので、その Webhook URL を使います。

マニュアル:https://support.discord.com/hc/en-us/articles/228383668-Intro-to-Webhooks

2. CloudWatch Metrics

CloudWatch Metrics にアクセスするして、ほしいグラフを設定してから、Source のタブで直接設定JSONがもらえます。すごく便利な機能でそのまま貼り付けると使えます。もちろん公式ドキュメントもあるので合わせて読んだらもっと理解できると思います。

マニュアル:https://docs.aws.amazon.com/AmazonCloudWatch/latest/APIReference/API_GetMetricData.html

Screenshot from 2023-12-04 23-07-22.png

3. Lambda を作成

CloudWatch Metricsを取得して、Discord Webhook で送る Lambda を作ります。role がわからない/テストの時に、一旦 CloudWatchReadOnlyAccess で良いかもしれません。

ソースコード紹介

Metrics の設定

今回は Invocations, Errors, Duration 三つの Metrics を取得

  metrics = {
    "Invocations": [
      [ "AWS/Lambda", "Invocations", "FunctionName", "funtion1", { "period": 900, "stat": "Sum", "region": "ap-northeast-1" } ],
      [ "...", "funtion2", { "period": 900, "stat": "Sum", "region": "ap-northeast-1" } ],
      [ "...", "funtion3", { "period": 900, "stat": "Sum", "region": "ap-northeast-1" } ],
      [ "...", "funtion4", { "period": 900, "stat": "Sum", "region": "ap-northeast-1" } ]
    ],
    "Errors": [
      [ "AWS/Lambda", "Errors", "FunctionName", "funtion1", { "period": 300, "stat": "Sum", "region": "ap-northeast-1" } ],
      [ "...", "funtion2", { "period": 300, "stat": "Sum", "region": "ap-northeast-1" } ],
      [ "...", "funtion3", { "period": 300, "stat": "Sum", "region": "ap-northeast-1" } ],
      [ "...", "funtion4", { "period": 300, "stat": "Sum", "region": "ap-northeast-1" } ]
    ],
    "Duration": [
      [ "AWS/Lambda", "Duration", "FunctionName", "funtion1", { "period": 300, "stat": "Average", "region": "ap-northeast-1" } ],
      [ "...", "funtion2", { "period": 300, "stat": "Average", "region": "ap-northeast-1" } ],
      [ "...", "funtion3", { "period": 300, "stat": "Average", "region": "ap-northeast-1" } ],
      [ "...", "funtion4", { "period": 300, "stat": "Average", "region": "ap-northeast-1" } ]]
    ],
  }

Metrics の設定(続き)

画像の大きさなどの共通設定はこちらに設定

  for metric, _ in metrics.items():

    widget_definition = json.dumps(
      {
        "liveData": False,
        "stacked": False,
        "width": 800,
        "height": 400,
        "start": '-PT3H',
        "end": "P0D",
        "timezone": '+0900',
        "view": "timeSeries",
        "metrics": metrics[metric],
      }
    )

画像の取得

get_metric_widget_image を使用して画像をローカルに保存

    response = cloudwatch.get_metric_widget_image(MetricWidget = widget_definition)
    image_path = f'/tmp/{metric}.png'

    with open (image_path, 'wb') as f:
      f.write(response["MetricWidgetImage"])

Discord Webhook

Webhook URL を使って、ローカルに保存した画像を Discord に送る

    webhook_url = os.getenv('discord_webhook_url')

    discord = Discord(url=webhook_url)
    with open(image_path, 'rb') as f:
      discord.post(username="monitoring", content=metric, file={ "attachment": f })

全体ソースコード

import json
import boto3
from discordwebhook import Discord
import time
import os

def lambda_handler(event, context):
  cloudwatch = boto3.client('cloudwatch')

  metrics = {
    "Invocations": [
      [ "AWS/Lambda", "Invocations", "FunctionName", "funtion1", { "period": 900, "stat": "Sum", "region": "ap-northeast-1" } ],
      [ "...", "funtion2", { "period": 900, "stat": "Sum", "region": "ap-northeast-1" } ],
      [ "...", "funtion3", { "period": 900, "stat": "Sum", "region": "ap-northeast-1" } ],
      [ "...", "funtion4", { "period": 900, "stat": "Sum", "region": "ap-northeast-1" } ]
    ],
    "Errors": [
      [ "AWS/Lambda", "Errors", "FunctionName", "funtion1", { "period": 300, "stat": "Sum", "region": "ap-northeast-1" } ],
      [ "...", "funtion2", { "period": 300, "stat": "Sum", "region": "ap-northeast-1" } ],
      [ "...", "funtion3", { "period": 300, "stat": "Sum", "region": "ap-northeast-1" } ],
      [ "...", "funtion4", { "period": 300, "stat": "Sum", "region": "ap-northeast-1" } ]
    ],
    "Duration": [
      [ "AWS/Lambda", "Duration", "FunctionName", "funtion1", { "period": 300, "stat": "Average", "region": "ap-northeast-1" } ],
      [ "...", "funtion2", { "period": 300, "stat": "Average", "region": "ap-northeast-1" } ],
      [ "...", "funtion3", { "period": 300, "stat": "Average", "region": "ap-northeast-1" } ],
      [ "...", "funtion4", { "period": 300, "stat": "Average", "region": "ap-northeast-1" } ]]
    ],
  }

  for metric, _ in metrics.items():

    widget_definition = json.dumps(
      {
        "liveData": False,
        "stacked": False,
        "width": 800,
        "height": 400,
        "start": '-PT3H',
        "end": "P0D",
        "timezone": '+0900',
        "view": "timeSeries",
        "metrics": metrics[metric],
      }
    )

    response = cloudwatch.get_metric_widget_image(MetricWidget = widget_definition)
    image_path = f'/tmp/{metric}.png'

    time.sleep(1)

    with open (image_path, 'wb') as f:
      f.write(response["MetricWidgetImage"])

    webhook_url = os.getenv('discord_webhook_url')

    discord = Discord(url=webhook_url)
    with open(image_path, 'rb') as f:
      discord.post(username="monitoring", content=metric, file={ "attachment": f })
  
  return {
    'statusCode': 200,
    'body': json.dumps('Hello from Lambda!')
  }
0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0