Sending AWS CloudWatch Logs Error to Microsoft Teams Channel

In this tutorial, we will show you how to send AWS CloudWatch logs error to Microsoft Teams channel. In this example, we will send logs error of an AWS Lambda function to a channel of Microsoft Teams.

Follow these steps to implement this solution:

STEP 1: Creating an IAM Role for Lambda

To create an IAM role, do the following:

  1. Go to IAM console at https://console.aws.amazon.com/iam.
  2. Choose Policies from the left navigation menu and click on Create Policy.
  3. Click the JSON tab and replace the default IAM Policy with the following IAM Policy:
  4. {
        "Version": "2012-10-17",
        "Statement": [
            {
                "Effect": "Allow",
                "Action": [
                    "logs:CreateLogGroup",
                    "logs:CreateLogStream",
                    "logs:PutLogEvents"
                ],
                "Resource": "arn:aws:logs:*:*:*"
            }
        ]
    }
    
  5. Click the Next button.
  6. Enter a name of your choice for this policy (For example: MyCloudWatchPolicy) and click the Create policy button. Note the name of the policy for use in later steps.
  7. Choose Roles from the left navigation menu and click on Create role.
  8. When you are on the select role type page, choose AWS service as trusted entity type and Lambda under Use case.
  9. Click on Next.
  10. Filter the policy that you just created by it's name and select the checkbox.
  11. Click on Next.
  12. Enter the role name of your choice in the Role name field (For example: MyCloudWatchRole).
  13. Click the Create role. Note the name of the Role for use in later steps.

STEP 2: Creating and Setting up a Lambda function

To create and set up a Lambda function, do the following:

  1. Go to Lambda console at https://console.aws.amazon.com/lambda/home. Click the Create function button.
  2. Choose Author from scratch.
  3. Enter the function name of your choice in the Function name field.
  4. Choose Python3.10 or your preferred version as your Runtime.
  5. For Execution Role, select Use an existing role, then select the IAM role created in the previous step.
  6. Choose Create Function.
  7. Remove code from the default function and copy the following code into the Function code Window:
  8. import base64
    import gzip
    import json
    import logging
    import os
    from urllib.request import Request, urlopen
    from urllib.error import URLError, HTTPError
    
    logging.basicConfig(level=logging.INFO)
    logger = logging.getLogger(__name__)
    
    HOOK_URL = os.environ['HOOK_URL']
    
    
    def log_payload(event):
        logger.setLevel(logging.DEBUG)
        logger.debug(event['awslogs']['data'])
        compressed_payload = base64.b64decode(event['awslogs']['data'])
        uncompressed_payload = gzip.decompress(compressed_payload)
        logpayload = json.loads(uncompressed_payload)
        return logpayload
    
    
    def error_details(payload):
        error_msg = ""
        log_events = payload['logEvents']
        logger.debug(payload)
        loggroup = payload['logGroup']
        logstream = payload['logStream']
        lambda_func_name = loggroup.split('/')
        logger.debug(f'LogGroup: {loggroup}')
        logger.debug(f'Logstream: {logstream}')
        logger.debug(f'Function name: {lambda_func_name[3]}')
        logger.debug(log_events)
        for log_event in log_events:
            error_msg += log_event['message']
        logger.debug('Message: %s' % error_msg.split("\n"))
        return loggroup, logstream, error_msg, lambda_func_name
    
    
    def send_message_to_teams(loggroup, logstream, error_msg, lambda_func_name):
        try:
            msg = ""
            msg += "\nLambda error  summary" + "\n\n"
            msg += "##########################################################\n"
            msg += "# LogGroup Name:- " + str(loggroup) + "\n"
            msg += "# LogStream:- " + str(logstream) + "\n"
            msg += "# Log Message:- " + "\n"
            msg += "# \t\t" + str(error_msg.split("\n")) + "\n"
            msg += "##########################################################\n"
    
            # Sending the notification...
            message = {
                "@context": "https://schema.org/extensions",
                "@type": "MessageCard",
                "themeColor": "d63333",
                "title": f'Execution error for Lambda - {lambda_func_name[3]}',
                "text": msg
            }
            req = Request(HOOK_URL, json.dumps(message).encode('utf-8'))
            response = urlopen(req)
            response.read()
            logger.info("Message posted")
            return {"status": "200 OK"}
        except HTTPError as e:
            logger.error("Request failed: %d %s", e.code, e.reason)
        except URLError as e:
            logger.error("Server connection failed : %s", e.reason)
    
    
    def lambda_handler(event, context):
        pload = log_payload(event)
        lgroup, lstream, errmessage, lambdaname = error_details(pload)
        send_message_to_teams(lgroup, lstream, errmessage, lambdaname)
  9. Click the Deploy button to save the changes.
  10. Go to the Environment variables which is under the Configuration section of the Lambda function and add the following key pair environment variables:
    • Key = HOOK_URL
    • Value = copy here the connector url of the channel from the Microsoft Teams. To get the connector url, go to Teams from the left menu on the Microsoft Teams. Click on menu next to the channel you want to send the message to. This will show you an option to add connectors. Then, choose to configure the Incoming Webhook connector which gives us an endpoint for sending messages to that channel.
  11. Choose Save.

STEP 3: Adding a CloudWatch Trigger

To add a CloudWatch trigger, do the following:

  1. Click on Add trigger button under the Lambda Function overview section and then choose CloudWatch Logs from the drop-down menu.
  2. For Log Group, select the CloudWatch log group name of the Lambda function from which you want the error notifications.
  3. Enter the name of your choice for this trigger in the Filter name field.
  4. In the Filter pattern field, enter the filter value for the log you want to be notified on. For example: ?ERROR ?WARNING ?CRITICAL ?5xx will filter logs with ERROR, WARNING, CRITICAL, 5xx terms found in the log.
  5. Enable trigger and Click the Add button.

The set up is complete. You can test it by running your Lambda with some errors in the code.