{"id":62037,"date":"2024-06-06T13:26:12","date_gmt":"2024-06-06T07:56:12","guid":{"rendered":"https:\/\/www.tothenew.com\/blog\/?p=62037"},"modified":"2024-06-06T17:16:06","modified_gmt":"2024-06-06T11:46:06","slug":"send-cloudwatch-alarms-to-slack-via-aws-lambda","status":"publish","type":"post","link":"https:\/\/www.tothenew.com\/blog\/send-cloudwatch-alarms-to-slack-via-aws-lambda\/","title":{"rendered":"Send CloudWatch alarms to Slack via AWS Lambda"},"content":{"rendered":"<h2><span style=\"color: #000000;\">Introduction<\/span><\/h2>\n<p><span style=\"color: #000000;\">One of the key factors in maintaining production uptime is the implementation of effective monitoring and alert systems. Integrating AWS CloudWatch with Slack using AWS Lambda allows you to receive real-time alerts in your Slack channels, keeping your team informed and responsive. This blog will guide you do this integration using a AWS Lambda function for sending AWS CloudWatch alarms to Slack.<\/span><\/p>\n<h2><span style=\"color: #000000;\">Objective<\/span><\/h2>\n<p><span style=\"color: #000000;\">The article covers setting up an incoming webhook in your Slack workspace to receive messages from AWS and how to create an AWS Lambda function to process CloudWatch alarms and send formatted notifications to the Slack channel via the webhook URL.<\/span><\/p>\n<p><span style=\"color: #000000;\"><b>Prerequisites<\/b><\/span><\/p>\n<ul>\n<li><span style=\"color: #000000;\">AWS Account<\/span><\/li>\n<li><span style=\"color: #000000;\">Slack<\/span><\/li>\n<\/ul>\n<h2><span style=\"color: #000000;\"><b>Steps by Step Procedure &#8211;<\/b><\/span><\/h2>\n<h3><span style=\"color: #000000;\"><b>1. <\/b><b>Creation of a SNS Topic<\/b><\/span><\/h3>\n<p><span style=\"color: #000000;\">Cloudwatch uses SNS topics to publish messages. So, In your AWS console, visit\u00a0Simple Notification Service, then enter the name of the topic that you want to create, and click on Next Step\u00a0under the topic name.<\/span><\/p>\n<p><span style=\"color: #000000;\"><img decoding=\"async\" loading=\"lazy\" class=\"aligncenter\" src=\"https:\/\/www.tothenew.com\/blog\/wp-ttn-blog\/uploads\/2024\/05\/Image1.png\" alt=\"\" width=\"824\" height=\"402\" \/><\/span><\/p>\n<p><span style=\"color: #000000;\"><img decoding=\"async\" loading=\"lazy\" class=\"aligncenter\" src=\"https:\/\/www.tothenew.com\/blog\/wp-ttn-blog\/uploads\/2024\/05\/Image2.png\" alt=\"\" width=\"826\" height=\"301\" \/><\/span><\/p>\n<p><span style=\"color: #000000;\"><strong>Note<\/strong>: Select type as Standard and the topic name that you have entered earlier should be visible in the Name section, confirm that and create a topic.<\/span><\/p>\n<p><span style=\"color: #000000;\"><img decoding=\"async\" loading=\"lazy\" class=\"aligncenter\" src=\"https:\/\/www.tothenew.com\/blog\/wp-ttn-blog\/uploads\/2024\/05\/Image3.png\" alt=\"\" width=\"699\" height=\"633\" \/><\/span><\/p>\n<h3><span style=\"color: #000000;\"><b>2. <\/b><b>Creation of Slack channel and Slack App<\/b><\/span><\/h3>\n<p><span style=\"color: #000000;\">Now, Create a slack channel for receiving cloudwatch alerts. Let\u2019s give it a name Test and choose visibility as per your need.<\/span><\/p>\n<p><span style=\"color: #000000;\"><img decoding=\"async\" loading=\"lazy\" class=\"aligncenter\" src=\"https:\/\/www.tothenew.com\/blog\/wp-ttn-blog\/uploads\/2024\/05\/Image4.png\" alt=\"\" width=\"432\" height=\"377\" \/><\/span><br \/>\n<span style=\"color: #000000;\"><img decoding=\"async\" loading=\"lazy\" class=\"aligncenter\" src=\"https:\/\/www.tothenew.com\/blog\/wp-ttn-blog\/uploads\/2024\/05\/Image5.png\" alt=\"\" width=\"442\" height=\"386\" \/><\/span><\/p>\n<p><span style=\"color: #000000;\">For creating a slack app, visit\u00a0<a style=\"color: #000000;\" href=\"https:\/\/api.slack.com\/apps\" rel=\"nofollow\">https:\/\/api.slack.com\/apps<\/a>\u00a0and click on\u00a0<strong>Create an app<\/strong>. Choose\u00a0<strong>From scratch\u00a0<\/strong>option for creating a slack app<\/span><\/p>\n<p><span style=\"color: #000000;\"><img decoding=\"async\" loading=\"lazy\" class=\"aligncenter\" src=\"https:\/\/www.tothenew.com\/blog\/wp-ttn-blog\/uploads\/2024\/05\/Image6.png\" alt=\"\" width=\"740\" height=\"418\" \/><\/span><\/p>\n<p><span style=\"color: #000000;\">Give a name to your app and select the same workspace in you have created the channel for receiving the alerts to develop your app.<\/span><\/p>\n<p><span style=\"color: #000000;\"><img decoding=\"async\" loading=\"lazy\" class=\"aligncenter\" src=\"https:\/\/www.tothenew.com\/blog\/wp-ttn-blog\/uploads\/2024\/05\/Image7.png\" alt=\"\" width=\"727\" height=\"411\" \/><\/span><\/p>\n<p><span style=\"color: #000000;\">We will be using webhooks for receiving alerts from cloudwatch. So, let\u2019s\u00a0<strong>activate incoming webhooks<\/strong>\u00a0and the webhook to your channel in which you want to receive alerts.<\/span><\/p>\n<p><span style=\"color: #000000;\"><img decoding=\"async\" loading=\"lazy\" class=\"aligncenter\" src=\"https:\/\/www.tothenew.com\/blog\/wp-ttn-blog\/uploads\/2024\/05\/Image8.png\" alt=\"\" width=\"699\" height=\"633\/\" \/><\/span><\/p>\n<p><span style=\"color: #000000;\">Go to\u00a0<strong>Basic Information <\/strong>and give basic details like the<strong> App icon<\/strong>\u00a0and\u00a0<strong>description<\/strong>\u00a0to your app. It\u2019s an optional step<\/span><\/p>\n<p><span style=\"color: #000000;\"><img decoding=\"async\" loading=\"lazy\" class=\"aligncenter\" src=\"https:\/\/www.tothenew.com\/blog\/wp-ttn-blog\/uploads\/2024\/05\/Image9.png\" alt=\"\" width=\"460\" height=\"629\" \/><\/span><\/p>\n<h3><span style=\"color: #000000;\"><b>3. <\/b><b>Creation of Lambda Function<\/b><\/span><\/h3>\n<p><span style=\"color: #000000;\">Go to the<strong>\u00a0AWS Management Console<\/strong>\u00a0and navigate to\u00a0<strong>Lambda<\/strong>\u00a0and click\u00a0<strong>Create function<\/strong>, and choose\u00a0<strong>Author from scratch<\/strong>. Provide basic details to your lambda function and select\u00a0<strong>Python3.9<\/strong> runtime as this the python version which our lambda function will be using.<\/span><\/p>\n<p><span style=\"color: #000000;\"><img decoding=\"async\" loading=\"lazy\" class=\"aligncenter\" src=\"https:\/\/www.tothenew.com\/blog\/wp-ttn-blog\/uploads\/2024\/05\/Image10.png\" alt=\"\" width=\"528\" height=\"591\" \/><\/span><\/p>\n<p><span style=\"color: #000000;\">After the creation of the Lambda, we need a trigger to invoke our lambda function whenever any Cloudwatch event takes place.<\/span><\/p>\n<p><span style=\"color: #000000;\"><img decoding=\"async\" loading=\"lazy\" class=\"aligncenter\" src=\"https:\/\/www.tothenew.com\/blog\/wp-ttn-blog\/uploads\/2024\/05\/Image11.png\" alt=\"\" width=\"734\" height=\"416\" \/><\/span><\/p>\n<p><span style=\"color: #000000;\">Select the topic that we have created earlier to send alerts to slack. AWS will add a resource-based policy to the function and add a subscription to the topic.<\/span><\/p>\n<p><span style=\"color: #000000;\"><img decoding=\"async\" loading=\"lazy\" class=\"aligncenter\" src=\"https:\/\/www.tothenew.com\/blog\/wp-ttn-blog\/uploads\/2024\/05\/Image12.png\" alt=\"\" width=\"706\" height=\"386\" \/><\/span><\/p>\n<p><span style=\"color: #000000;\"><span style=\"font-weight: 400;\">Now, Replace the below prewritten function with the below function and give your webhook url to<strong>\u00a0slack_url<\/strong>\u00a0variable, give your region to\u00a0<strong>region\u00a0<\/strong>variable and Deploy the function.<\/span><\/span><\/p>\n<pre style=\"background-color: #f5f5f5; padding: 20px; border-radius: 8px; max-width: 100%;\"><span style=\"color: #000000;\"><code>\r\n<textarea id=\"codeBox\" style=\"width: 1600px; height: 900px;\" cols=\"100\" readonly=\"readonly\" rows=\"30\">import urllib3\r\nimport urllib3\r\nimport json\r\nimport logging\r\n\r\nslack_url = \"Your WebHook URL\"\r\nhttp = urllib3.PoolManager()\r\n\r\nlogging.basicConfig(level=logging.INFO)\r\nlogger = logging.getLogger()\r\n\r\ndef get_alarm_attributes(sns_message):\r\n    alarm = dict()\r\n    \r\n    alarm['name'] = sns_message['AlarmName']\r\n    alarm['description'] = sns_message.get('AlarmDescription', 'No description provided.')\r\n    alarm['reason'] = sns_message['NewStateReason']\r\n    alarm['region'] = sns_message['Region']\r\n    alarm['state'] = sns_message['NewStateValue']\r\n    alarm['previous_state'] = sns_message['OldStateValue']\r\n    alarm['timestamp'] = sns_message['StateChangeTime']\r\n\r\n    # Use the correct AWS region code\r\n    region = \"us-east-1\"\r\n    alarm_name = sns_message['AlarmName']\r\n    alarm['link'] = f\"https:\/\/{region}.console.aws.amazon.com\/cloudwatch\/home?region={region}#alarmsV2:alarm\/{alarm_name}\"\r\n\r\n    return alarm\r\n\r\ndef register_alarm(alarm):\r\n    return {\r\n        \"blocks\": [\r\n            {\r\n                \"type\": \"header\",\r\n                \"text\": {\r\n                    \"type\": \"plain_text\",\r\n                    \"text\": \":warning: \" + alarm['name'] + \" alarm was registered\"\r\n                }\r\n            },\r\n            {\r\n                \"type\": \"divider\"\r\n            },\r\n            {\r\n                \"type\": \"section\",\r\n                \"text\": {\r\n                    \"type\": \"mrkdwn\",\r\n                    \"text\": f\"*Alarm Name:* {alarm['name']}\\n\\n*Description:* {alarm['description']}\"\r\n                }\r\n            },\r\n            {\r\n                \"type\": \"section\",\r\n                \"fields\": [\r\n                    {\"type\": \"mrkdwn\", \"text\": f\"*Region:* {alarm['region']}\"},\r\n                    {\"type\": \"mrkdwn\", \"text\": f\"*Timestamp:* {alarm['timestamp']}\"}\r\n                ]\r\n            },\r\n            {\r\n                \"type\": \"section\",\r\n                \"text\": {\r\n                    \"type\": \"mrkdwn\",\r\n                    \"text\": f\"\"\r\n                }\r\n            }\r\n        ]\r\n    }\r\n\r\ndef activate_alarm(alarm):\r\n    return {\r\n        \"blocks\": [\r\n            {\r\n                \"type\": \"header\",\r\n                \"text\": {\r\n                    \"type\": \"plain_text\",\r\n                    \"text\": \":red_circle: Alarm: \" + alarm['name'],\r\n                }\r\n            },\r\n            {\r\n                \"type\": \"divider\"\r\n            },\r\n            {\r\n                \"type\": \"section\",\r\n                \"text\": {\r\n                    \"type\": \"mrkdwn\",\r\n                    \"text\": f\"*Alarm Name:* {alarm['name']}\\n\\n*Description:* {alarm['description']}\"\r\n                }\r\n            },\r\n            {\r\n                \"type\": \"section\",\r\n                \"fields\": [\r\n                    {\"type\": \"mrkdwn\", \"text\": f\"*Region:* {alarm['region']}\"},\r\n                    {\"type\": \"mrkdwn\", \"text\": f\"*Timestamp:* {alarm['timestamp']}\"}\r\n                ]\r\n            },\r\n            {\r\n                \"type\": \"section\",\r\n                \"text\": {\r\n                    \"type\": \"mrkdwn\",\r\n                    \"text\": f\"\"\r\n                }\r\n            }\r\n        ]\r\n    }\r\n\r\ndef resolve_alarm(alarm):\r\n    return {\r\n        \"blocks\": [\r\n            {\r\n                \"type\": \"header\",\r\n                \"text\": {\r\n                    \"type\": \"plain_text\",\r\n                    \"text\": \":large_green_circle: Alarm: \" + alarm['name'] + \" was resolved\",\r\n                }\r\n            },\r\n            {\r\n                \"type\": \"divider\"\r\n            },\r\n            {\r\n                \"type\": \"section\",\r\n                \"text\": {\r\n                    \"type\": \"mrkdwn\",\r\n                    \"text\": f\"*Alarm Name:* {alarm['name']}\\n\\n*Description:* {alarm['description']}\"\r\n                }\r\n            },\r\n            {\r\n                \"type\": \"section\",\r\n                \"fields\": [\r\n                    {\"type\": \"mrkdwn\", \"text\": f\"*Region:* {alarm['region']}\"},\r\n                    {\"type\": \"mrkdwn\", \"text\": f\"*Timestamp:* {alarm['timestamp']}\"}\r\n                ]\r\n            },\r\n            {\r\n                \"type\": \"section\",\r\n                \"text\": {\r\n                    \"type\": \"mrkdwn\",\r\n                    \"text\": f\"\"\r\n                }\r\n            }\r\n        ]\r\n    }\r\n\r\ndef insufficient_data_alarm(alarm):\r\n    return {\r\n        \"blocks\": [\r\n            {\r\n                \"type\": \"header\",\r\n                \"text\": {\r\n                    \"type\": \"plain_text\",\r\n                    \"text\": \":grey_question: Alarm: \" + alarm['name'] + \" is in INSUFFICIENT_DATA state\",\r\n                }\r\n            },\r\n            {\r\n                \"type\": \"divider\"\r\n            },\r\n            {\r\n                \"type\": \"section\",\r\n                \"text\": {\r\n                    \"type\": \"mrkdwn\",\r\n                    \"text\": f\"*Alarm Name:* {alarm['name']}\\n\\n*Description:* {alarm['description']}\"\r\n                }\r\n            },\r\n            {\r\n                \"type\": \"section\",\r\n                \"fields\": [\r\n                    {\"type\": \"mrkdwn\", \"text\": f\"*Region:* {alarm['region']}\"},\r\n                    {\"type\": \"mrkdwn\", \"text\": f\"*Timestamp:* {alarm['timestamp']}\"}\r\n                ]\r\n            },\r\n            {\r\n                \"type\": \"section\",\r\n                \"text\": {\r\n                    \"type\": \"mrkdwn\",\r\n                    \"text\": f\"\"\r\n                }\r\n            }\r\n        ]\r\n    }\r\n\r\ndef lambda_handler(event, context):\r\n    sns_message = json.loads(event[\"Records\"][0][\"Sns\"][\"Message\"])\r\n    alarm = get_alarm_attributes(sns_message)\r\n\r\n    msg = str()\r\n\r\n    if alarm['previous_state'] == \"INSUFFICIENT_DATA\" and alarm['state'] == 'OK':\r\n        msg = register_alarm(alarm)\r\n    elif alarm['previous_state'] == 'OK' and alarm['state'] == 'ALARM':\r\n        msg = activate_alarm(alarm)\r\n    elif alarm['previous_state'] == 'ALARM' and alarm['state'] == 'OK':\r\n        msg = resolve_alarm(alarm)\r\n    elif alarm['state'] == 'INSUFFICIENT_DATA':\r\n        msg = insufficient_data_alarm(alarm)\r\n    elif alarm['previous_state'] == 'INSUFFICIENT_DATA' and alarm['state'] == 'ALARM':\r\n        msg = activate_alarm(alarm)\r\n\r\n    encoded_msg = json.dumps(msg).encode(\"utf-8\")\r\n    try:\r\n        resp = http.request(\"POST\", slack_url, body=encoded_msg, headers={'Content-Type': 'application\/json'})\r\n        logger.info(\r\n            {\r\n                \"message\": msg,\r\n                \"status_code\": resp.status,\r\n                \"response\": resp.data,\r\n            }\r\n        )\r\n    except Exception as e:\r\n        logger.error(f\"Error sending message to Slack: {e}\")\r\n\r\n        <\/textarea><\/code><\/span><\/pre>\n<p><span style=\"color: #000000;\"><span style=\"font-weight: 400;\"><br \/>\n<\/span>Note: You can find your webhook url in the <strong>Incoming Webhooks<\/strong> tab in your Slack application.<br \/>\n<\/span><\/p>\n<p><span style=\"color: #000000;\"><img decoding=\"async\" loading=\"lazy\" class=\"aligncenter\" src=\"https:\/\/www.tothenew.com\/blog\/wp-ttn-blog\/uploads\/2024\/05\/Image13.png\" alt=\"\" width=\"720\" height=\"447\" \/><\/span><\/p>\n<h3><span style=\"color: #000000;\"><b>4. <\/b><b>Create a Cloudwatch Alarm<\/b><\/span><\/h3>\n<p><span style=\"color: #000000;\">Now, create a CloudWatch alarm and configure it to send notifications to the Lambda function via an SNS topic.<\/span><\/p>\n<p><span style=\"color: #000000;\">Go to the AWS CloudWatch console and navigate to the Alarms section. Click &#8220;Create Alarm&#8221; and choose the appropriate metric for your use case (e.g., CPU utilisation, memory usage, or custom metrics).<\/span><\/p>\n<p><span style=\"color: #000000;\">Set the desired threshold and configure the alarm&#8217;s behaviour (e.g., send a notification when the metric exceeds a certain value).<\/span><\/p>\n<p><span style=\"color: #000000;\"><img decoding=\"async\" loading=\"lazy\" class=\"aligncenter\" src=\"https:\/\/www.tothenew.com\/blog\/wp-ttn-blog\/uploads\/2024\/05\/Image14.png\" alt=\"\" width=\"574\" height=\"813\" \/><\/span><\/p>\n<p style=\"text-align: justify;\"><span style=\"color: #000000;\">Under &#8220;Send a notification to,&#8221; select &#8220;SNS Topic&#8221; and choose the SNS Topic you created in the previous steps.<\/span><\/p>\n<p><span style=\"color: #000000;\"><img decoding=\"async\" loading=\"lazy\" class=\"aligncenter\" src=\"https:\/\/www.tothenew.com\/blog\/wp-ttn-blog\/uploads\/2024\/05\/Image15.png\" alt=\"\" width=\"601\" height=\"702\" \/><\/span><\/p>\n<p><span style=\"color: #000000;\">Review the alarm configuration and click &#8220;Create Alarm.&#8221;<\/span><\/p>\n<p><span style=\"color: #000000;\"><img decoding=\"async\" loading=\"lazy\" class=\"aligncenter\" src=\"https:\/\/www.tothenew.com\/blog\/wp-ttn-blog\/uploads\/2024\/05\/Image16.png\" alt=\"\" width=\"573\" height=\"839\" \/><\/span><\/p>\n<p><span style=\"color: #000000;\">For testing the CPU utilization, the Stress Linux utility can be used. Install it by running sudo apt install stress, and then for testing, execute stress &#8211;cpu 2.<\/span><\/p>\n<p><span style=\"color: #000000;\"><img decoding=\"async\" loading=\"lazy\" class=\"aligncenter\" src=\"https:\/\/www.tothenew.com\/blog\/wp-ttn-blog\/uploads\/2024\/05\/Image17.png\" alt=\"\" width=\"524\" height=\"575\" \/><\/span><\/p>\n<h2><span style=\"color: #000000;\">Conclusion<\/span><\/h2>\n<p><span style=\"color: #000000;\">You have now successfully set up an AWS Lambda function to send CloudWatch alarms to a Slack channel. This integration allows you to stay informed about your AWS resources&#8217; health and performance in real-time, directly over your team slack channel.<\/span><\/p>\n<p><span style=\"color: #000000;\">Feel free to customize the Lambda function further as per your specific needs. For example, you can add more details to the Slack messages, handle different types of alerts differently, or integrate with other monitoring tools.<\/span><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Introduction One of the key factors in maintaining production uptime is the implementation of effective monitoring and alert systems. Integrating AWS CloudWatch with Slack using AWS Lambda allows you to receive real-time alerts in your Slack channels, keeping your team informed and responsive. This blog will guide you do this integration using a AWS Lambda [&hellip;]<\/p>\n","protected":false},"author":1834,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"iawp_total_views":556},"categories":[5877],"tags":[248,1545,3812],"aioseo_notices":[],"_links":{"self":[{"href":"https:\/\/www.tothenew.com\/blog\/wp-json\/wp\/v2\/posts\/62037"}],"collection":[{"href":"https:\/\/www.tothenew.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.tothenew.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.tothenew.com\/blog\/wp-json\/wp\/v2\/users\/1834"}],"replies":[{"embeddable":true,"href":"https:\/\/www.tothenew.com\/blog\/wp-json\/wp\/v2\/comments?post=62037"}],"version-history":[{"count":19,"href":"https:\/\/www.tothenew.com\/blog\/wp-json\/wp\/v2\/posts\/62037\/revisions"}],"predecessor-version":[{"id":62251,"href":"https:\/\/www.tothenew.com\/blog\/wp-json\/wp\/v2\/posts\/62037\/revisions\/62251"}],"wp:attachment":[{"href":"https:\/\/www.tothenew.com\/blog\/wp-json\/wp\/v2\/media?parent=62037"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.tothenew.com\/blog\/wp-json\/wp\/v2\/categories?post=62037"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.tothenew.com\/blog\/wp-json\/wp\/v2\/tags?post=62037"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}