---
title: "09 — CloudWatch: Metrics, Logs, and Events — The Nervous System"
uid: cloudwatch-monitoring
tags: ["observability", "aws", "monitoring", "cloudwatch", "roadmap:aws", "metrics", "logs", "events"]
excerpt: "CloudWatch is three primitives — metrics (numbers over time), logs (text events), events (state changes) — and alarms are the glue that turns them into automated responses."
date: 2026-08-13T03:28:30+0000
source: https://www.aveshina.my.id/en/blog/cloudwatch-monitoring
---

"The graphs screen in the console" was how I saw CloudWatch, which meant every monitoring task started with me staring at a dashboard. The actual shape: **CloudWatch is three primitives — metrics (numbers over time), logs (text events with timestamps), and events (state changes that something can react to) — and alarms are the glue that turns those primitives into automated responses** [1]. Once I separated the three, every monitoring question became "which primitive am I looking at, and what should react to it?"

## Metrics: numbers over time

A **metric** is a time-ordered set of data points — a variable I'm watching, sampled over time [2]. CPU utilization, request count, bytes read, error rate — each is a metric. AWS services emit metrics for free (EC2 CPU, S3 bucket size, Lambda invocations), and I can publish my own custom metrics from application code.

The shape worth knowing: a metric is identified by a **name**, a **namespace** (which service or app it belongs to), and up to 30 **dimensions** (key/value pairs that slice it — e.g. InstanceId=i-abc, Environment=prod). I retrieve statistics (average, sum, max, p99) over a time window. The way of thinking: a metric is a labeled time series, and CloudWatch is the store that keeps it.

## Logs: text events with timestamps

**CloudWatch Logs** is the centralized log sink [4]. EC2 instances, Lambda functions, containers, CloudTrail API calls — anything that emits text with a timestamp can ship it here. The two organizing concepts:

- **Log groups** — the top-level container, usually one per application or service. Retention is set per group (so I can keep prod logs for 90 days and dev logs for 7).
- **Log streams** — a sequence of logs from one source within a group (one Lambda instance, one EC2 instance).

The feature I lean on hardest is **CloudWatch Logs Insights** — a query language over my logs. "Show me all ERROR lines from the payments service in the last hour, grouped by request ID" is a few lines of query, not a grep over downloaded files. Logs without a queryable index are just storage; Insights is what makes them usable.

## Events: state changes that something reacts to

**CloudWatch Events** (now folded into **EventBridge**) captures state changes in my AWS environment [3]. An EC2 instance stopped, a new object landed in an S3 bucket, a scheduled cron fired — each is an event. The shape:

- An **event pattern** (or a **schedule**) matches events I care about.
- A **target** is what runs when the pattern matches — a Lambda function, an SNS notification, a Step Function, an Auto Scaling policy.

This is the automation substrate. "When an instance in my ASG terminates, run a Lambda that deregisters it from the service mesh (the layer that tracks which services are running)" is an event rule plus a target. "Run the nightly ETL (the batch job that crunches the data) at 2am" is a scheduled rule plus a Lambda target. The whole event-driven architectures I build on AWS sit on top of this one primitive.

## Alarms: turning observations into actions

An **alarm** watches a metric over a window and changes state when it crosses a threshold [2]. "If the average CPU on my ASG stays above 80% for 5 minutes, go into ALARM." Once in ALARM, the alarm can:

- Notify an **SNS topic**, which fans out to email, Slack via a webhook, or a paging system.
- Trigger an **Auto Scaling policy** (the link between a CloudWatch metric and capacity changes).
- Trigger a **Lambda** or a **Systems Manager** action.

Alarms are how a metric becomes a response. Without them, CloudWatch is just dashboards; with them, it's a closed loop — observe, decide, act.

