cloudwatch-janitor 🧹
Find the CloudWatch waste hiding in your AWS bill — in one read-only command.
CloudWatch costs creep up silently: log groups that keep data forever, alarms watching resources that were deleted months ago, dashboards nobody has opened since 2024. cloudwatch-janitor scans your account, lists every finding, and estimates what it's costing you per month.
It never modifies anything. Four read-only API calls, that's it.
CHECK RESOURCE ISSUE EST. $/MO
---------------- ------------------------------ ------------------------------------------------- ---------
log-retention /aws/lambda/etl-processor No retention policy (312.40 GB stored, growing…) 9.37
log-retention /aws/eks/prod-cluster/apps No retention policy (88.10 GB stored, growing…) 2.64
idle-log-groups /aws/lambda/old-webhook-fn No incoming events in 90 days (12.33 GB stored) 0.37
stale-alarms db-conn-alarm-legacy INSUFFICIENT_DATA for 214 days (metric likely…) 0.10
stale-dashboards team-x-dashboard Not modified in 431 days 3.00
5 finding(s), estimated savings: $15.48/month (rough estimate, standard pricing)
Install
pip install cloudwatch-janitor
Or straight from GitHub:
pip install git+https://github.com/varunmj/cloudwatch-janitor.git
Or clone and run directly:
git clone https://github.com/varunmj/cloudwatch-janitor.git
cd cloudwatch-janitor && pip install -e .
Usage
# Scan the default profile/region
cloudwatch-janitor
# Specific profile and region
cloudwatch-janitor --profile prod --region us-west-2
# Only some checks
cloudwatch-janitor --checks log-retention,stale-alarms
# JSON output (pipe it, save it, alert on it)
cloudwatch-janitor --json > findings.json
What it checks
| Check | What it finds | Why it matters |
|---|---|---|
log-retention |
Log groups with no retention policy | Logs are stored forever at ~$0.03/GB-month, growing every day |
idle-log-groups |
Log groups with zero incoming events in 90 days but data still stored | Usually left behind by deleted Lambdas/services — safe to remove |
stale-alarms |
Alarms in INSUFFICIENT_DATA for 30+ days |
The metric is probably gone; you're paying for monitoring that monitors nothing |
stale-dashboards |
Dashboards not modified in 180+ days | Dashboards beyond the first 3 cost $3/month each |
Cost estimates are deliberately rough (us-east-1 standard pricing) — they're there to help you prioritize, not to reconcile your bill.
Permissions
Least privilege, read-only. Attach docs/iam-policy.json:
{
"Action": [
"logs:DescribeLogGroups",
"cloudwatch:DescribeAlarms",
"cloudwatch:GetMetricData",
"cloudwatch:ListDashboards"
]
}
Contributing
New checks are the easiest way to contribute — each check is a single file in cw_janitor/checks/ exposing CHECK_ID, TITLE, and run(session, region) -> list[Finding]. See CONTRIBUTING.md and the open issues for ideas (unused custom metrics, orphaned metric filters, Contributor Insights rules...).
License
MIT
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file cloudwatch_janitor-0.1.0.tar.gz.
File metadata
- Download URL: cloudwatch_janitor-0.1.0.tar.gz
- Upload date:
- Size: 9.8 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
d156d48a3d70a3c1e9d92c32fe3ed9b311e9abbebb0007b7dfea5d35138adb78
|
|
| MD5 |
8a0503ed3a7b932429eadd77526ff2e2
|
|
| BLAKE2b-256 |
d74c98fc7a207f69adb28e7198c226c77177fc6342ad5038a6c5638459a98405
|
Provenance
The following attestation bundles were made for cloudwatch_janitor-0.1.0.tar.gz:
Publisher:
publish.yml on varunmj/cloudwatch-janitor
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
cloudwatch_janitor-0.1.0.tar.gz -
Subject digest:
d156d48a3d70a3c1e9d92c32fe3ed9b311e9abbebb0007b7dfea5d35138adb78 - Sigstore transparency entry: 2294628266
- Sigstore integration time:
-
Permalink:
varunmj/cloudwatch-janitor@9402049265649ce7a71abe07a4c6324a6ea643d3 -
Branch / Tag:
refs/tags/v0.1.0 - Owner: https://github.com/varunmj
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@9402049265649ce7a71abe07a4c6324a6ea643d3 -
Trigger Event:
release
-
Statement type:
File details
Details for the file cloudwatch_janitor-0.1.0-py3-none-any.whl.
File metadata
- Download URL: cloudwatch_janitor-0.1.0-py3-none-any.whl
- Upload date:
- Size: 11.5 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
2b02dfbfc40a0ee2c8463d2fcd755d47028b84f86895708adc33ab052aa9f0fe
|
|
| MD5 |
3be68fb607695a1fcd0c32c06c64497b
|
|
| BLAKE2b-256 |
c5861578eda30b25162e61c88aa82381d045a77fabe8f42c9c465587e82857d2
|
Provenance
The following attestation bundles were made for cloudwatch_janitor-0.1.0-py3-none-any.whl:
Publisher:
publish.yml on varunmj/cloudwatch-janitor
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
cloudwatch_janitor-0.1.0-py3-none-any.whl -
Subject digest:
2b02dfbfc40a0ee2c8463d2fcd755d47028b84f86895708adc33ab052aa9f0fe - Sigstore transparency entry: 2294628344
- Sigstore integration time:
-
Permalink:
varunmj/cloudwatch-janitor@9402049265649ce7a71abe07a4c6324a6ea643d3 -
Branch / Tag:
refs/tags/v0.1.0 - Owner: https://github.com/varunmj
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@9402049265649ce7a71abe07a4c6324a6ea643d3 -
Trigger Event:
release
-
Statement type: