AWS for DevOps — Monitoring Exercises
10.6 — Practice Exercises: Monitoring & Observability
Test your understanding of CloudWatch, CloudTrail, X-Ray, and SNS.
Exercise 1 — Create a CloudWatch Alarm
Create a CloudWatch alarm that triggers when an EC2 instance’s CPU exceeds 80% for 2 consecutive 5-minute periods. The alarm should send a notification to an SNS topic called infra-alerts.
Show Answer
# Create the SNS topic
$ aws sns create-topic --name infra-alerts
# Subscribe your email
$ aws sns subscribe \
--topic-arn arn:aws:sns:ap-south-1:123456789012:infra-alerts \
--protocol email \
--notification-endpoint admin@example.com
# Create the alarm
$ aws cloudwatch put-metric-alarm \
--alarm-name high-cpu-ec2 \
--metric-name CPUUtilization \
--namespace AWS/EC2 \
--dimensions Name=InstanceId,Value=i-0abc123def456 \
--statistic Average \
--period 300 \
--threshold 80 \
--comparison-operator GreaterThanThreshold \
--evaluation-periods 2 \
--alarm-actions arn:aws:sns:ap-south-1:123456789012:infra-alerts \
--ok-actions arn:aws:sns:ap-south-1:123456789012:infra-alerts
Key points:
--period 300= 5-minute intervals--evaluation-periods 2= must breach for 2 consecutive periods--ok-actionsnotifies when the alarm returns to OK state
Exercise 2 — Query CloudWatch Logs
You have a log group /ecs/api and need to find all requests that took longer than 2 seconds in the last hour. Write the Logs Insights query.
Show Answer
$ aws logs start-query \
--log-group-name /ecs/api \
--start-time $(date -u -v-1H +%s) \
--end-time $(date -u +%s) \
--query-string '
fields @timestamp, @message
| filter @message like /response_time/
| parse @message "response_time=*ms" as rt
| filter rt > 2000
| sort @timestamp desc
| limit 50
'
Alternative if using JSON logs:
fields @timestamp, request_path, response_time
| filter response_time > 2000
| sort response_time desc
| limit 50
Key points:
parseextracts fields from unstructured log messagesfilternarrows results to slow requests- Use
stats avg(response_time) by request_pathto find which endpoints are slow
Exercise 3 — Investigate with CloudTrail
Someone deleted a production S3 bucket last night. How would you find out who did it and when?
Show Answer
# Look up DeleteBucket events in the last 24 hours
$ aws cloudtrail lookup-events \
--lookup-attributes AttributeKey=EventName,AttributeValue=DeleteBucket \
--start-time "2026-03-29T00:00:00Z" \
--end-time "2026-03-30T12:00:00Z"
The output will show:
Username— who made the API callEventTime— when it happenedSourceIPAddress— from whereResources— which bucket was deleted
To prevent this in the future:
- Enable MFA Delete on critical buckets
- Use S3 Bucket Policy to deny
s3:DeleteBucket - Set up a CloudWatch alarm on
DeleteBucketevents via CloudTrail + CloudWatch Logs
Exercise 4 — Design a Monitoring Strategy
Your team runs a microservices application with: API Gateway → Lambda → DynamoDB. Design a monitoring strategy covering metrics, logs, traces, and alerts.
Show Answer
Metrics to monitor:
| Service | Metric | Threshold |
|---|---|---|
| API Gateway | 5XXError | > 5 per minute |
| API Gateway | Latency (p99) | > 3 seconds |
| Lambda | Errors | > 0 |
| Lambda | Duration (p99) | > 80% of timeout |
| Lambda | Throttles | > 0 |
| DynamoDB | ConsumedReadCapacityUnits | > 80% of provisioned |
| DynamoDB | SystemErrors | > 0 |
Logging strategy:
- API Gateway: Enable access logging (JSON format)
- Lambda: Structured JSON logs with correlation ID
- Use a shared log group prefix:
/app/my-api/
Tracing:
- Enable X-Ray Active tracing on both API Gateway and Lambda
- Use X-Ray SDK in Lambda to trace DynamoDB calls
- Set up service map dashboard
Alert routing:
| Condition | Severity | Action |
|---|---|---|
| Lambda errors > 0 for 5 min | P2 | Slack #incidents |
| API Gateway 5XX > 10 for 5 min | P1 | PagerDuty |
| DynamoDB throttles > 0 | P3 | Slack #monitoring |
| Lambda near timeout | P3 | Slack #monitoring |
Exercise 5 — Set Up CloudTrail + CloudWatch Integration
Create a CloudTrail trail that sends management events to a CloudWatch Logs group. Then create a metric filter that counts DeleteBucket events and an alarm that fires when any bucket is deleted.
Show Answer
# 1. Create the S3 bucket for trail logs
$ aws s3 mb s3://my-trail-logs-123456
# 2. Create the CloudWatch log group
$ aws logs create-log-group --log-group-name /aws/cloudtrail/audit
# 3. Create the trail with CloudWatch integration
$ aws cloudtrail create-trail \
--name audit-trail \
--s3-bucket-name my-trail-logs-123456 \
--is-multi-region-trail \
--enable-log-file-validation \
--cloud-watch-logs-log-group-arn \
arn:aws:logs:ap-south-1:123456789012:log-group:/aws/cloudtrail/audit:* \
--cloud-watch-logs-role-arn \
arn:aws:iam::123456789012:role/CloudTrailToCloudWatch
# 4. Start logging
$ aws cloudtrail start-logging --name audit-trail
# 5. Create a metric filter for DeleteBucket
$ aws logs put-metric-filter \
--log-group-name /aws/cloudtrail/audit \
--filter-name delete-bucket-events \
--filter-pattern '{ $.eventName = "DeleteBucket" }' \
--metric-transformations \
metricName=DeleteBucketCount,metricNamespace=SecurityAlerts,metricValue=1
# 6. Create an alarm on the metric
$ aws cloudwatch put-metric-alarm \
--alarm-name bucket-deletion-alert \
--metric-name DeleteBucketCount \
--namespace SecurityAlerts \
--statistic Sum \
--period 300 \
--threshold 0 \
--comparison-operator GreaterThanThreshold \
--evaluation-periods 1 \
--alarm-actions arn:aws:sns:ap-south-1:123456789012:critical-alerts
Key points:
- The metric filter scans CloudTrail logs in real-time via CloudWatch Logs
- Any
DeleteBucketevent increments the custom metric - The alarm fires immediately (1 evaluation period) when any bucket is deleted
Next Chapter → Configuration & Secrets Management