```figure
<svg viewBox="0 0 680 280" xmlns="http://www.w3.org/2000/svg" class="my-6 w-full max-w-2xl" role="img" aria-label="Three primitives flow into CloudWatch: Metrics (line graph), Logs (text lines), Events (lightning bolts). An Alarm watches a metric; when it crosses a threshold it goes into ALARM state and fans out to an SNS topic, an Auto Scaling policy, and a Lambda function.">
  <g font-family="ui-sans-serif, system-ui, sans-serif" text-rendering="geometricPrecision">
    <defs><marker id="cwa" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="6" markerHeight="6" orient="auto"><path d="M0,0 L10,5 L0,10 z" fill="#64748b"/></marker></defs>

    <!-- three primitives -->
    <rect x="30" y="30" width="120" height="50" rx="8" fill="#e0e7ff" stroke="#6366f1"/>
    <text x="90" y="52" font-size="11" font-weight="700" fill="#1e1b4b" text-anchor="middle">Metrics</text>
    <text x="90" y="68" font-size="9" fill="#1e1b4b" text-anchor="middle">numbers over time</text>

    <rect x="30" y="100" width="120" height="50" rx="8" fill="#dcfce7" stroke="#16a34a"/>
    <text x="90" y="122" font-size="11" font-weight="700" fill="#052e16" text-anchor="middle">Logs</text>
    <text x="90" y="138" font-size="9" fill="#052e16" text-anchor="middle">timestamped text</text>

    <rect x="30" y="170" width="120" height="50" rx="8" fill="#fce7f3" stroke="#db2777"/>
    <text x="90" y="192" font-size="11" font-weight="700" fill="#500724" text-anchor="middle">Events</text>
    <text x="90" y="208" font-size="9" fill="#500724" text-anchor="middle">state changes</text>

    <!-- CloudWatch hub -->
    <rect x="240" y="80" width="160" height="100" rx="10" fill="#fef9c3" stroke="#ca8a04"/>
    <text x="320" y="120" font-size="13" font-weight="700" fill="#422006" text-anchor="middle">CloudWatch</text>
    <text x="320" y="150" font-size="10" fill="#422006" text-anchor="middle">alarm on a metric</text>

    <!-- arrows in -->
    <path d="M150,55 L240,105" stroke="#64748b" stroke-width="1.3" marker-end="url(#cwa)"/>
    <path d="M150,125 L240,125" stroke="#64748b" stroke-width="1.3" marker-end="url(#cwa)"/>
    <path d="M150,195 L240,150" stroke="#64748b" stroke-width="1.3" marker-end="url(#cwa)"/>

    <!-- alarm -> targets -->
    <rect x="470" y="40" width="170" height="44" rx="8" fill="#e0e7ff" stroke="#6366f1"/>
    <text x="555" y="58" font-size="10" font-weight="700" fill="#1e1b4b" text-anchor="middle">SNS topic</text>
    <text x="555" y="73" font-size="9" fill="#1e1b4b" text-anchor="middle">→ email, Slack, page</text>

    <rect x="470" y="105" width="170" height="44" rx="8" fill="#dcfce7" stroke="#16a34a"/>
    <text x="555" y="123" font-size="10" font-weight="700" fill="#052e16" text-anchor="middle">Auto Scaling policy</text>
    <text x="555" y="138" font-size="9" fill="#052e16" text-anchor="middle">→ add/remove capacity</text>

    <rect x="470" y="170" width="170" height="44" rx="8" fill="#fce7f3" stroke="#db2777"/>
    <text x="555" y="188" font-size="10" font-weight="700" fill="#500724" text-anchor="middle">Lambda / SSM action</text>
    <text x="555" y="203" font-size="9" fill="#500724" text-anchor="middle">→ run remediation</text>

    <path d="M400,110 L470,62" stroke="#64748b" stroke-width="1.3" marker-end="url(#cwa)"/>
    <path d="M400,130 L470,127" stroke="#64748b" stroke-width="1.3" marker-end="url(#cwa)"/>
    <path d="M400,150 L470,192" stroke="#64748b" stroke-width="1.3" marker-end="url(#cwa)"/>
  </g>
</svg>
```

## How I use this

CloudWatch is the part of AWS I treat as non-negotiable for anything beyond a tutorial. The discipline I keep: every service emits at least one custom metric for its core health (requests, errors, latency), and every service ships its logs to a CloudWatch Logs group with a defined retention. I write Logs Insights queries for the three questions I'll inevitably ask in an incident (top errors, slowest requests, recent state changes) *before* the incident, not during it. Alarms are wired to the metrics that matter — and crucially, to the actions that should follow — so that capacity adds itself, and the right person gets paged, without a human in the loop. The three primitives are simple; the value is in closing the loop from observation to automated response.

## References

[1] Amazon Web Services, "What is Amazon CloudWatch?," CloudWatch User Guide, 2024. [Online]. Available: [https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/WhatIsCloudWatch.html](https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/WhatIsCloudWatch.html)

[2] Amazon Web Services, "CloudWatch metrics," CloudWatch User Guide, 2024. [Online]. Available: [https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/publishingMetrics.html](https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/publishingMetrics.html)

[3] Amazon Web Services, "Amazon CloudWatch Events," AWS Whitepapers, 2024. [Online]. Available: [https://docs.aws.amazon.com/whitepapers/latest/introduction-devops-aws/cloudwatch-events.html](https://docs.aws.amazon.com/whitepapers/latest/introduction-devops-aws/cloudwatch-events.html)

[4] Amazon Web Services, "What is Amazon CloudWatch Logs?," CloudWatch Logs User Guide, 2024. [Online]. Available: [https://docs.aws.amazon.com/AmazonCloudWatch/latest/logs/WhatIsCloudWatchLogs.html](https://docs.aws.amazon.com/AmazonCloudWatch/latest/logs/WhatIsCloudWatchLogs.html)

```quiz
Q: Which CloudWatch primitive is "a time-ordered set of data points for a variable you're watching"?
- A metric
- A log stream
correct: 0
explain: A metric is a labeled time series — CPU, request count, latency. AWS services emit many for free, and you can publish your own.

Q: CloudWatch Logs are organized into…
- buckets and objects
- log groups (per app/service) containing log streams (per source)
correct: 1
explain: A log group holds the logs for one app or service and carries the retention setting; each source within it writes a log stream.

Q: An EC2 instance terminating and triggering a Lambda to deregister it from a service mesh is an example of…
- CloudWatch Events / EventBridge matching a state change and routing it to a target
- a CloudWatch alarm on a metric
correct: 0
explain: State changes in AWS resources are events. An event pattern matches the termination; a Lambda is the target. Alarms are for metric thresholds.

Q: What does a CloudWatch alarm in ALARM state do?
- It can notify SNS, trigger an Auto Scaling policy, or invoke a Lambda/SSM action
- It only displays in red on the dashboard
correct: 0
explain: An alarm watches a metric and, when it crosses a threshold, fans out to actions. That's the loop from observation to automated response.

Q: The feature that makes CloudWatch Logs queryable in an incident is…
- CloudWatch Logs Insights
- bucket policies
correct: 0
explain: Logs Insights is a query language over log groups. Writing the queries before an incident is what turns logs from storage into a usable diagnostic tool.
```
