# EC2 Detailed Monitoring Not Enabled

> Detailed monitoring moves an EC2 instance from 5-minute to 1-minute CloudWatch metrics for roughly $2.10 per month (7 instance metrics at $0.30 each). ZopNight flags running production instances with it disabled, and deliberately keeps quiet about dev and test boxes, where paying for finer metrics rarely makes sense.

Source: https://zop.dev/integrations/aws/recommendations/ec2-detailed-monitoring-not-enabled
Updated: 2026-08-19

---

## What changes at 1-minute resolution

By default [the metrics EC2 sends to CloudWatch](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/viewing_metrics_with_cloudwatch.html) land at 5-minute intervals. That is fine for
capacity trends and poor for incident forensics: a 90-second CPU spike that caused an
outage may not even be visible after 5-minute averaging. Detailed monitoring raises
the resolution to 1 minute, which also lets autoscaling and alarms react roughly five
times sooner, since they evaluate fresher data.

## A recommendation that costs money to accept

This is one of the few findings where the fix increases the bill: about $2.10 per
instance per month, which is 7 EC2 metrics at [CloudWatch's $0.30 per metric per month](https://aws.amazon.com/cloudwatch/pricing/). That
is exactly why the finding carries no savings figure, and why it is scoped to
production instances only.

## The production filter, precisely

Nagging a throwaway test box to spend more on monitoring is noise, so the rule
suppresses itself when an instance looks non-production: a dev/test-shaped name or a
dev/test environment tag. An explicit production environment tag overrides both
signals and keeps the instance eligible. This gate exists because of real data: in
one production account audit, 71 of 122 raw findings landed on uat, sit and perftest
instances, and the filter removed all of them.

## Read the current state

```bash
aws ec2 describe-instances \
  --filters Name=instance-state-name,Values=running \
  --query 'Reservations[].Instances[].[InstanceId,Monitoring.State,Tags[?Key==`Name`]|[0].Value]' \
  --output table
```

The middle column showing `disabled` is the same state discovery records; the rule
fires only on a confirmed `disabled` and abstains when the monitoring state was not
captured at all.

## What it will not tell you

Nothing is said about stopped instances. And the rule cannot tell you whether your
alarms actually exploit the finer resolution. Enabling detailed monitoring without
tightening alarm evaluation periods buys data, not faster reactions. That second step
is yours to take after the switch is on.
