
Amazon CloudWatchAuthorCloudBrum editorial teamLast reviewedReading time~12 minLevelBeginner to advanced
Amazon Web Services · Management tools · Metrics, logs and alarms
CloudWatch is where AWS sends its numbers and its log lines, and where you decide what counts as a problem. Most AWS services publish metrics to it without any setup, your own code can add more, and alarms turn a metric that crosses a line into an email, a page or an automatic action. Logs, dashboards, traces and synthetic checks sit in the same place. The bill is the surprise: custom metrics with many dimension values and logs that are never given an expiry date are the two usual ways a small monitoring setup becomes a large one.
On this page (17 sections)
Mind map: Amazon CloudWatch at a glance
Free to share. The downloaded image includes the CloudBrum link.
Key features (summary)
- Metrics from AWS, free of setupEC2, Lambda, RDS, S3, load balancers and most other services publish metrics on their own. You open the console and the graph is already there.
- Your own metrics next to themSend a number with PutMetricData, or write a structured log line in embedded metric format and let CloudWatch turn it into a metric. Memory and disk use on an EC2 instance need the CloudWatch agent.
- Alarms that can actAn alarm watches a metric against a threshold and changes state. It can notify an SNS topic, start or stop an instance, scale a group or open a Systems Manager item. Composite alarms combine several alarms to cut noise.
- Logs and Logs InsightsLog groups keep what your apps and services write. Logs Insights searches and aggregates them with its own query language, and with OpenSearch PPL or SQL if you prefer those.
- DashboardsBuild a board of graphs, numbers and log queries. It can show several accounts and Regions at once once cross-account observability is set up.
- Application viewApplication Signals discovers services and tracks latency, errors and service level objectives. Synthetics canaries call your endpoints on a schedule, and real user monitoring watches what browsers experience.
- Cross-account observabilityA monitoring account can see metrics, logs and traces from many source accounts, so a team doesn’t have to log in to twenty accounts to find one error.
- Anomaly detectionCloudWatch learns the normal pattern of a metric, including daily and weekly rhythm, and an alarm can fire when the value leaves the expected band instead of crossing a fixed number.
Basic concepts
- Namespace
- A container for metrics, such as AWS/Lambda or your own Orders/Checkout. Metrics in different namespaces never mix.
- Metric and dimension
- A metric is a time-ordered set of data points. Dimensions are name and value pairs, for example FunctionName=checkout, that make each combination a separate metric (and a separate bill line).
- Statistic and period
- A statistic (average, sum, maximum, a percentile) summarises the data points inside a period, such as 60 seconds. Alarms and graphs are always built on a statistic over a period.
- Resolution
- Standard metrics arrive at one-minute resolution. High-resolution custom metrics can go down to one second, at a higher price.
- Alarm state
- OK, ALARM or INSUFFICIENT_DATA. The third one means the alarm didn’t receive enough data to decide, which is not the same as being healthy.
- Evaluation periods and datapoints to alarm
- An alarm can require, for example, 3 breaching datapoints out of the last 5 periods, so one blip doesn’t wake anyone.
- Composite alarm
- An alarm whose state is a rule over other alarms, such as ALARM(error-rate) AND ALARM(latency). It’s used to page once, not three times.
- Log group and log stream
- A log group is a set of logs that share retention, encryption and access settings. A stream is a sequence of events from one source, such as one container or one Lambda instance.
- Retention policy
- How long a log group keeps events. Without one, events are kept indefinitely and keep costing storage.
- Metric filter
- A pattern on a log group that counts matching events and publishes the count as a metric, for example every line containing ERROR.
- Embedded metric format (EMF)
- A JSON log format that carries metric values. CloudWatch extracts them from the log line, so a service can log once and get both a log and a metric.
- CloudWatch agent
- A program on an EC2 instance, on-premises server or container that sends system metrics (memory, disk) and log files to CloudWatch.
- Service level objective (SLO)
- A target for a service, such as 99.9 percent of requests under 500 ms in a month. Application Signals tracks SLOs and the remaining error budget.
How to create & configure it
Set up alarms, logs and a dashboard with the AWS CLI
- Decide what a problem isWrite down two or three symptoms that matter to a user, such as errors, slow responses or nothing arriving. Alarms on causes (CPU) come later, and only where they have helped before.
- Create a place to send alertsMake an SNS topic and subscribe the team address or an on-call tool. Test it with a manual publish before you rely on it.
- Set retention on every log groupNew log groups keep events forever by default. Set a retention period when the group is created, for example 30 days for application logs and longer for audit logs.
- Turn log lines into numbers where neededAdd a metric filter for the error lines you care about, or write embedded metric format from the code. Keep the dimensions few.
- Create the alarmsAlarm on a rate or a percentile over several periods rather than a single data point, and say what to do about missing data. A canary or a load balancer 5XX alarm is a good first one.
- Combine alarms that belong togetherCreate a composite alarm for the symptom you would be paged about, and let the single alarms only record state.
- Build one dashboardUser-visible symptoms go on top, supporting graphs underneath, and the runbook links to it.
- Practise with a faultBreak something on purpose in a test account and watch the alarm, the page and the dashboard. Fix what was confusing.
- Review cost and noise monthlyLook at which metrics and log groups cost the most, delete unused ones, and remove alarms that nobody acts on.
Tip: if an alarm publishes to an SNS topic that is encrypted with the AWS managed key, the message never arrives, because CloudWatch can’t use that key. Use an unencrypted topic or a customer managed KMS key whose policy allows cloudwatch.amazonaws.com. See the code references for the same setup as Terraform.
Common issues after configuration
| Symptom | Likely cause | What to check / fix |
|---|---|---|
| The alarm sits in INSUFFICIENT_DATA | The metric has no data points in the evaluation window, the dimensions don’t match the real metric, or the Region is wrong | Open the metric in the console and compare its name, namespace and dimensions with the alarm. Set treat-missing-data to what you want (for example notBreaching for an error count). |
| There is no memory or disk metric for an EC2 instance | EC2 only publishes CPU, network and disk operations by default | Install the CloudWatch agent and give the instance role the CloudWatchAgentServerPolicy. |
| The alarm changes state but no notification arrives | The SNS topic has no subscription, the subscription isn’t confirmed, or the topic is encrypted with a key CloudWatch can’t use | Check the subscription status, test with a manual publish, and use a topic that CloudWatch is allowed to publish to. |
| AccessDenied on PutMetricData or PutLogEvents | The role or user lacks cloudwatch:PutMetricData or logs:PutLogEvents, or a resource policy denies it | Add the action to the role, limited to the log group or namespace, and check for a deny in a service control policy. |
| A Lambda function writes no logs | Its execution role has no permission to create log streams and put events, or the log group was deleted and the role can’t create it | Attach the basic execution policy or the three logs permissions, and create the log group with a retention period ahead of time. |
| ThrottlingException or Rate exceeded from the API | Too many PutMetricData, GetMetricData or DescribeAlarms calls, often from a dashboard tool or a loop | Batch metric values in one call, cache reads, use GetMetricData for many series and retry with backoff. |
| The metric filter never produces data | The filter pattern doesn’t match the log format, or the log events are JSON and the pattern isn’t a JSON pattern | Test the pattern in the console with real events, use JSON filter syntax for JSON logs, and remember that a filter doesn’t apply to events that arrived before it was created. |
| The monthly bill jumps | A new custom metric with a high-cardinality dimension (user ID, request ID), a verbose log level, or detailed monitoring turned on for many instances | Find the biggest items in Cost Explorer by usage type, remove the dimension that explodes the metric, lower the log level and set retention. |
| A Logs Insights query is slow or expensive | It scans many log groups over a long time range | Narrow the time range and the log groups, filter early in the query, and keep a small stats-only query for dashboards. |
| Alarm graphs don’t match the console graph | A different period or statistic is used (for example Average against Maximum), or the metric math has a mismatched period | Open the alarm’s own graph, copy its statistic and period into the dashboard widget, and check the unit. |
| The cross-account dashboard shows nothing for a source account | The source account isn’t linked to the monitoring account’s sink, or the link doesn’t include that data type | Check the observability sink and link settings in both accounts, and allow the resource types you want. |
Use cases: when and where to use it
Good fit
- Any workload on AWS, because the service metrics are there already
- Teams that want alarms that act, such as scaling or restarting, without another tool
- Applications on Lambda, ECS, EKS and EC2 that log to the platform’s default destination
- Organisations that need audit-friendly retention and encryption of logs in the same cloud as the workload
- Small teams that prefer one console to a monitoring stack they have to run
- Cost-aware teams that will set retention and watch metric cardinality
Consider something else
- API calls and who made them → AWS CloudTrail, which records activity rather than performance
- Deep tracing across services → AWS X-Ray or Application Signals, with OpenTelemetry instrumentation
- Metrics in the Prometheus format at scale → Amazon Managed Service for Prometheus with Amazon Managed Grafana
- A single view across several clouds → a third-party tool, or OpenTelemetry into a backend you choose
- The same job on other clouds → compare Azure Monitor and Cloud Monitoring
Pros: why consider it?
Why teams choose it
- Metrics from AWS services arrive without any setup
- Alarms can notify and also take action
- Logs, metrics, dashboards and traces in one service
- Cross-account and cross-Region views for larger organisations
- Pay-as-you-go, with a free tier for small setups
- Embedded metric format avoids a separate metrics pipeline
Trade-offs to weigh
- Costs creep up through custom metrics, log ingestion and never-expiring log groups
- The query and dashboard experience is less polished than some dedicated tools
- Memory and disk metrics need an agent
- Alarm design takes care, and INSUFFICIENT_DATA surprises newcomers
- Strongly tied to AWS, so multi-cloud setups need another layer
- Regional: metrics and logs stay in the Region where they were sent
Common threats, vulnerabilities & risks
| Risk | Severity | Why it matters | Mitigation |
|---|---|---|---|
| Alarms that nobody watches | High | If the notification path is broken, nobody learns about a real incident. | Test the whole path (alarm, topic, subscriber) regularly and alert on the alarm actions that fail. |
| Sensitive data written to logs | High | Anyone with log access can read the tokens or card numbers that were logged, for as long as the group keeps them. | Stop logging them at the source, turn on data protection policies for masking, and limit who can read the log groups. |
| No retention set on log groups | Medium | Logs pile up, cost more each month and may break a data retention rule. | Set retention in templates, and check it with an AWS Config rule. |
| High-cardinality metric dimensions | Medium | Every new dimension value is another billed metric, so cost climbs with the number of users. | Limit dimensions to a handful of fixed values. Request and user IDs belong in the log line. |
| Alarms on causes, not symptoms | Medium | Paging on CPU wakes people for nothing, and soon the pager is ignored. | Page on user-visible symptoms and keep cause alarms as non-paging signals. |
| Over-broad write access to metrics and logs | Medium | Anyone who can write to a namespace can fake data and hide a problem, or flood the bill. | Limit PutMetricData and PutLogEvents to the roles that need them, by namespace and log group. |
| Missing data treated as healthy | Low–Med | A crashed service sends no data, and an alarm that treats missing data as fine stays green. | Choose the missing-data setting per alarm, and use a heartbeat metric or a canary for liveness. |
| Single account and Region view | Low–Med | During an incident people hunt through accounts and Regions for the right graph. | Set up cross-account observability and a standard dashboard per application. |
| Audit trail kept where an attacker could erase it | Low–Med | A compromised account can delete its own logs, along with the evidence. | Send audit logs to a separate log archive account with restricted deletion. |
Performance optimisation
- Publish custom metrics in batches, and use StatisticValues when a process records many values per minute.
- Use GetMetricData rather than many GetMetricStatistics calls, and ask for several series per request.
- Choose standard resolution unless you need seconds, since high-resolution metrics and alarms cost more.
- Keep dashboards light: many widgets with long time ranges and wide queries load slowly.
- In Logs Insights, filter first and limit the time range and the log groups you query.
- Use metric filters or EMF for numbers you alarm on, rather than running a query on a timer.
- Send logs in structured JSON, so queries and filters can use fields instead of text patterns.
- Put canaries near your users' Regions, and keep the script short so the check itself stays fast.
Reduce monthly cost
FinOps is the habit of managing cloud spend together with engineering. These are the FinOps checks that matter most for Amazon CloudWatch.
- Count your custom metrics: each unique combination of namespace, name and dimensions is billed separately each month.
- Remove high-cardinality dimensions such as request or user IDs, which can turn one metric into thousands.
- Set a retention period on every log group, and move rarely read logs to the Infrequent Access log class where its limits are acceptable.
- Keep log levels sensible in production, because ingestion is billed per gigabyte.
- Turn on detailed monitoring only where a one-minute view pays off, such as an Auto Scaling group.
- Remove unused alarms and dashboards, and use composite alarms to replace several noisy ones.
- Narrow Logs Insights queries, since you pay for the data scanned.
- Watch metric streams and cross-Region data transfer, which add their own charges.
- Export old logs to S3 with a lifecycle rule when you need to keep them but rarely read them.
- Tag log groups and alarms with the owning team, and put a budget alert on CloudWatch.
Figures here are from AWS's pricing pages and other published guides, read in October 2026. Regions differ, sources disagree on alarm rates and prices move, so confirm on the live page (see Pricing).
Security optimisation
- Give roles only the write actions they need, limited to a log group or namespace, and keep read access to logs narrow.
- Encrypt log groups with a KMS key when the data warrants it, and make sure the key policy lets CloudWatch Logs use it.
- Turn on data protection policies to find and mask sensitive values in logs.
- Don’t log secrets or personal data in the first place, and review log output in code review.
- Use VPC interface endpoints for CloudWatch and CloudWatch Logs so private workloads don’t need a path to the internet.
- Send CloudTrail events to CloudWatch Logs and alarm on root account use, console sign-in without MFA and changes to alarms.
- Keep audit logs in a separate account with deletion restricted, and set a long retention there.
- Restrict who can change or delete alarms and dashboards, since turning off an alarm hides a problem.
- For cross-account observability, share only the data types you need and review the sink policy.
- Alert on failed alarm actions and on log delivery errors, so a broken pipeline is noticed.
Governance & compliance
Guardrails
- A shared Terraform module for log groups with retention, encryption and tags, and for alarms with a notification topic and a runbook link
- A service control policy that stops deleting or disabling alarms and log groups outside the platform team’s roles
- A tagging rule for alarms and log groups (owner, application, environment) checked at creation
- A standard set of alarms and one dashboard layout for each kind of workload (web service, queue consumer, batch job)
Continuous checks (AWS Config)
- “cw-loggroup-retention-period-check” so every log group has a retention period
- “cloudwatch-log-group-encrypted” for groups that must use a KMS key
- “cloudwatch-alarm-action-check” so alarms have an action
- “cloudwatch-alarm-settings-check” for period, statistic and threshold settings
- “cloud-trail-cloud-watch-logs-enabled” to confirm CloudTrail reaches the log group
AWS CloudTrail records who changed alarms, dashboards and log settings, AWS Config checks the rules above, IAM Access Analyzer reports resource policies that share log groups, and AWS Artifact holds compliance reports. AWS runs the service and keeps the data safe. The retention period, the people who can read the logs, the alarm thresholds and the on-call response are yours.
Reduce carbon footprint
- Log less at the source, and keep verbose levels for short debugging sessions, so less data is stored and processed.
- Set retention periods and delete unused log groups, metrics and dashboards.
- Use sampling for traces and high-volume logs where full detail isn’t needed.
- Run Logs Insights over short windows and few log groups.
- Log storage and queries are cheapest in carbon terms in a Region on a cleaner grid, if your data rules and latency allow it.
- The tool reports per account and does not list CloudWatch on its own, so quote no CloudWatch figure.
Pricing
Purchase options
Metrics From about $0.30 per custom metric a month
AWS service metrics at standard resolution are included. Custom metrics are billed per unique metric, with volume tiers above 10,000, and high-resolution metrics cost more.
Logs About $0.50 per GB ingested
Standard class ingestion in US East as we read it, plus storage per GB-month, with a cheaper Infrequent Access class that has fewer features.
Alarms Per alarm metric, by type
Standard and high-resolution alarms are priced differently, and composite and anomaly-detection alarms have their own rates. Sources disagree on the exact figures.
Queries and extras Per GB scanned, per use
Logs Insights is billed by data scanned. Dashboards, canaries, real user monitoring, Application Signals and metric streams each have their own charges.
What you actually pay for
- Custom metrics, by unique metric and resolution
- Log ingestion, storage and Logs Insights queries
- Alarm metrics, composite alarms and anomaly detection
- Dashboards beyond the free allowance, canary runs and real user monitoring sessions
- Metric streams, cross-Region and cross-account data, and API requests above the free tier
AWS lists a free tier for small setups, and rates differ by Region. See the official Amazon CloudWatch pricing page and the AWS Pricing Calculator.
Important code references
Monitoring for an orders API: a 30-day log group, a metric filter that counts error lines, an alarm on the error count, a second alarm on latency, a composite alarm that pages once when both fire, an SNS topic for the alerts and a small dashboard. The CLI tab sets up the alarms, log group and dashboard; Terraform describes the same resources. The Python tab publishes a custom metric in batches and lists the alarms that need attention, and the C# tab audits alarms and log groups in an account for missing actions and missing retention. Replace the account, topic address and names with your own.
# Placeholders: replace the Region, account and e-mail address with your own.
REGION=ap-south-1
ACCOUNT=111122223333
APP=orders-api
# 1. Somewhere to send alerts, with one subscriber.
TOPIC=$(aws sns create-topic --region $REGION --name $APP-alerts --query TopicArn --output text)
aws sns subscribe --region $REGION --topic-arn "$TOPIC" --protocol email --notification-endpoint oncall@example.com
# 2. A log group that expires its events, and a metric filter that counts error lines.
aws logs create-log-group --region $REGION --log-group-name /apps/$APP
aws logs put-retention-policy --region $REGION --log-group-name /apps/$APP --retention-in-days 30
aws logs put-metric-filter --region $REGION --log-group-name /apps/$APP --filter-name errors \
--filter-pattern '"ERROR"' \
--metric-transformations metricName=ErrorLines,metricNamespace=Orders/Api,metricValue=1,defaultValue=0
# 3. An alarm on the error count: 3 breaching minutes out of 5, and missing data counts as fine.
aws cloudwatch put-metric-alarm --region $REGION --alarm-name $APP-errors \
--namespace Orders/Api --metric-name ErrorLines --statistic Sum --period 60 \
--evaluation-periods 5 --datapoints-to-alarm 3 --threshold 10 --comparison-operator GreaterThanOrEqualToThreshold \
--treat-missing-data notBreaching --alarm-actions "$TOPIC" --ok-actions "$TOPIC"
# 4. An alarm on a custom p95 latency metric. A missing data point is bad news here, so it breaches.
aws cloudwatch put-metric-alarm --region $REGION --alarm-name $APP-latency \
--namespace Orders/Api --metric-name LatencyMs --extended-statistic p95 --period 60 \
--evaluation-periods 5 --datapoints-to-alarm 3 --threshold 800 --comparison-operator GreaterThanThreshold \
--treat-missing-data breaching
# 5. One composite alarm that pages when both are bad, so the team gets a single message.
aws cloudwatch put-composite-alarm --region $REGION --alarm-name $APP-degraded \
--alarm-rule "ALARM($APP-errors) AND ALARM($APP-latency)" --alarm-actions "$TOPIC"
# 6. A dashboard with the two graphs.
cat > dashboard.json <<EOF
{
"widgets": [
{"type": "metric", "x": 0, "y": 0, "width": 12, "height": 6, "properties": {"region": "$REGION", "title": "Error lines per minute",
"metrics": [["Orders/Api", "ErrorLines"]], "stat": "Sum", "period": 60}},
{"type": "metric", "x": 12, "y": 0, "width": 12, "height": 6, "properties": {"region": "$REGION", "title": "p95 latency (ms)",
"metrics": [["Orders/Api", "LatencyMs"]], "stat": "p95", "period": 60}}
]
}
EOF
aws cloudwatch put-dashboard --region $REGION --dashboard-name $APP --dashboard-body file://dashboard.json
# 7. Ask the logs a question: the ten most frequent error messages in the last hour.
QID=$(aws logs start-query --region $REGION --log-group-name /apps/$APP \
--start-time $(date -d '-1 hour' +%s) --end-time $(date +%s) \
--query-string 'fields @message | filter @message like /ERROR/ | stats count(*) as n by @message | sort n desc | limit 10' \
--query queryId --output text)
aws logs get-query-results --region $REGION --query-id "$QID"
# 8. Which alarms are in trouble right now?
aws cloudwatch describe-alarms --region $REGION --state-value ALARM --query "MetricAlarms[].[AlarmName,StateReason]" --output text
# Placeholders: pass in your own address and names.
variable "region" {
type = string
default = "ap-south-1"
}
variable "app" {
type = string
default = "orders-api"
}
variable "alert_email" {
type = string
}
provider "aws" {
region = var.region
}
resource "aws_sns_topic" "alerts" {
name = "${var.app}-alerts"
}
resource "aws_sns_topic_subscription" "oncall" {
topic_arn = aws_sns_topic.alerts.arn
protocol = "email"
endpoint = var.alert_email
}
resource "aws_cloudwatch_log_group" "app" {
name = "/apps/${var.app}"
retention_in_days = 30
}
resource "aws_cloudwatch_log_metric_filter" "errors" {
name = "errors"
log_group_name = aws_cloudwatch_log_group.app.name
pattern = "\"ERROR\""
metric_transformation {
name = "ErrorLines"
namespace = "Orders/Api"
value = "1"
default_value = "0"
}
}
resource "aws_cloudwatch_metric_alarm" "errors" {
alarm_name = "${var.app}-errors"
namespace = "Orders/Api"
metric_name = "ErrorLines"
statistic = "Sum"
period = 60
evaluation_periods = 5
datapoints_to_alarm = 3
threshold = 10
comparison_operator = "GreaterThanOrEqualToThreshold"
treat_missing_data = "notBreaching"
alarm_actions = [aws_sns_topic.alerts.arn]
ok_actions = [aws_sns_topic.alerts.arn]
depends_on = [aws_cloudwatch_log_metric_filter.errors]
}
resource "aws_cloudwatch_metric_alarm" "latency" {
alarm_name = "${var.app}-latency"
namespace = "Orders/Api"
metric_name = "LatencyMs"
extended_statistic = "p95"
period = 60
evaluation_periods = 5
datapoints_to_alarm = 3
threshold = 800
comparison_operator = "GreaterThanThreshold"
treat_missing_data = "breaching"
}
resource "aws_cloudwatch_composite_alarm" "degraded" {
alarm_name = "${var.app}-degraded"
alarm_rule = "ALARM(${aws_cloudwatch_metric_alarm.errors.alarm_name}) AND ALARM(${aws_cloudwatch_metric_alarm.latency.alarm_name})"
alarm_actions = [aws_sns_topic.alerts.arn]
}
resource "aws_cloudwatch_dashboard" "app" {
dashboard_name = var.app
dashboard_body = jsonencode({
widgets = [
{
type = "metric", x = 0, y = 0, width = 12, height = 6
properties = {
region = var.region, title = "Error lines per minute", stat = "Sum", period = 60
metrics = [["Orders/Api", "ErrorLines"]]
}
},
{
type = "metric", x = 12, y = 0, width = 12, height = 6
properties = {
region = var.region, title = "p95 latency (ms)", stat = "p95", period = 60
metrics = [["Orders/Api", "LatencyMs"]]
}
}
]
})
}
output "alert_topic_arn" {
value = aws_sns_topic.alerts.arn
}
# pip install boto3
# Publishes a custom metric in batches (one API call for many values) and lists the alarms that need a look.
import datetime as dt
import boto3
cw = boto3.client("cloudwatch", region_name="ap-south-1")
NAMESPACE = "Orders/Api"
def publish_latencies(samples_ms, route="checkout"):
"""samples_ms: the latencies seen in the last minute. One statistic set replaces N separate points."""
if not samples_ms:
return
now = dt.datetime.now(dt.timezone.utc)
cw.put_metric_data(Namespace=NAMESPACE, MetricData=[{
"MetricName": "LatencyMs", "Dimensions": [{"Name": "Route", "Value": route}], "Timestamp": now, "Unit": "Milliseconds",
"StatisticValues": {"SampleCount": len(samples_ms), "Sum": float(sum(samples_ms)),
"Minimum": float(min(samples_ms)), "Maximum": float(max(samples_ms))}}])
def alarms_needing_attention():
"""Alarms in ALARM, or in INSUFFICIENT_DATA (often a dead publisher), with the reason CloudWatch gives."""
found = []
for page in cw.get_paginator("describe_alarms").paginate(AlarmTypes=["MetricAlarm", "CompositeAlarm"]):
for a in page["MetricAlarms"] + page["CompositeAlarms"]:
if a["StateValue"] != "OK":
found.append((a["AlarmName"], a["StateValue"], a.get("StateReason", "")))
return found
if __name__ == "__main__":
publish_latencies([120, 95, 310, 88, 140, 220], route="checkout")
for name, state, reason in alarms_needing_attention():
print("%-28s %-18s %s" % (name, state, reason[:80]))
// dotnet add package AWSSDK.CloudWatch
// dotnet add package AWSSDK.CloudWatchLogs
// Audits the Region: alarms without an action, alarms stuck without data, and log groups that never expire.
using Amazon.CloudWatch;
using Amazon.CloudWatch.Model;
using Amazon.CloudWatchLogs;
using Amazon.CloudWatchLogs.Model;
using var cw = new AmazonCloudWatchClient();
using var logs = new AmazonCloudWatchLogsClient();
int problems = 0;
string? token = null;
do
{
var page = await cw.DescribeAlarmsAsync(new DescribeAlarmsRequest { NextToken = token, MaxRecords = 100 });
foreach (MetricAlarm a in page.MetricAlarms)
{
var notes = new List<string>();
if (a.AlarmActions.Count == 0 && a.OKActions.Count == 0) notes.Add("no alarm or OK action");
if (a.StateValue == StateValue.INSUFFICIENT_DATA) notes.Add($"no data since {a.StateUpdatedTimestamp:yyyy-MM-dd}");
if (a.ActionsEnabled == false) notes.Add("actions are disabled");
foreach (string n in notes) { Console.WriteLine($"alarm {a.AlarmName,-40} {n}"); problems++; }
}
token = page.NextToken;
} while (token != null);
string? lgToken = null;
do
{
var page = await logs.DescribeLogGroupsAsync(new DescribeLogGroupsRequest { NextToken = lgToken });
foreach (LogGroup g in page.LogGroups)
{
if (g.RetentionInDays is null or 0)
{
double gb = (g.StoredBytes ?? 0) / 1_073_741_824.0;
Console.WriteLine($"logs {g.LogGroupName,-40} never expires ({gb:0.00} GB stored)");
problems++;
}
}
lgToken = page.NextToken;
} while (lgToken != null);
Console.WriteLine(problems == 0 ? "No problems found." : $"{problems} problem(s) found.");
return problems == 0 ? 0 : 1;
Best videos to explore
Videos picked for this service. Each one is labelled with its source, opens on YouTube if you prefer, and loads only when you press play.
Interview questions
BasicWhat is Amazon CloudWatch?
It’s the AWS service that collects metrics and logs, shows them on dashboards and raises alarms. Most AWS services send metrics to it automatically, and your own applications can send metrics and logs too. Alarms can notify people or trigger actions such as scaling.
BasicHow does CloudWatch differ from CloudTrail?
CloudWatch tells you how a system is performing: metrics, logs, alarms. CloudTrail records who called which AWS API and when. They work together, for example when you send CloudTrail events to CloudWatch Logs and alarm on a risky action, but one is about performance and the other is about activity.
BasicWhy does my EC2 instance not show memory usage?
EC2 publishes CPU, network and disk operation metrics from outside the instance, but it can’t see inside the operating system. Memory and disk space need the CloudWatch agent running on the instance, with a role that allows it to publish.
IntermediateWhat does INSUFFICIENT_DATA mean on an alarm, and how do you handle it?
The alarm didn’t get enough data points in its window to decide. It can be a new alarm, a metric that no longer reports, or a wrong dimension. Choose the missing-data treatment per alarm: for an error count, missing data is usually fine, but for a heartbeat metric missing data should count as breaching.
IntermediateHow do composite alarms reduce noise?
A composite alarm evaluates a rule over other alarms, such as high errors AND high latency, and only that alarm sends the notification. The underlying alarms still change state and keep history, but the on-call person receives one message instead of several.
IntermediateWhat is embedded metric format?
It’s a JSON structure for log lines that includes metric definitions and values. CloudWatch Logs reads the line, creates the metrics and keeps the full log event. It suits Lambda and containers, where calling PutMetricData on every request would add latency and cost.
AdvancedHow would you keep a CloudWatch bill under control as a platform grows?
Treat metrics and logs as products with owners. Limit dimensions to a fixed set and keep identifiers out of them, set retention in every template, choose log levels deliberately, use the Infrequent Access class for logs you rarely read, narrow Logs Insights queries, delete unused alarms and dashboards, tag by team, and review the biggest usage types in Cost Explorer each month.
AdvancedHow do you design alarms for a service so that on-call stays sane?
Alarm on user-visible symptoms such as error rate, latency percentiles and failed checks, over several periods, with a clear runbook link. Keep cause alarms (CPU, queue depth) as non-paging signals or inputs to a composite alarm. Tune thresholds from real data, use anomaly detection where the pattern has a rhythm, and review every page that wasn’t actionable.
AdvancedHow would you set up monitoring for an organisation with many AWS accounts?
Use cross-account observability: designate a monitoring account with a sink, link source accounts through AWS Organizations, and build shared dashboards and alarms there. Send audit logs to a separate log archive account with restricted deletion, standardise log group naming, retention and encryption with templates, and enforce them with AWS Config rules and service control policies.
AdvancedWhen would you use Amazon Managed Service for Prometheus or a third-party tool instead of CloudWatch?
When the team already runs Prometheus and PromQL across Kubernetes, when you need one view across several clouds, or when specialised features such as long-term analysis, advanced tracing or a particular alerting workflow matter more than staying inside one provider. A common split is CloudWatch for AWS service metrics and alarms, plus another tool for application telemetry; CloudWatch also accepts OpenTelemetry data, so the split is a choice, not a limit.
Similar or alternative services on other clouds
| Capability | AWS | Azure | Google Cloud |
|---|---|---|---|
| Service | Amazon CloudWatch | Azure Monitor | Cloud Monitoring with Cloud Logging |
| Metrics from the platform | Automatic for most AWS services | Automatic platform metrics, kept 93 days | Automatic for Google Cloud services, free of charge |
| Custom metrics | PutMetricData, EMF, the agent | Custom metrics, OpenTelemetry, Azure Monitor workspace for Prometheus | Custom and Prometheus metrics, OpenTelemetry |
| Logs | Log groups, Logs Insights (QL, PPL, SQL) | Log Analytics workspaces, queried with KQL | Cloud Logging, with log-based metrics |
| Alerts | Metric, composite and anomaly alarms, SNS and other actions | Metric, log search and activity log alerts, action groups | Alerting policies with notification channels |
| Application view | Application Signals, X-Ray, Synthetics, RUM | Application Insights | Cloud Trace, Error Reporting, uptime checks and SLO monitoring |
| Query language | Logs Insights QL for logs, metric math for metrics | KQL | PromQL (MQL is no longer recommended) |
| How you are billed | Per metric, alarm, log GB and query | Mostly per GB of logs ingested, plus metrics and alerts | Per MiB of metrics ingested, per GiB of logs, per alert condition |
Services that publish to CloudWatch include AWS Lambda, Amazon EC2, Amazon EKS and Amazon RDS. Encrypting log groups uses AWS KMS.
Did you find this article helpful?
Your answer helps us improve this page for the next reader.
Sources and further reading
CloudBrum wrote this page in its own words, using the provider’s public documentation listed below as the reference. Features, limits, names and prices change, so confirm anything that matters on the provider’s own pages before you decide.
- What is Amazon CloudWatch?Amazon Web Services
- Using Amazon CloudWatch alarmsAmazon Web Services
- Combining alarms: composite alarmsAmazon Web Services
- CloudWatch Logs concepts and retentionAmazon Web Services
- Analyzing log data with CloudWatch Logs InsightsAmazon Web Services
- Embedded metric format specificationAmazon Web Services
- CloudWatch service quotasAmazon Web Services
- Amazon CloudWatch pricingAmazon Web Services
- Terraform AWS provider: aws_cloudwatch_metric_alarmHashiCorp
