How to Send Slack Notification from AWS CloudWatchLogs Filter Pattern

If we have an application that stores logs to Amazon CloudWatchLogs, its efficient if we have a monitoring like Slack Alerts. Example, if we encountered an “ERROR” string, we will receive a Slack Notification.

It will send a Slack Notification message to a particular Slack Channel from AWS CloudWatchLogs Log Group based on Filter Pattern. And on Slack Notification, it will output the actual “log line” message.

Diagram



thumbnail

Lambda function will listen for an event from a particular Log Groups in CloudWatchLogs based on a filter pattern message (ex: “error” or “ERROR” string) then it will send a Slack Message to a particular slack channel (ex: “#aws-notification”).
Please take note, the filter pattern is case-sensitive.

Prerequisites


  1. AWS Account.
  2. Slack Webhook URL.
  3. CloudWatchLogs Log Group.

For this walkthrough, we should have already a running application that stores logs using AWS CloudWatchLogs.

Setup


1. Login to your AWS Account.

2. Open Lambda Console.

thumbnail

3. Click the “Create function” button.

thumbnail

4. Configure Lambda function.

  • Select “Author from scratch” for function option.
  • Specify your function name.
  • Select “Node.js 12.x” as Runtime.
  • Click on “Configure” button.

    thumbnail

5. Edit Function code.

Put the following code inside your “index.js” Function code and click on “Deploy” button.

const SLACK_WEBHOOK_URL = process.env.SLACK_WEBHOOK_URL;
const SLACK_USER        = process.env.SLACK_USER;

const https = require('https');
const zlib  = require('zlib');

exports.handler = async (event, context) => {
    try {
      const payload       = Buffer.from(event.awslogs.data, 'base64');
      const parsedPayload = JSON.parse(zlib.gunzipSync(payload).toString('utf8'));
      const logEvents 	  = parsedPayload.logEvents;

      let cwlErrorMessage = '';
      for (let logEvent of logEvents) {
          cwlErrorMessage += logEvent.message + "\n";
      }
  
      // check empty error message
      if ('' === cwlErrorMessage) {
  	throw new Error('Empty error message');
      }

      let userAccountNotification = {
        'username': SLACK_USER, // This will appear as user name who posts the message
        'blocks': [
          {
            "type": "section",
            "text": {
              "type": "mrkdwn",
              "text": cwlErrorMessage.replace(/"/g, '') // The message content, replace double quote
            }
          }
        ],
      };
        
      await sendSlackMessage(userAccountNotification);
      
      return `Successfully processed ${parsedPayload.logEvents.length} log events.`;
        
    } catch(error) {
        console.error('Stg CloudWatch Error Alarm: error sending slack notification ', error);
    }
};


const sendSlackMessage = (messageBody) => {
    return new Promise((resolve, reject) => {
        // check webhook url
        if (! SLACK_WEBHOOK_URL) {
            reject('No Webhook URL');
        }
        
        // general request options, we defined that it's a POST request and content is JSON
        const requestOptions = {
          method: 'POST',
          header: {
            'Content-Type': 'application/json'
          }
        };
    
        // actual request
        const req = https.request(SLACK_WEBHOOK_URL, requestOptions, (res) => {
          let response = '';
    
          res.on('data', (d) => {
            response += d;
          });
    
          // response finished, resolve the promise with data
          res.on('end', () => {
            resolve(response);
          })
        });
    
        // there was an error, reject the promise
        req.on('error', (e) => {
          reject(e);
        });
    
        // send our message body (was parsed to JSON beforehand)
        req.write(JSON.stringify(messageBody));
        req.end();
  });
};

6. Edit Environment variables.

  • SLACK_USER - this Slack User is the name who posted in slack channel.
  • SLACK_WEBHOOK_URL - please refer to the following link on how to Create an Incoming Webhook.

7. Add trigger.

Click on “Add trigger”.

thumbnail

8. Configure trigger.

  • Select CloudWatch Logs.
  • Select a Log Group you want to monitor.
  • Specify a Filter name.
  • Specify a Filter pattern. Example, if you want to monitor for “ERROR” string message in your CloudWatchLogs Log Group, you can put ERROR on the Filter pattern input box.
    If you want to use multiple string pattern, example: “error” or “ERROR” string, you can use question mark, example:
    ?error ?ERROR
    Please take note, this is case-sensitive.
    Please refer for the following link for Filter Pattern.
  • Click on “Add” button.


thumbnail

9. Testing.

Note: please update trigger Filter Pattern to ERROR. (Please refer on #8 Configure trigger.)

  • Click on Select a test event
  • Click on Configure test events

thumbnail

  • For Event Template, search for Amazon Cloudwatch Logs
  • Specify your Test Event name.
  • Click on “Create” button.
  • Click on “Test” button.
  • You should receive a Slack alert under a particular channel based on your Slack Webhook URL. Please note, for this test to work, the Filter Pattern must be using ERROR string.

thumbnail

I hope this guide helps you in setting up your Slack Notification based from CloudWatchLogs Filter Pattern.