Library / SDK
prometheus/cloudwatch_exporter avatar
prometheus/cloudwatch_exporter

cloudwatch_exporter: exporting AWS CloudWatch metrics into Prometheus

Metrics exporter for Amazon AWS CloudWatch

977 stars340 forksJavaApache-2.0

At a glance

What is it?
The Prometheus cloudwatch_exporter is a Java exporter that scrapes Amazon CloudWatch metrics and republishes them in Prometheus format, driven by a YAML file that declares each metric, its dimensions, and how it is selected. It is not archived, and the last push was on 2026-10-19.
Who is it for?
cloudwatch_exporter fits teams that already run Prometheus and need AWS service metrics in the same scrape target as everything else, especially when the metric set is known, bounded, and written down in YAML.
Can I use it commercially?
Yes. Apache-2.0 is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 1 day ago.
What is it written in?
Mainly Java, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 23, 2026, and from our analysis. They are not legal advice.

Editorial analysis

The gap: AWS service metrics live behind an API that Prometheus cannot scrape

CloudWatch is where AWS publishes the metrics for everything running inside an account, from load balancer request counts to Lambda durations. Prometheus cannot scrape CloudWatch directly, since CloudWatch exposes a query API rather than a metrics endpoint. Someone has to sit in between, translate the API calls into the Prometheus exposition format, and keep the mapping stable over time. The Prometheus cloudwatch_exporter is that bridge: a Prometheus exporter for Amazon CloudWatch. The intended users are platform and SRE teams running Prometheus in an AWS account, usually in a hybrid setup where the Prometheus server sits outside the cloud or in a second account. The design is explicit about scope. It exports the metrics you declare, in the way you declare them, and it leaves discovery and selection of what to collect as a configuration decision rather than a code change.

A YAML file is the whole interface to CloudWatch

Everything the exporter collects is described in a YAML configuration file. The top level has a region, an optional role_arn, and a required metrics list. Each entry in that list names a namespace, a metric, the dimensions for that metric, and the statistics to retrieve. A minimal entry looks like this:

yaml
---
region: eu-west-1
metrics:
 - aws_namespace: AWS/ELB
   aws_metric_name: RequestCount
   aws_dimensions: [AvailabilityZone, LoadBalancerName]
   aws_dimension_select:
     LoadBalancerName: [myLB]
   aws_statistics: [Sum]

The rule that catches people is on aws_dimensions. The documentation states it should contain exactly all the dimensions available for a metric, and it tells you to run aws cloudwatch list-metrics to find out which ones you need. That is not a suggestion, it is a correctness requirement, since a metric with a missing dimension cannot be queried and will not appear. The other keys are optional and can be set globally or per metric, which lets a file declare a common policy once and override it where a metric behaves differently.

Selecting resources by tag rather than by dimension value

The aws_dimension_select key filters on dimension values, so it works well when you know the name of the load balancer or the instance. It does not work when resources are created dynamically, which is why the exporter also supports aws_tag_select. The tag based form filters on the resources themselves and then maps the tagged resource ID back to a CloudWatch dimension:

yaml
---
region: eu-west-1
metrics:
 - aws_namespace: AWS/ELB
   aws_metric_name: RequestCount
   aws_dimensions: [AvailabilityZone, LoadBalancerName]
   aws_tag_select:
     tag_selections:
       Monitoring: ["enabled"]
     resource_type_selection: "elasticloadbalancing:loadbalancer"
     resource_id_dimension: LoadBalancerName
   aws_statistics: [Sum]

Two keys under aws_tag_select are required. resource_type_selection is the resource type to filter on, written as service:resource_type following the resource group tagging API, and the resource type part can be an empty string in cases like S3 where the value is s3:. resource_id_dimension tells the exporter which CloudWatch dimension corresponds to the ARN resource ID. For metrics whose dimension does not follow the usual resource ID convention, arn_resource_id_regexp lets you supply an alternative regular expression, with a documented default of (?:([^:/]+)|[^:/]+/([^:]+))$ where the first non empty match group is used. This tag path needs the tag:GetResources IAM permission in addition to the CloudWatch ones, and it is what makes the exporter usable with auto scaling groups rather than only with fixed resource names.

