Send Amazon CloudWatch Alarms to Slack

Send Amazon CloudWatch Alarms to Slack

The following article provides a practical example of Running AWS Lambda Functions Locally Using LocalStack. The purpose of this AWS Lambda function is to forward AWS CloudWatch alarms to Slack by utilizing an SNS topic as an intermediary. Please ensure you have completed all the prerequisites mentioned in the referenced article before continuing. In addition, we will use Nuke to automate various helpful tasks. You can learn more about Nuke here. So, let's begin.

Lambda Function

Run the following commands to set up our project:

dotnet new lambda.EmptyFunction -n SNS2Slack -o .
dotnet add src/SNS2Slack package Slack.Webhooks
dotnet add src/SNS2Slack package Amazon.Lambda.SNSEvents
dotnet new sln -n SNS2Slack
dotnet sln add --in-root src/SNS2Slack

Open the solution, navigate to the SNS2Slack project, and create an Alarm.cs file containing the following content:

namespace SNS2Slack;

public class Alarm
    public string? AlarmName { get; set; }
    public string? AlarmDescription { get; set; }
    public string? AWSAccountId { get; set; }
    public string? NewStateValue { get; set; }
    public string? NewStateReason { get; set; }
    public string? OldStateValue { get; set; }
    public Trigger? Trigger { get; set; }

public class Trigger
    public string? MetricName { get; set; }
    public string? Namespace { get; set; }
    public string? Statistic { get; set; }
    public string? GreaterThanOrEqualToThreshold { get; set; }
    public decimal Period { get; set; }
    public decimal Threshold { get; set; }
    public decimal EvaluationPeriods { get; set; }

Open the Function.cs file and update the content as follows:

using Amazon.Lambda.Core;
using Amazon.Lambda.SNSEvents;
using Slack.Webhooks.Elements;
using Slack.Webhooks;
using System.Text.Json;
using Slack.Webhooks.Blocks;
[assembly: LambdaSerializer(typeof(Amazon.Lambda.Serialization.SystemTextJson.DefaultLambdaJsonSerializer))]
namespace SNS2Slack;
public class Function
    private readonly SlackClient _slackClient;
    public Function()
        var webHook = Environment.GetEnvironmentVariable("SlackWebHook");
        _slackClient = new SlackClient(webHook);

    public async Task FunctionHandler(SNSEvent evnt, ILambdaContext context)
        foreach (var record in evnt.Records)
            await ProcessRecord(record, context);

    private async Task ProcessRecord(SNSEvent.SNSRecord record, ILambdaContext context)
        context.Logger.LogInformation($"Processed record {record.Sns.Message}");
        if (record.Sns.Message == null)
        var alarm = JsonSerializer.Deserialize<Alarm>(record.Sns.Message);
        if (string.IsNullOrEmpty(alarm?.AlarmName))
        var slackMessage = new SlackMessage
            Markdown = true
        slackMessage.Blocks = new List<Block>
            new Section
                Text = new TextObject($"{alarm.AlarmDescription}\n")
                    Type = TextObject.TextType.Markdown
        await _slackClient.PostAsync(slackMessage);

Essentially, we receive the alarm within an SNS record and subsequently send its description to Slack. Create a template.yml file as follows:

AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31
Description: >

    Timeout: 15
    MemorySize: 512
    Runtime: dotnet6
      - x86_64

    Type: String

    Type: AWS::SNS::Topic
      TopicName: "SlackTopic"

    Type: AWS::Serverless::Function
      Handler: SNS2Slack::SNS2Slack.Function::FunctionHandler
      CodeUri: ./src/SNS2Slack/
          SlackWebHook: !Ref SlackWebHook
          Type: SNS
            Topic: !Ref SNSTopic

    Description: SNS ARN
    Value: !Ref SNSTopic

The SAM script creates an SNS topic to which CloudWatch Alarms will be sent and a Lambda function triggered by the mentioned SNS topic.

Local Stack

Add a docker-compose.yml file at the solution level with the following content:

version: "3.8"

    container_name: "my-localstack"
    image: localstack/localstack
      - ""
      - ""
      - DEBUG=1
      - DOCKER_HOST=unix:///var/run/docker.sock
      - ".volume/tmp/localstack:/tmp/localstack"
      - "/var/run/docker.sock:/var/run/docker.sock"


Go to and create a new application (from scratch):

Activate the Incoming WebHooks feature:

Finally, add a new Webhook to Workspace:

Once completed, copy the Webhook URL for future use.


Run the nuke :setup command and follow the instructions (we recommend using all the default values) to set up the project. Navigate to the _build the project and update the content as follows:

using Nuke.Common;
using Nuke.Common.Tooling;

class Build : NukeBuild
    [PathExecutable(name: "docker-compose")]
    public readonly Tool DockerCompose;
    [PathExecutable(name: "samlocal")]
    public readonly Tool SamLocal;
    public static int Main () => Execute<Build>(x => x.SamLocalBuild);
    public string SlackWebHook;
    public bool IsRunning()
        var output = DockerCompose("ps --status running --quiet");
        return output.Count > 0;

    Target StartEnv => _ => _
    .OnlyWhenDynamic(() => !IsRunning())
    .Executes(() =>
        DockerCompose("up -d");

    Target StopEnv => _ => _
        .Executes(() =>

    Target SamLocalBuild => _ => _
        .Executes(() =>

    Target SamLocalDeploy => _ => _
        .Requires(() => SlackWebHook)
        .Executes(() =>
            SamLocal($"deploy --no-confirm-changeset --disable-rollback --resolve-s3 --s3-prefix sns2slack --stack-name sns2slack --region us-east-1  --capabilities CAPABILITY_IAM --parameter-overrides SlackWebHook={SlackWebHook}");

In the class above, we are automating the following tasks:

  • StartEnv: Start the LocalStack environment by running the docker-compose file.

  • SamLocalBuild: Build the Lambda function using samlocal CLI.

  • SamLocalDeploy: Deploy the Lambda function to the LocalStack environment, requesting the Slack Webhook URL.

  • StopEnv: Stop and remove the LocalStack environment.

Run the following command to deploy the Lambda function locally:

nuke SamLocalDeploy --slack-web-hook <MY_WEBHOOK_URL>

We can use aws lambda list-functions --endpoint-url=http://localhost:4566 to verify the Lambda function deployment.

Cloud Watch Alarm

Register a CloudWatch alarm by using the created SNS topic as an action:

aws cloudwatch put-metric-alarm --endpoint-url=http://localhost:4566 --alarm-name my-alarm --alarm-description 'This is my slack message' --comparison-operator GreaterThanThreshold --evaluation-periods 1 --alarm-actions arn:aws:sns:us-east-1:000000000000:SlackTopic

Next, change the state of the alarm with:

aws cloudwatch set-alarm-state --endpoint-url=http://localhost:4566 --alarm-name my-alarm --state-reason "Testing" --state-value ALARM

In conclusion, this article demonstrates how to send Amazon CloudWatch alarms to Slack using AWS Lambda functions. By following the provided steps, we'll be able to set up and deploy a Lambda function locally **(**thanks to LocalStack), integrate it with Slack, and automate useful tasks with Nuke. All the code is available here. Thanks, and happy coding.