Monitor Your System with CloudWatch
Set up CloudWatch alarms and dashboards to monitor a serverless API.
Introduction
30 Second Summary
Imagine your app breaks at 2am and you only find out when a customer emails the next morning. In the real world, engineers set up automated alerts so they know about problems the moment they happen.
In this project, you will build a monitoring layer for your existing Lead Intake API using Amazon CloudWatch and Amazon SNS. When your Lambda function starts throwing errors, you will receive an email alert within minutes.
What You'll Build
A production-style monitoring layer that wires CloudWatch alarms to SNS email notifications, giving you instant visibility when your serverless API fails or slows down.
By the end of this project, you'll have:
- An SNS topic with a confirmed email subscription for delivering system alerts.
- A CloudWatch alarm that detects Lambda errors and triggers email notifications via SNS.
- A CloudWatch dashboard showing real-time Invocations, Errors, and Duration metrics for your function.
- Secret Mission: Add a Duration alarm that catches latency spikes before they impact users.
Are there any prerequisites?
Yes. You need to have completed Project 1 (Build a Serverless Lead Intake API) with your LeadIntakeFunction still deployed. You also need the AWS CLI configured and Postman installed.
Set Up the SNS Notification Channel
Your Lead Intake API is live and processing requests. But if it starts failing at 2 AM, how would you know?
You need a delivery channel that can reach you the moment something goes wrong. Amazon SNS (Simple Notification Service) is a messaging service that delivers notifications to subscribers. In this step, you'll create an SNS topic and wire your email to it so future alarms have a way to reach you.
In this step, get ready to:
- Create an SNS topic named LeadIntakeAlerts.
- Subscribe your email address and confirm the subscription.
- Test the notification channel with a test message.
Create an SNS topic in the AWS Console
An SNS topic is a communication channel that groups multiple subscribers under one address. When a message is published to the topic, every subscriber receives it.
- In the AWS Console, type SNS into the top search bar and select **Simple Notification Service**.
- In the left navigation pane, click Topics.
- Click Create topic.
- Under Details, for Type, select Standard.
- For Name, enter LeadIntakeAlerts.
- Leave all other settings as defaults and scroll to the bottom.
- Click Create topic.
The console opens your new topic's detail page. You should see the topic name, its ARN, and the status displayed in the Details section.
What is an SNS topic?
Think of a topic like a mailing list. You publish one message to the topic, and SNS fans it out to every subscriber. Subscribers can be email addresses, Lambda functions, SQS queues, or HTTP endpoints.
You chose the Standard type because it supports email delivery. FIFO topics are for ordered message processing and do not support email.
Don't see the Topics option?
Make sure you are in the SNS service page, not the SQS service page. Both appear in search results and have similar names.
help me find the SNS Topics page in the AWS Console
Add an email subscription and confirm it
A topic without subscribers is like a megaphone in an empty room. You need to subscribe your email so messages actually reach you.
- On your LeadIntakeAlerts topic detail page, click Create subscription.
- Under Details, for Protocol, select Email.
- For Endpoint, enter your personal email address.
- Click Create subscription.
The console shows your subscription with the status Pending confirmation. SNS sent a confirmation email to the address you entered.
- Open your email inbox and find the message from AWS Notifications.
- Click the Confirm subscription link inside the email.
- Return to the SNS console and refresh the page. The subscription status should now show Confirmed.
Why do I need to confirm?
Confirmation prevents anyone from subscribing your email to topics without your permission. SNS will not deliver messages to an unconfirmed endpoint.
Don't see the confirmation email?
Check your spam or junk folder. The email comes from a sender address containing no-reply@sns.amazonaws.com. If you still don't see it after a minute, delete the subscription and create a new one with a different email address.
help me troubleshoot why I'm not receiving the SNS subscription confirmation email
Publish a test message to verify delivery
Before wiring alarms to this topic, confirm the full delivery path works by sending a manual test message.
- In the SNS console, click Topics in the left navigation pane.
- Click your LeadIntakeAlerts topic to open its detail page.
- Click Publish message.
- For Subject, enter Test notification.
- In the Message body field, enter Hello from SNS! If you see this, your alert channel is working.
- Click Publish message.
The console shows a success banner with a message ID. Now check your inbox.
- Open your email inbox and look for the message with the subject Test notification.
- Verify the email body matches the message you typed in the console.
What should I see?
Your email should arrive within a few seconds. The email body contains the exact message text you entered, along with some metadata like the topic ARN and a link to unsubscribe.
Message not arriving?
Make sure you confirmed the subscription first. SNS will not deliver to unconfirmed subscriptions. Check your spam folder as well.
help me figure out why my SNS test message is not arriving in my email
Your notification channel is live and verified. Next up, you'll explore what CloudWatch already knows about your Lambda function and graph its metrics in real time.
Explore Lambda Metrics in CloudWatch
Your notification channel is live. Now you need something worth alerting on. Before you can build an alarm, you need to understand what CloudWatch already knows about your function.
Every time your LeadIntakeFunction runs, Lambda automatically sends performance data to CloudWatch. In this step, you will explore those metrics and watch them update in near real-time as you send fresh requests.
In this step, get ready to:
- Navigate to CloudWatch Metrics and locate your function's data.
- Graph the Invocations and Errors metrics to see historical activity.
- Send live requests and watch the graph update within minutes.
Navigate to your function's metrics in CloudWatch
CloudWatch organizes metrics by namespace. Lambda metrics live under the AWS/Lambda namespace, grouped by function name.
- In the AWS Console, type CloudWatch in the top search bar and select CloudWatch from the results.
- In the left navigation pane, click Metrics, then All metrics.
- On the Browse tab, find and click the AWS/Lambda namespace.
- Select By Function Name to view metrics grouped by individual function.
- Locate LeadIntakeFunction in the list.
What is the AWS/Lambda namespace?
A namespace is a container for related metrics. Every AWS service publishes metrics to its own namespace automatically. The AWS/Lambda namespace holds all Lambda function metrics (Invocations, Errors, Duration, Throttles) without any extra configuration on your part.
The By Function Name dimension filters these metrics to a single function. This is why you see LeadIntakeFunction listed there.
Don't see AWS/Lambda in the list?
The namespace only appears if at least one Lambda function has been invoked in the past two weeks. If you do not see it, switch back to Postman and send a request to your API endpoint first, then wait a minute and refresh the page.
Also confirm you are in the same AWS region where you deployed LeadIntakeFunction. Check the region selector in the top-right corner of the console.
Need more help? Why can't I see my Lambda function in CloudWatch Metrics?
Graph the Invocations and Errors metrics
With your function located, you can graph its key health signals. These graphs show historical activity from the requests you sent during the previous project.
- In the metrics list for LeadIntakeFunction, tick the checkbox next to Invocations.
- Tick the checkbox next to Errors as well.
- Both metrics now appear on the graph above the table.
What do these metrics mean?
- Invocations counts the number of times your function code was invoked. This includes both successful runs and runs that resulted in an error.
- Errors counts invocations that resulted in a function error. A healthy function keeps this at zero.
Lambda sends metric data to CloudWatch in 1-minute intervals. You do not need to configure anything for this to happen.
- Adjust the time range at the top of the graph to 3h (3 hours) or wider so you can see your historical data clearly.
You should see data points on the Invocations line corresponding to requests you made in the previous project.
Send new requests and watch the graph update
Metrics only tell a story when they reflect live activity. You will now send fresh requests and watch the graph respond within minutes.
- Switch to Postman.
- Open the request you used in the previous project to send a valid lead to your API Gateway endpoint.
- Click Send three times (you can wait a second between each send) to generate 3 successful invocations.
- Confirm each request returns a 200 status code in Postman.
Why 3 requests?
Three requests create enough data points to form a visible spike on the graph. A single request could be overlooked as noise, but three in quick succession produce a clear signal you can point to and say "that was me."
- Switch back to the CloudWatch Metrics graph in your browser.
- Wait 1-2 minutes for the data to arrive (Lambda sends metrics in 1-minute intervals).
- Click the refresh icon at the top-right of the graph (the circular arrow) to reload the data.
- You should see the Invocations line jump by 3 data points at the current time.
Graph not updating?
Make sure your graph time range includes the current time. Drag the right edge of the time window to "now" or select a preset like 1h.
If more than 2 minutes have passed and you still see no change, confirm the 3 Postman requests all returned 200. A failed request might not register as an Invocation if the error occurred at the API Gateway level before reaching Lambda.
Still stuck? Help me figure out why my CloudWatch graph is not showing new invocations after I sent requests in Postman.
You now have a real-time window into your function's health. Next up, you will turn these metrics into an automated alarm that emails you the moment something breaks.
Create a CloudWatch Alarm for Errors
You now know what metrics CloudWatch collects about your function. But staring at graphs all day is not a realistic monitoring strategy.
What you need is an automated alarm that watches a metric for you and sends an email the moment something goes wrong. In this step, you will create a CloudWatch alarm on the Errors metric for your LeadIntakeFunction.
In this step, get ready to:
- Create a CloudWatch alarm on the Errors metric for your Lambda function.
- Configure the alarm to send a notification to your SNS topic when errors occur.
- Verify the alarm appears in the CloudWatch Alarms dashboard.
Create a new alarm and select the Errors metric
The alarm creation wizard in CloudWatch walks you through selecting a metric, defining a threshold, and choosing what happens when that threshold is breached.
- In the CloudWatch console, click Alarms in the left navigation pane.
- Click All alarms.
- Click Create alarm.
- Click Select metric.
- Under the All metrics tab, click Lambda.
- Click By Function Name.
- Find the row where FunctionName is LeadIntakeFunction and Metric Name is Errors.
- Select the checkbox next to that row.
- Click Select metric.
The Specify metric and conditions page appears, showing a graph of the Errors metric.
- Under Statistic, select Sum.
- Under Period, select 1 minute.
- Under Conditions, for Threshold type, choose Static.
- For Whenever Errors is..., select Greater.
- In the than... field, enter 0.
- Click Additional configuration.
- For Datapoints to alarm, set both values to 1 out of 1.
- Click Next.
What do these settings mean?
The Sum statistic counts the total number of errors in each period. A 1-minute period means CloudWatch evaluates your function every 60 seconds.
Setting the threshold to Greater than 0 means any single error triggers the alarm. The 1 out of 1 evaluation period means CloudWatch does not wait for multiple breaching periods before firing.
Configure the alarm action and name
Now you will tell CloudWatch what to do when the alarm fires. You will connect it to the SNS topic you created earlier so it sends you an email notification.
- Under Notification, confirm that In alarm is selected as the alarm state trigger.
- In the SNS topic dropdown, select LeadIntakeAlerts.
- Click Next.
- In the Name field, enter LeadIntake-Errors-Alarm.
- Leave the description field empty for now.
- Click Next.
- Under Preview and create, review the alarm configuration.
- Click Create alarm.
Why connect the alarm to an SNS topic?
CloudWatch alarms invoke actions only when changing state. By pointing the ALARM state action at your LeadIntakeAlerts SNS topic, every state transition to ALARM triggers an email to your confirmed subscription.
This decouples the monitoring system from the notification channel. You could later add SMS, Slack, or PagerDuty subscribers to the same topic without reconfiguring the alarm itself.
Verify the alarm in the CloudWatch Alarms dashboard
- Click Alarms in the left navigation pane, then All alarms.
- Confirm that LeadIntake-Errors-Alarm appears in the list.
- Check that the State column shows INSUFFICIENT_DATA.
Why does it say INSUFFICIENT_DATA?
A new alarm starts in the INSUFFICIENT_DATA state because CloudWatch has not yet collected enough data points at the 1-minute resolution to evaluate the threshold. Once your function runs (or does not run) for at least one evaluation period, the alarm transitions to either OK or ALARM.
Don't see your alarm?
Make sure you are in the same AWS region where you created your LeadIntakeFunction. Alarms are region-specific.
If you see an error about permissions, confirm that your IAM user has the cloudwatch:PutMetricAlarm permission. Admin users have this by default.
Help me troubleshoot my CloudWatch alarm creation
Your alarm is now armed and watching. Next up, you will deliberately trigger it to prove the full pipeline from error detection to email notification actually works.
Trigger the Alarm and Verify End-to-End
You have an alarm configured, an SNS topic connected, and a confirmed email subscription. But until you see an actual notification land in your inbox, you cannot be sure the pipeline works.
In this step, you will deliberately cause errors to trigger your alarm and use the AWS CLI to test notification delivery directly. This proves the full chain from metric breach to email delivery.
In this step, get ready to:
- Send a malformed request to your API to generate a real Lambda error.
- Use the AWS CLI to manually set your alarm to ALARM state and verify the email notification arrives.
- Reset the alarm to OK state and confirm it returns to normal.
Send a malformed request to trigger an error
Your alarm watches for Lambda errors. To trigger it with real data, you need to send a request that causes your LeadIntakeFunction to fail.
- Switch back to Postman with your API Gateway endpoint from the previous project.
- Change the request method to POST and send a request with an empty body (no JSON payload) to your API endpoint.
- You should see a 400 or 500 error response, confirming the request failed.
- Send 2-3 more malformed requests to ensure the Errors metric registers multiple datapoints.
Why multiple requests?
Your alarm evaluates the Errors metric over a 1-minute period. Sending several failing requests within a short window ensures CloudWatch has enough data to evaluate the threshold and trigger the alarm.
- Wait 1-2 minutes for CloudWatch to process the metric data.
- Check your email inbox for an alarm notification from AWS Notifications.
What does the alarm email look like?
The default SNS alarm notification email contains the alarm name, timestamp, region, and state in JSON format. It is not a polished HTML email. Look for a message with your alarm name LeadIntake-Errors-Alarm and a state value of ALARM.
No email after 2 minutes?
The alarm may still be in INSUFFICIENT_DATA state if your requests did not actually cause Lambda errors (a 400 response from API Gateway validation is not the same as a Lambda error). Check the alarm state in the CloudWatch console.
If the alarm has not triggered yet, do not worry. The next substep uses the CLI to manually set the alarm state, which guarantees notification delivery.
Help me troubleshoot why my CloudWatch alarm did not trigger after sending malformed requests to my API
Use the CLI to manually trigger the alarm
Waiting for real metric data can be slow. The AWS CLI provides a set-alarm-state command that temporarily changes an alarm's state and fires the configured actions. This is the AWS-recommended approach for testing notification delivery.
- Set the alarm to ALARM state by running this command in your terminal:
aws cloudwatch set-alarm-state --alarm-name "LeadIntake-Errors-Alarm" --state-value ALARM --state-reason "testing purposes"
What does this command do?
The set-alarm-state command temporarily overrides the alarm's evaluated state. When the updated state differs from the previous value, CloudWatch invokes the configured action (your SNS notification). The state reverts to the true evaluated state on the next alarm period evaluation.
- Check your email inbox within 30 seconds. You should receive an alarm notification email from AWS Notifications containing the alarm name LeadIntake-Errors-Alarm and state ALARM.
Still no email?
Check that your SNS subscription is confirmed. Return to the SNS console, select your LeadIntakeAlerts topic, and verify the subscription status shows Confirmed.
Also check your spam or junk folder. AWS notification emails sometimes get filtered by email providers.
Help me figure out why I'm not receiving SNS email notifications from my CloudWatch alarm
Reset the alarm to OK state
Now that you have confirmed the notification works, reset the alarm to a clean state so it is ready to detect real errors going forward.
- Reset the alarm by running this command:
aws cloudwatch set-alarm-state --alarm-name "LeadIntake-Errors-Alarm" --state-value OK --state-reason "testing complete"
Why reset to OK?
Alarms invoke actions only when changing state. Leaving the alarm in ALARM means it will not fire again until it first returns to OK and then breaches the threshold a second time. Resetting it now ensures it is ready to catch the next real error.
- Return to the CloudWatch console and navigate to Alarms in the left sidebar.
- Confirm that LeadIntake-Errors-Alarm now shows OK state.
Alarm still showing ALARM?
The alarm state may revert within seconds if there is recent error data in the metric. If you sent many failing requests earlier, wait for the 1-minute evaluation period to pass without new errors. The alarm will settle into OK or INSUFFICIENT_DATA once the error datapoints age out.
Help me understand why my alarm keeps returning to ALARM state after I reset it
Your alert pipeline is proven. You now know that when your Lambda function throws errors, CloudWatch detects the threshold breach and SNS delivers the notification to your inbox. Next up, you will build a dashboard to visualize your function's health at a glance.
Build a CloudWatch Dashboard
Your alarm pipeline is proven. You know CloudWatch can detect errors and SNS can deliver the notification to your inbox.
Alarms are reactive. They tell you something went wrong after the fact. A CloudWatch dashboard gives you a proactive, at-a-glance view of your system's health. In this step, you'll build a single-pane-of-glass dashboard that shows invocations, errors, and response times for your LeadIntakeFunction.
In this step, get ready to:
- Create a CloudWatch dashboard named LeadIntakeAPI-Health.
- Add three widgets showing Invocations, Errors, and Duration for your function.
- Verify the dashboard with live data from test requests.
Create your CloudWatch dashboard
A dashboard is a customizable page in CloudWatch where you arrange widgets that display metric data. You'll create one dedicated to your Lead Intake API.
- In the AWS Console, navigate to the CloudWatch service.
- In the left navigation pane, click Dashboards.
- Click Create dashboard.
- In the dialog box, enter LeadIntakeAPI-Health as the dashboard name.
- Click Create dashboard to confirm.
CloudWatch opens your new empty dashboard and prompts you to add your first widget.
Why a dedicated dashboard?
You could check metrics one at a time in the Metrics explorer, but a dashboard lets you see invocations, errors, and latency side by side. Patterns become obvious when you can compare multiple metrics in a single view.
Add widgets for invocations, errors, and duration
You'll add three widgets, each showing a different health signal for your Lambda function.
- In the Add to this dashboard dialog, select Line and click Configure.
- In the Browse tab, select AWS/Lambda as the namespace.
- Select By Function Name.
- Check the box next to Invocations for LeadIntakeFunction.
- Set the time range to 3h using the predefined options at the top of the screen.
- Click Create widget.
Your first widget appears on the dashboard showing invocation history over the past 3 hours.
- Click the + symbol to add another widget.
- Select Line and click Next.
- Choose Metrics.
- In the Browse tab, navigate to AWS/Lambda > By Function Name.
- Check the box next to Errors for LeadIntakeFunction.
- Set the time range to 3h.
- Click Create widget.
You now have two line graphs side by side. The Errors graph should show the spike from your alarm test in the previous step.
- Click the + symbol to add your third widget.
- This time, select Number and click Configure.
- In the Browse tab, navigate to AWS/Lambda > By Function Name.
- Check the box next to Duration for LeadIntakeFunction.
- Click the Graphed metrics tab above the metric list.
- In the Statistic column, change the value to Average.
- Set the time range to 1h.
- Click Create widget.
Why Average for Duration?
The Duration metric measures how long your function takes to process each request, reported in milliseconds. Using the Average statistic gives you a single number representing typical response time, which is easier to read at a glance than a line graph of individual durations.
A Number widget displays this as a big readable value on your dashboard. If it suddenly spikes, you'll notice immediately.
Don't see your function in the metric list?
If LeadIntakeFunction doesn't appear under By Function Name, make sure you're in the same AWS region where you deployed the function. Check the region selector in the top-right corner of the console.
If you still don't see it, the function may not have been invoked recently enough. Send a test request via Postman first, wait 1-2 minutes, then retry.
help me find my Lambda function's metrics in CloudWatch
Send test requests and verify live data
Your dashboard has all three widgets, but you want to see them update with fresh data. You'll send a mix of valid and invalid requests to generate new metric activity.
- Switch to Postman.
- Send 3 valid requests to your API endpoint with properly formatted lead data.
- Send 2 invalid requests with missing required fields to generate errors.
- Return to your LeadIntakeAPI-Health dashboard in CloudWatch.
- Wait 1-2 minutes for the metrics to propagate, then click the refresh icon in the top-right corner of the dashboard.
Your Invocations line graph should show 5 new data points. Your Errors graph should show the 2 invalid requests as a spike. Your Duration number should display the average response time in milliseconds.
- Click Save dashboard in the top-right corner to save your work.
Why send both valid and invalid requests?
A mix of request types lets you confirm that each widget tracks the right signal. Valid requests bump the Invocations count without affecting Errors. Invalid requests bump both Invocations and Errors. This contrast proves your widgets are wired to the correct metrics.
Dashboard not updating?
Lambda sends metric data to CloudWatch in 1-minute intervals. If your graphs look empty after refreshing, wait another minute and refresh again. The data will appear shortly.
Also confirm that Save dashboard was clicked. Unsaved dashboards can lose widget configurations if you navigate away.
help me troubleshoot my CloudWatch dashboard metrics not updating
Secret mission
Add a Duration Alarm for Latency Spikes
Your Errors alarm catches failures. But what about a function that succeeds yet takes too long? Slow responses frustrate users and violate SLAs. Add a Duration alarm that catches latency problems before they impact customers.
Clean Up Your Resources
Clean Up Your Resources
Decide whether to keep your resources running, pause them to come back later, or delete them entirely. This project runs entirely within the AWS Free Tier, so there are no ongoing costs.
Resources you used:
- SNS topic: LeadIntakeAlerts (free, no ongoing cost).
- CloudWatch alarm: LeadIntake-Errors-Alarm (free within the 10-alarm free tier).
- CloudWatch alarm: LeadIntake-Duration-Alarm (free within the 10-alarm free tier).
- CloudWatch dashboard: LeadIntakeAPI-Health (free within the 3-dashboard free tier).
Keep everything running
No action needed. Choose this if you want the alarms to keep monitoring your LeadIntakeFunction.
- All resources stay within the AWS Free Tier (10 alarms, 3 dashboards, free email notifications).
- Your alarms will continue monitoring your function and send you emails if errors occur.
- There is no ongoing cost for keeping these resources active.
Pause - I'll come back to this later
No action needed here either. CloudWatch alarms only notify you on state changes, so you will not receive emails unless your function actually errors.
- If your LeadIntakeFunction is not being invoked, no metrics are generated and no alarms fire.
- Your dashboard and alarms will be waiting for you when you come back.
Delete - I don't want to use this again
Remove all monitoring resources you created in this project. Follow each step below to clean up completely.
- Delete the dashboard:
- Delete the alarms:
- Delete the SNS topic and subscription:
Nice Work!
Nice Work!
You just built a production-style monitoring layer for your serverless API. Your Lead Intake Function now has an automated alert pipeline that notifies you when something goes wrong.
You've learned how to:
- Built a CloudWatch alarm that detects Lambda errors and sends email notifications via an SNS topic with a confirmed subscription.
- Tested the full alert pipeline end-to-end using both real API errors and the set-alarm-state CLI command.
- Built a CloudWatch dashboard with Invocations, Errors, and Duration widgets for at-a-glance system health.
- Secret Mission: Added a Duration alarm for latency monitoring with a 2-out-of-3 evaluation period to avoid false positives from cold starts.
Ready to quiz yourself?