Timing knobs that decide whether your alerts fire correctly

Three timing keys control what you actually receive, and each solves a specific CloudWatch behaviour. delay_seconds determines the newest data to request and exists to avoid collecting data that has not fully converged, defaulting to 600 seconds. range_seconds sets how far back to look, also defaulting to 600 seconds, and the documentation points at Billing metrics as the case where a short range is useless because those are only set every few hours. period_seconds sets the CloudWatch period to request, with only the most recent data point used, defaulting to 60 seconds. A fourth key, set_timestamp, decides whether the Prometheus timestamp keeps the original CloudWatch timestamp, and it defaults to true. That default has a documented catch: for metrics updated very infrequently, such as S3 BucketSize, Prometheus may refuse to scrape them if the timestamp is set to true, which the README ties to issue 100. The values can be set globally and per metric, so the usual pattern is a conservative global delay with a tighter override for a metric you know lands quickly.

Building the jar, checking the config, and running on port 9106

The exporter is a Java program that requires at least Java 11, and the repository builds with the bundled Maven wrapper:

bash
./mvnw package

That produces a jar with dependencies which is then run with the listen port and the config file as arguments:

bash
java -jar target/cloudwatch_exporter-*-SNAPSHOT-jar-with-dependencies.jar 9106 example.yml

The most useful command for anyone writing a configuration for the first time is the config check, which validates the YAML without starting the HTTP server or contacting CloudWatch, and exits 0 if the file is valid and 1 if it is not:

bash
java -jar target/cloudwatch_exporter-*-SNAPSHOT-jar-with-dependencies.jar --check-config example.yml

That turns a broken dimension list from a runtime surprise into a check you can run in a pull request. For teams that would rather not build, the README points at the most recent pre-built jar on the Maven central search page. The repository also ships an example.yml at the root and an examples directory with per namespace files such as EC2.yml, ELB.yml, S3 related entries, Lambda.yml, RDS style files, and more, and it links to a separate configuration builder tool for people who would rather assemble the file through a UI.

Credentials, IAM, and the container image

The exporter uses the AWS Java SDK, which offers a variety of ways to provide credentials, including the AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY environment variables. The IAM permissions required are cloudwatch:ListMetrics, cloudwatch:GetMetricStatistics, and cloudwatch:GetMetricData, and tag:GetResources is additionally required for the aws_tag_select feature. The role_arn key exists for cross account metrics, since the exporter can assume a role rather than operate only inside one account. Region resolution has two paths: set region in the YAML, or leave it out and let the SDK determine it from the default region provider chain. The Dockerfile shows the deployment shape. It builds with an eclipse-temurin JDK image, runs the same wrapper build, renames the jar, and then copies it into a JRE runtime image:

dockerfile
EXPOSE 9106
dockerfile
ENTRYPOINT [ "java", "-jar", "/cloudwatch_exporter.jar", "9106"]
CMD ["/config/config.yml"]

So the container takes the config path as a command argument, defaults to /config/config.yml, and exposes 9106. The image also drops to a non root user by specifying USER 65534, which matters for anyone running it under a restrictive cluster policy.

Where cloudwatch_exporter is the wrong tool

