0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

lambda

Last updated at Posted at 2024-11-22
import json
import boto3
import urllib.request
from datetime import datetime, timezone, timedelta  # timedeltaをインポート

# SNSクライアントを初期化(メール通知用)
sns_client = boto3.client('sns')

# SNSトピックのARNを指定してください
SNS_TOPIC_ARN = 'arn:aws:sns:your-region:your-account-id:your-topic-name'

# ワークフロー(TeamsのWebhookなど)のURLを設定してください
WORKFLOW_URL = 'https://your-workflow-url'

def extract_metrics(configuration):
    """
    メトリクス情報を抽出して文字列にフォーマットします
    """
    metrics = configuration.get('metrics', [])
    metric_list = []
    for metric in metrics:
        metric_info = metric.get('metricStat', {}).get('metric', {})
        namespace = metric_info.get('namespace', '')
        metric_name = metric_info.get('name', '')
        dimensions = metric_info.get('dimensions', {})
        dimensions_str = ', '.join([f"{k}={v}" for k, v in dimensions.items()])
        metric_list.append(f"{namespace}/{metric_name} ({dimensions_str})")
    return '; '.join(metric_list)

def format_timestamp(timestamp_str):
    """
    タイムスタンプ文字列を日本標準時(JST)にフォーマットします
    """
    if timestamp_str:
        try:
            # タイムスタンプを解析(タイムゾーン情報を含む)
            timestamp = datetime.strptime(timestamp_str, '%Y-%m-%dT%H:%M:%S.%f%z')
            # 日本標準時(UTC+9)のタイムゾーンを作成
            jst_timezone = timezone(timedelta(hours=9))
            # タイムゾーンを日本標準時に変換
            jst_time = timestamp.astimezone(jst_timezone)
            return jst_time.strftime('%Y-%m-%d %H:%M:%S %Z')
        except ValueError as e:
            print(f"タイムスタンプの解析エラー: {e}")
            return 'N/A'
    else:
        return 'N/A'

def send_email(message, subject):
    """
    SNSを使用してメールを送信します
    """
    response = sns_client.publish(
        TopicArn=SNS_TOPIC_ARN,
        Message=message,
        Subject=subject
    )
    print('メールを送信しました。メッセージID:')
    print(response['MessageId'])

def send_to_workflow(card_content):
    """
    ワークフローにデータを送信します
    """
    headers = {
        'Content-Type': 'application/json'
    }
    request = urllib.request.Request(WORKFLOW_URL, data=json.dumps(card_content).encode('utf-8'), headers=headers)
    try:
        with urllib.request.urlopen(request) as response:
            response_body = response.read()
            print('ワークフローへのデータ送信に成功しました。')
    except Exception as e:
        print(f"ワークフローへのデータ送信エラー: {e}")

def lambda_handler(event, context):
    """
    AWS Lambdaのエントリポイント
    """
    # デバッグ用にイベントを出力
    print("Received event: " + json.dumps(event))

    # CloudWatch Alarmからのイベントを解析
    alarm_data = event.get('alarmData', {})
    alarm_name = alarm_data.get('alarmName', '')
    state = alarm_data.get('state', {})
    reason = state.get('reason', '')
    timestamp = state.get('timestamp', '')
    region = event.get('region', '')
    configuration = alarm_data.get('configuration', {})
    metrics = extract_metrics(configuration)

    # タイムスタンプをフォーマット
    occurrence_time = format_timestamp(timestamp)

    # 小文字に変換して比較を容易にする
    reason_lower = reason.lower()
    alarm_name_lower = alarm_name.lower()

    # メッセージの初期化
    subject = ''
    message = ''
    workflow_data = {}

    # メンションするユーザーの情報を設定
    mention_name = 'ユーザー名'  # メンションしたいユーザーの表示名
    mention_id = 'user-id'      # メンションしたいユーザーのID(AAD Object IDなど)

    # 第一段階のフィルタリング:reasonに特定のキーワードが含まれるかチェック
    if ('no datapoints' in reason_lower) or ('insufficient data' in reason_lower) or ('unknown' in reason_lower):
        # 固定形式のメールAを送信 - データ不明
        subject = '【データ不明】アラームが発生しました'
        message = f'''発生時間:{occurrence_time}
発生アラーム名:{alarm_name}
発生メトリクス:{metrics}

理由:
{reason}

詳細はdevops環境のAWS CloudWatchコンソールでご確認ください。'''

        # Adaptive Cardを作成(メンションを含む)
        workflow_data = create_adaptive_card_with_mention(subject, occurrence_time, alarm_name, metrics, reason, mention_name, mention_id)

    else:
        # 第二段階のフィルタリング:alarmNameに特定のキーワードが含まれるかチェック
        if 'warning' in alarm_name_lower:
            # 固定形式のメールBを送信 - 警告
            subject = '【警告】アラームが発生しました'
        elif 'danger' in alarm_name_lower:
            # 固定形式のメールCを送信 - 危険
            subject = '【危険】重大なアラームが発生しました'
        else:
            # 固定形式のメールDを送信 - アラーム状態
            subject = '【アラーム状態】アラームが発生しました'

        message = f'''発生時間:{occurrence_time}
発生アラーム名:{alarm_name}
発生メトリクス:{metrics}

理由:
{reason}

詳細はdevops環境のAWS CloudWatchコンソールでご確認ください。'''

        # Adaptive Cardを作成(メンションを含む)
        workflow_data = create_adaptive_card_with_mention(subject, occurrence_time, alarm_name, metrics, reason, mention_name, mention_id)

    # SNSメールを送信
    send_email(message, subject)

    # ワークフローにデータを送信
    send_to_workflow(workflow_data)

def create_adaptive_card_with_mention(title, occurrence_time, alarm_name, metrics, reason, mention_name, mention_id):
    """
    Adaptive Cardを作成し、メンションを含めます
    """
    mention_text = f"<at>{mention_name}</at>"

    card = {
        "type": "message",
        "attachments": [
            {
                "contentType": "application/vnd.microsoft.card.adaptive",
                "contentUrl": None,
                "content": {
                    "$schema": "http://adaptivecards.io/schemas/adaptive-card.json",
                    "type": "AdaptiveCard",
                    "version": "1.4",
                    "msteams": {
                        "entities": [
                            {
                                "type": "mention",
                                "text": mention_text,
                                "mentioned": {
                                    "id": mention_id,
                                    "name": mention_name
                                }
                            }
                        ]
                    },
                    "body": [
                        {
                            "type": "TextBlock",
                            "text": f"{mention_text} {title}",
                            "size": "Large",
                            "weight": "Bolder",
                            "color": "Attention",
                            "wrap": True
                        },
                        {
                            "type": "FactSet",
                            "facts": [
                                {
                                    "title": "発生時間:",
                                    "value": occurrence_time
                                },
                                {
                                    "title": "発生アラーム名:",
                                    "value": alarm_name
                                },
                                {
                                    "title": "発生メトリクス:",
                                    "value": metrics
                                }
                            ]
                        },
                        {
                            "type": "TextBlock",
                            "text": "理由:",
                            "weight": "Bolder",
                            "wrap": True
                        },
                        {
                            "type": "TextBlock",
                            "text": reason,
                            "wrap": True
                        },
                        {
                            "type": "TextBlock",
                            "text": "詳細はdevops環境のAWS CloudWatchコンソールでご確認ください。",
                            "wrap": True
                        }
                    ]
                }
            }
        ]
    }
    return card

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

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?