The README itself names the alternatives and that is the fastest way to understand the boundaries. For ECS workloads there is also an ECS exporter. For a different approach to CloudWatch metrics, with automatic discovery, the recommendation is Yet Another CloudWatch Exporter. The difference in approach is the key point. This exporter is configuration driven and static: you list namespaces and metrics, and it fetches exactly those. YACE discovers and selects metrics on its own, which suits accounts where the resource set changes constantly or where nobody wants to maintain a YAML file per namespace. The downside of the static approach is that a new autoscaling group or a new load balancer only shows up in Prometheus after somebody edits the config. A second limit is the IAM surface. GetMetricData is required even when the older GetMetricStatistics path is in use, because use_get_metric_data is described as an experimental boolean that switches between GetMetricData and GetMetricStatistics, and it defaults to false but the permission list still names GetMetricData. Roles for service accounts also mean cross account configuration has to be arranged on the AWS side before the exporter can report anything.

Releases, licence, and the cost of an upgrade

The project is not archived and the last push was on 2026-10-19, so work on it is current. The release history is worth reading for upgrade planning: v0.18.0 shipped on 2026-07-01, v0.17.0 on 2026-06-08, and v0.16.0 on 2024-08-18, which is a long gap before the two recent ones. The version stays below 1.0, so the project is not claiming a stable API contract, and the RELEASEING.md and MAINTAINERS.md files at the repository root tell you who to look at when a release note needs context. Licence is Apache 2.0, with the LICENSE and NOTICE files at the root. For a service that runs inside your own account and only reads metrics, Apache 2 is a permissive choice with no copyleft obligation on the surrounding deployment, provided the notices are retained. The upgrade cost for a running deployment is mostly in configuration rather than in code, since the exporter is a jar or a container that reads a YAML file, and the check-config flag lets you validate a changed file before it reaches a running pod.

Editorial conclusion

cloudwatch_exporter fits teams that already run Prometheus and need AWS service metrics in the same scrape target as everything else, especially when the metric set is known, bounded, and written down in YAML. It is a poor fit if you want automatic discovery of every metric on every resource, since that is the explicit job of the Yet Another CloudWatch Exporter alternative the README points to, and it is a poor fit if you cannot issue IAM permissions that grant cloudwatch:ListMetrics, cloudwatch:GetMetricStatistics and cloudwatch:GetMetricData. Before adopting it, run the jar with --check-config against your configuration to validate it without contacting CloudWatch, confirm the region resolves either from the config or from the default region provider chain, and review the delay_seconds default of 600 seconds against your alert thresholds.

Frequently asked questions

How do I run the Prometheus cloudwatch_exporter?

Build with ./mvnw package, then run java -jar target/cloudwatch_exporter-*-SNAPSHOT-jar-with-dependencies.jar 9106 example.yml with your YAML config. The exporter requires at least Java 11, and the container image exposes port 9106 with /config/config.yml as the default config path.

Which AWS IAM permissions does cloudwatch_exporter need?

The cloudwatch:ListMetrics, cloudwatch:GetMetricStatistics and cloudwatch:GetMetricData permissions are required. The tag:GetResources permission is also required if you use the aws_tag_select feature to select resources by tag.

How do I validate a cloudwatch_exporter config file?

Run the jar with --check-config and the path to your file. The process validates the YAML without starting the HTTP server or contacting CloudWatch, and it exits 0 if the file is valid and 1 if it is not.

What is the difference between aws_dimension_select and aws_tag_select?

aws_dimension_select filters on CloudWatch dimension values, which needs the resource names to be known. aws_tag_select filters on the tagged resources and maps the tagged resource ID back to a CloudWatch dimension, which is what makes it usable with resources created dynamically.

Should I use cloudwatch_exporter or Yet Another CloudWatch Exporter?

The README points to YACE for a different approach with automatic discovery, and it is the better fit when the resource set changes constantly or you do not want to maintain a YAML file per namespace. cloudwatch_exporter fits when the metric set is known and you want the mapping written down explicitly.

Official sources

  1. Issues
  2. License: Apache-2.0
  3. prometheus/cloudwatch_exporter on GitHub
  4. README
  5. Releases
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/prometheus-cloudwatch-exporter.svg)](https://hysenlabs.com/projects/prometheus-cloudwatch-exporter)

Was this useful?