├── .circleci └── config.yml ├── .dockerignore ├── .github ├── ISSUE_TEMPLATE │ ├── bug.md │ ├── config.yml │ ├── metrics.md │ └── request.md ├── dependabot.yaml └── workflows │ ├── container_description.yml │ └── maven.yml ├── .gitignore ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── Dockerfile ├── LICENSE ├── MAINTAINERS.md ├── Makefile ├── NOTICE ├── README.md ├── RELEASING.md ├── SECURITY.md ├── example.yml ├── examples ├── AmazonMQ.yml ├── ApiGateway.yml ├── AppRunner.yml ├── ApplicationELB.yml ├── Athena.yml ├── AuroraServerless.yml ├── AutoScaling.yml ├── Backup.yml ├── CloudFront.yml ├── DDoSProtection.yml ├── DMS.yml ├── DocumentDB.yml ├── DynamoDB.yml ├── EBS.yml ├── EC2.yml ├── ECS.yml ├── EFS.yml ├── ELB.yml ├── ElastiCache.yml ├── Fargate.yml ├── Firehose.yml ├── Kafka.yml ├── Kinesis.yml ├── Lambda.yml ├── NATGateway.yml ├── NetworkELB.yml ├── RDS.yml ├── Redshift.yml ├── Route53.yml ├── S3.yml ├── SES.yml ├── SNS.yml ├── SQS.yml ├── Sagemaker.yml ├── VPN.yml ├── WAF.yml ├── WAFV2.yml └── dashboards │ └── DocumentDB.yml ├── pom.xml └── src ├── main ├── java │ └── io │ │ └── prometheus │ │ └── cloudwatch │ │ ├── BuildInfoCollector.java │ │ ├── CachingDimensionSource.java │ │ ├── CloudWatchCollector.java │ │ ├── DataGetter.java │ │ ├── DefaultDimensionSource.java │ │ ├── DimensionSource.java │ │ ├── DisallowHttpMethods.java │ │ ├── DynamicReloadServlet.java │ │ ├── GetMetricDataDataGetter.java │ │ ├── GetMetricStatisticsDataGetter.java │ │ ├── HealthServlet.java │ │ ├── HomePageServlet.java │ │ ├── MetricRule.java │ │ ├── ReloadSignalHandler.java │ │ └── WebServer.java └── resources │ └── .properties └── test └── java └── io └── prometheus └── cloudwatch ├── CachingDimensionExpiryTest.java ├── CachingDimensionSourceTest.java ├── CloudWatchCollectorTest.java ├── GetMetricDataGetterTest.java └── RequestsMatchers.java /.circleci/config.yml: -------------------------------------------------------------------------------- 1 | --- 2 | version: 2.1 3 | 4 | orbs: 5 | prometheus: prometheus/prometheus@0.17.1 6 | 7 | executors: 8 | java: 9 | docker: 10 | - image: cimg/openjdk:21.0 11 | 12 | jobs: 13 | build: 14 | working_directory: ~/circleci-java 15 | executor: java 16 | steps: 17 | - checkout 18 | - restore_cache: # restore the saved cache after the first run or if `pom.xml` has changed 19 | key: circleci-demo-java-spring-{{ checksum "pom.xml" }} 20 | - run: mvn dependency:go-offline # gets the project dependencies 21 | - save_cache: 22 | paths: 23 | - ~/.m2 24 | key: circleci-demo-java-spring-{{ checksum "pom.xml" }} 25 | - run: 26 | name: Check formatting 27 | command: | 28 | if (mvn fmt:check); 29 | then 30 | echo "Code is well formatted" 31 | else 32 | echo "Code is not formatted well. Please run 'mvn fmt:format' and commit changes" 33 | exit 1 34 | fi 35 | - run: mvn package 36 | publish_image: 37 | executor: java 38 | environment: 39 | DOCKER_BUILDKIT: 1 40 | BUILDX_PLATFORMS: linux/amd64,linux/arm64 41 | steps: 42 | - checkout 43 | - setup_remote_docker 44 | - run: 45 | name: Install buildx 46 | command: | 47 | BUILDX_BINARY_URL="https://github.com/docker/buildx/releases/download/v0.7.0/buildx-v0.7.0.linux-amd64" 48 | 49 | curl --output docker-buildx \ 50 | --silent --show-error --location --fail --retry 3 \ 51 | "$BUILDX_BINARY_URL" 52 | 53 | mkdir -p ~/.docker/cli-plugins 54 | 55 | mv docker-buildx ~/.docker/cli-plugins/ 56 | chmod a+x ~/.docker/cli-plugins/docker-buildx 57 | 58 | docker buildx install 59 | # Run binfmt 60 | docker run --rm --privileged tonistiigi/binfmt:latest --install "$BUILDX_PLATFORMS" 61 | - run: docker context create buildx 62 | - run: docker buildx create --name buildx --use buildx 63 | - run: docker login -u "$QUAY_LOGIN" -p "$QUAY_PASSWORD" quay.io 64 | - run: docker login -u "$DOCKER_LOGIN" -p "$DOCKER_PASSWORD" 65 | - run: | 66 | tags=(master main) 67 | if [[ -n "$CIRCLE_TAG" ]]; then 68 | tags+=("${CIRCLE_TAG}" latest) 69 | fi 70 | 71 | set -x 72 | docker buildx build \ 73 | --progress plain \ 74 | --platform "$BUILDX_PLATFORMS" \ 75 | "${tags[@]/#/--tag=quay.io/prometheus/cloudwatch-exporter:}" \ 76 | "${tags[@]/#/--tag=prom/cloudwatch-exporter:}" \ 77 | --push . 78 | - run: docker images 79 | build_image: 80 | executor: java 81 | environment: 82 | DOCKER_BUILDKIT: 1 83 | BUILDX_PLATFORMS: linux/amd64,linux/arm64 84 | steps: 85 | - checkout 86 | - setup_remote_docker 87 | - run: 88 | name: Install buildx 89 | command: | 90 | BUILDX_BINARY_URL="https://github.com/docker/buildx/releases/download/v0.7.0/buildx-v0.7.0.linux-amd64" 91 | 92 | curl --output docker-buildx \ 93 | --silent --show-error --location --fail --retry 3 \ 94 | "$BUILDX_BINARY_URL" 95 | 96 | mkdir -p ~/.docker/cli-plugins 97 | 98 | mv docker-buildx ~/.docker/cli-plugins/ 99 | chmod a+x ~/.docker/cli-plugins/docker-buildx 100 | 101 | docker buildx install 102 | # Run binfmt 103 | docker run --rm --privileged tonistiigi/binfmt:latest --install "$BUILDX_PLATFORMS" 104 | - run: docker context create buildx 105 | - run: docker buildx create --name buildx --use buildx 106 | - run: | 107 | docker buildx build \ 108 | --progress plain \ 109 | --platform "$BUILDX_PLATFORMS" \ 110 | . 111 | 112 | workflows: 113 | version: 2 114 | cloudwatch_exporter: 115 | jobs: 116 | - build: 117 | filters: 118 | tags: 119 | only: /.*/ 120 | - build_image: 121 | requires: 122 | - build 123 | filters: 124 | branches: 125 | ignore: master 126 | - publish_image: 127 | context: org-context 128 | requires: 129 | - build 130 | filters: 131 | tags: 132 | only: /.*/ 133 | branches: 134 | only: master 135 | -------------------------------------------------------------------------------- /.dockerignore: -------------------------------------------------------------------------------- 1 | ### Maven template 2 | target/ 3 | pom.xml.tag 4 | pom.xml.releaseBackup 5 | pom.xml.versionsBackup 6 | pom.xml.next 7 | release.properties 8 | dependency-reduced-pom.xml 9 | buildNumber.properties 10 | .mvn/timing.properties 11 | # https://github.com/takari/maven-wrapper#usage-without-binary-jar 12 | .mvn/wrapper/maven-wrapper.jar 13 | 14 | ### Java template 15 | # Compiled class file 16 | *.class 17 | 18 | # Log file 19 | *.log 20 | 21 | # BlueJ files 22 | *.ctxt 23 | 24 | # Mobile Tools for Java (J2ME) 25 | .mtj.tmp/ 26 | 27 | # Package Files # 28 | *.jar 29 | *.war 30 | *.nar 31 | *.ear 32 | *.zip 33 | *.tar.gz 34 | *.rar 35 | 36 | # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml 37 | hs_err_pid* 38 | 39 | ### JetBrains template 40 | # Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio, WebStorm and Rider 41 | # Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 42 | 43 | # User-specific stuff 44 | .idea/ 45 | 46 | # CMake 47 | cmake-build-*/ 48 | 49 | # File-based project format 50 | *.iws 51 | 52 | # IntelliJ 53 | out/ 54 | 55 | # mpeltonen/sbt-idea plugin 56 | .idea_modules/ 57 | 58 | # JIRA plugin 59 | atlassian-ide-plugin.xml 60 | 61 | # Crashlytics plugin (for Android Studio and IntelliJ) 62 | com_crashlytics_export_strings.xml 63 | crashlytics.properties 64 | crashlytics-build.properties 65 | fabric.properties 66 | 67 | # local additions 68 | .circleci/ 69 | example* 70 | .git* 71 | 72 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: 'Report a bug' 3 | about: Report a bug 🪲 4 | title: "[bug]: bug title here" 5 | labels: bug 6 | assignees: '' 7 | 8 | --- 9 | 10 | ### What did you do 11 | 12 | 13 | 14 | ### What did you expect to see? 15 | 16 | ### What did you see instead? Under which circumstances? 17 | 18 | ### Are you currently working around this issue? 19 | 20 | 21 | 22 | ### Additional context 23 | 24 | 25 | 26 | 27 | 28 | ### Environment 29 | 30 | * Exporter version: `X.X.X` 31 | * Operating system & architecture: `XX` 32 | * Running in containers? y/n 33 | * Using the official image? y/n 34 | 35 | 36 | ### Exporter configuration file 37 | 38 |
39 | expand 40 | 41 | ```yaml 42 | 43 | ``` 44 | 45 |
46 | 47 | ### Logs 48 | 49 | 50 |
51 | expand 52 | 53 | ```log 54 | (paste log lines here) 55 | ``` 56 | 57 |
58 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/config.yml: -------------------------------------------------------------------------------- 1 | blank_issues_enabled: false 2 | contact_links: 3 | - name: Prometheus community channels 4 | url: https://prometheus.io/community 5 | about: For general prometheus questions ❓❓ 6 | - name: Cloudwatch Service quotas 7 | url: https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/cloudwatch_limits.html 8 | about: Read about Cloudwatch quotas 9 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/metrics.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: 'Metrics issue' 3 | about: Request help getting metrics out of CloudWatch 📈 4 | title: "[metrics]: short description here" 5 | labels: metrics-configuration 6 | assignees: '' 7 | 8 | --- 9 | 10 | ### Context information 11 | 12 | 13 | 14 | * AWS service: 15 | * CloudWatch namespace: 16 | * Link to metrics documentation for this service: 17 | * AWS region of the exporter: 18 | * AWS region of the service: 19 | 20 |
21 | 22 | Exporter configuration 23 | 24 | 25 | 26 | ```yaml 27 | 28 | 29 | 30 | 31 | ``` 32 | 33 |
34 | 35 |
36 | 37 | Exporter logs 38 | 39 | 40 | 41 | ```log 42 | 43 | ``` 44 | 45 | ### What do you expect to happen? 46 | 47 | 48 | 49 | ### What happened instead? 50 | 51 | 52 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: 'Suggest a feature' 3 | about: Suggest an idea to make the tool better! 🌟 4 | title: "[request]: describe request here" 5 | labels: enhancement 6 | assignees: '' 7 | 8 | --- 9 | ## Use case. Why is this important? 10 | 11 | 12 | 13 | ## How do you think the new configuration should look like? 14 | 15 | 16 | Example: 17 | 18 | ```yaml 19 | 20 | ``` 21 | -------------------------------------------------------------------------------- /.github/dependabot.yaml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | - package-ecosystem: "maven" # See documentation for possible values 4 | directory: "/" # Location of package manifests 5 | schedule: 6 | interval: "weekly" 7 | day: "thursday" 8 | open-pull-requests-limit: 100 9 | - package-ecosystem: "github-actions" 10 | directory: "/" 11 | schedule: 12 | interval: "weekly" 13 | day: "thursday" 14 | -------------------------------------------------------------------------------- /.github/workflows/container_description.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: Push README to Docker Hub 3 | on: 4 | push: 5 | paths: 6 | - "README.md" 7 | - "README-containers.md" 8 | - ".github/workflows/container_description.yml" 9 | branches: [ main, master ] 10 | 11 | permissions: 12 | contents: read 13 | 14 | jobs: 15 | PushDockerHubReadme: 16 | runs-on: ubuntu-latest 17 | name: Push README to Docker Hub 18 | if: github.repository_owner == 'prometheus' || github.repository_owner == 'prometheus-community' # Don't run this workflow on forks. 19 | steps: 20 | - name: git checkout 21 | uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 22 | - name: Set docker hub repo name 23 | run: echo "DOCKER_REPO_NAME=$(make docker-repo-name)" >> $GITHUB_ENV 24 | - name: Push README to Dockerhub 25 | uses: christian-korneck/update-container-description-action@d36005551adeaba9698d8d67a296bd16fa91f8e8 # v1 26 | env: 27 | DOCKER_USER: ${{ secrets.DOCKER_HUB_LOGIN }} 28 | DOCKER_PASS: ${{ secrets.DOCKER_HUB_PASSWORD }} 29 | with: 30 | destination_container_repo: ${{ env.DOCKER_REPO_NAME }} 31 | provider: dockerhub 32 | short_description: ${{ env.DOCKER_REPO_NAME }} 33 | # Empty string results in README-containers.md being pushed if it 34 | # exists. Otherwise, README.md is pushed. 35 | readme_file: '' 36 | 37 | PushQuayIoReadme: 38 | runs-on: ubuntu-latest 39 | name: Push README to quay.io 40 | if: github.repository_owner == 'prometheus' || github.repository_owner == 'prometheus-community' # Don't run this workflow on forks. 41 | steps: 42 | - name: git checkout 43 | uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 44 | - name: Set quay.io org name 45 | run: echo "DOCKER_REPO=$(echo quay.io/${GITHUB_REPOSITORY_OWNER} | tr -d '-')" >> $GITHUB_ENV 46 | - name: Set quay.io repo name 47 | run: echo "DOCKER_REPO_NAME=$(make docker-repo-name)" >> $GITHUB_ENV 48 | - name: Push README to quay.io 49 | uses: christian-korneck/update-container-description-action@d36005551adeaba9698d8d67a296bd16fa91f8e8 # v1 50 | env: 51 | DOCKER_APIKEY: ${{ secrets.QUAY_IO_API_TOKEN }} 52 | with: 53 | destination_container_repo: ${{ env.DOCKER_REPO_NAME }} 54 | provider: quay 55 | # Empty string results in README-containers.md being pushed if it 56 | # exists. Otherwise, README.md is pushed. 57 | readme_file: '' 58 | -------------------------------------------------------------------------------- /.github/workflows/maven.yml: -------------------------------------------------------------------------------- 1 | # This workflow will build a Java project with Maven, and cache/restore any dependencies to improve the workflow execution time 2 | # For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-java-with-maven 3 | 4 | # This workflow uses actions that are not certified by GitHub. 5 | # They are provided by a third-party and are governed by 6 | # separate terms of service, privacy policy, and support 7 | # documentation. 8 | 9 | name: Java CI with Maven 10 | 11 | on: 12 | push: 13 | branches: [ "master" ] 14 | 15 | jobs: 16 | build: 17 | 18 | runs-on: ubuntu-latest 19 | 20 | steps: 21 | - uses: actions/checkout@v4 22 | - name: Set up JDK 21 23 | uses: actions/setup-java@v4 24 | with: 25 | java-version: '21' 26 | distribution: 'temurin' 27 | cache: maven 28 | - name: test 29 | run: mvn -B test --file pom.xml 30 | - name: build 31 | run: mvn -B package --file pom.xml 32 | 33 | # Upload the full dependency graph to GitHub to improve the quality of Dependabot alerts this repository can receive 34 | - name: Update dependency graph 35 | uses: advanced-security/maven-dependency-submission-action@v4.1.1 36 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /targetpom.xml.releaseBackup 2 | release.properties 3 | target/ 4 | /pom.xml.releaseBackup 5 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Prometheus Community Code of Conduct 2 | 3 | Prometheus follows the [CNCF Code of Conduct](https://github.com/cncf/foundation/blob/main/code-of-conduct.md). 4 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing 2 | 3 | Prometheus uses GitHub to manage reviews of pull requests. 4 | 5 | * If you have a trivial fix or improvement, go ahead and create a pull request, 6 | addressing (with `@...`) the maintainer of this repository (see 7 | [MAINTAINERS.md](MAINTAINERS.md)) in the description of the pull request. 8 | 9 | * If you plan to do something more involved, first discuss your ideas 10 | on our [mailing list](https://groups.google.com/forum/?fromgroups#!forum/prometheus-developers). 11 | This will avoid unnecessary work and surely give you and us a good deal 12 | of inspiration. 13 | 14 | ### Formatting 15 | - IDEs differ in how they format Java code. This can generate a lot of unrelated code change. To avoid this - we enforce specific formatting. 16 | - Code is automatically formatted with [Spotify fmt maven-plugin](https://github.com/spotify/fmt-maven-plugin) whenever you run standard `mvn install`. 17 | - CI builds will fail if code is not formatted that way. 18 | - To simply run the formatter you can always run: `mvn fmt:format` (requires JVM > 11) 19 | # Releasing 20 | 21 | For release instructions, see [RELEASING](RELEASING.md). 22 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM eclipse-temurin:21-jdk-noble as builder 2 | 3 | SHELL ["/bin/bash", "-xe", "-o", "pipefail", "-c"] 4 | 5 | ARG MAVEN_VERSION=3.8.5 6 | ARG MAVEN_SHA512=89ab8ece99292476447ef6a6800d9842bbb60787b9b8a45c103aa61d2f205a971d8c3ddfb8b03e514455b4173602bd015e82958c0b3ddc1728a57126f773c743 7 | 8 | ADD https://archive.apache.org/dist/maven/maven-3/${MAVEN_VERSION}/binaries/apache-maven-${MAVEN_VERSION}-bin.tar.gz /opt/maven.tar.gz 9 | RUN mkdir -p /opt/maven \ 10 | && echo "${MAVEN_SHA512} /opt/maven.tar.gz" | sha512sum -c \ 11 | && tar -x --strip-components=1 -C /opt/maven -f /opt/maven.tar.gz 12 | ENV PATH /opt/maven/bin:${PATH} 13 | 14 | WORKDIR /cloudwatch_exporter 15 | COPY . /cloudwatch_exporter 16 | 17 | RUN mvn package \ 18 | && mv target/cloudwatch_exporter-*-with-dependencies.jar /cloudwatch_exporter.jar 19 | 20 | FROM eclipse-temurin:21-jre-noble as runner 21 | LABEL maintainer="The Prometheus Authors " 22 | EXPOSE 9106 23 | 24 | WORKDIR / 25 | RUN mkdir /config 26 | COPY --from=builder /cloudwatch_exporter.jar /cloudwatch_exporter.jar 27 | ENTRYPOINT [ "java", "-jar", "/cloudwatch_exporter.jar", "9106"] 28 | CMD ["/config/config.yml"] 29 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [yyyy] [name of copyright owner] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /MAINTAINERS.md: -------------------------------------------------------------------------------- 1 | * Matthias Rampke @matthiasr 2 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | # This is a dummy Makefile to satisfy expectations from common workflows. 2 | # Since this is not a Go project, we do not import Makefile.common from 3 | # github.com/prometheus/prometheus, but some common workflows depend on targets 4 | # there. 5 | 6 | DOCKER_IMAGE_NAME = cloudwatch-exporter 7 | DOCKER_REPO ?= prom 8 | 9 | .PHONY: docker-repo-name 10 | docker-repo-name: common-docker-repo-name 11 | 12 | .PHONY: common-docker-repo-name 13 | common-docker-repo-name: 14 | @echo "$(DOCKER_REPO)/$(DOCKER_IMAGE_NAME)" 15 | -------------------------------------------------------------------------------- /NOTICE: -------------------------------------------------------------------------------- 1 | Metrics exporter for Amazon AWS CloudWatch 2 | Copyright 2015 The Prometheus Authors 3 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | CloudWatch Exporter 2 | ===== 3 | 4 | A Prometheus exporter for [Amazon CloudWatch](http://aws.amazon.com/cloudwatch/). 5 | 6 | ## Alternatives 7 | 8 | For ECS workloads, there is also an [ECS exporter](https://github.com/prometheus-community/ecs_exporter). 9 | 10 | For a different approach to CloudWatch metrics, with automatic discovery, consider [Yet Another CloudWatch Exporter (YACE)](https://github.com/nerdswords/yet-another-cloudwatch-exporter). 11 | 12 | ## Building and running 13 | 14 | Cloudwatch Exporter requires at least Java 11. 15 | 16 | `mvn package` to build. 17 | 18 | `java -jar target/cloudwatch_exporter-*-SNAPSHOT-jar-with-dependencies.jar 9106 example.yml` to run. 19 | 20 | The most recent pre-built JAR can be found at http://search.maven.org/#search%7Cga%7C1%7Ca%3A%22cloudwatch_exporter%22 21 | 22 | ## Credentials and permissions 23 | 24 | The CloudWatch Exporter uses the 25 | [AWS Java SDK](http://docs.aws.amazon.com/AWSSdkDocsJava/latest/DeveloperGuide/welcome.html), 26 | which offers [a variety of ways to provide credentials](http://docs.aws.amazon.com/AWSSdkDocsJava/latest/DeveloperGuide/credentials.html). 27 | This includes the `AWS_ACCESS_KEY_ID` and `AWS_SECRET_ACCESS_KEY` environment 28 | variables. 29 | 30 | The `cloudwatch:ListMetrics`, `cloudwatch:GetMetricStatistics` and `cloudwatch:GetMetricData` IAM permissions are required. 31 | The `tag:GetResources` IAM permission is also required to use the `aws_tag_select` feature. 32 | 33 | ## Configuration 34 | The configuration is in YAML. 35 | 36 | An example with common options and `aws_dimension_select`: 37 | ``` 38 | --- 39 | region: eu-west-1 40 | metrics: 41 | - aws_namespace: AWS/ELB 42 | aws_metric_name: RequestCount 43 | aws_dimensions: [AvailabilityZone, LoadBalancerName] 44 | aws_dimension_select: 45 | LoadBalancerName: [myLB] 46 | aws_statistics: [Sum] 47 | ``` 48 | 49 | A similar example with common options and `aws_tag_select`: 50 | ``` 51 | --- 52 | region: eu-west-1 53 | metrics: 54 | - aws_namespace: AWS/ELB 55 | aws_metric_name: RequestCount 56 | aws_dimensions: [AvailabilityZone, LoadBalancerName] 57 | aws_tag_select: 58 | tag_selections: 59 | Monitoring: ["enabled"] 60 | resource_type_selection: "elasticloadbalancing:loadbalancer" 61 | resource_id_dimension: LoadBalancerName 62 | aws_statistics: [Sum] 63 | ``` 64 | **Note:** configuration examples for different namespaces can be found in [examples](./examples) directory 65 | 66 | **Note:** A configuration builder can be found [here](https://github.com/djloude/cloudwatch_exporter_metrics_config_builder). 67 | 68 | Name | Description 69 | ---------|------------ 70 | region | Optional. The AWS region to connect to. If none is provided, an attempt will be made to determine the region from the [default region provider chain](https://docs.aws.amazon.com/sdk-for-java/v1/developer-guide/java-dg-region-selection.html#default-region-provider-chain). 71 | role_arn | Optional. The AWS role to assume. Useful for retrieving cross account metrics. 72 | metrics | Required. A list of CloudWatch metrics to retrieve and export 73 | aws_namespace | Required. Namespace of the CloudWatch metric. 74 | aws_metric_name | Required. Metric name of the CloudWatch metric. 75 | aws_dimensions | Required. This should contain exactly all the dimensions available for a metric. Run `aws cloudwatch list-metrics` to find out which dimensions you need to include for your metric. 76 | aws_dimension_select | Optional. Which dimension values to filter. Specify a map from the dimension name to a list of values to select from that dimension. 77 | aws_dimension_select_regex | Optional. Which dimension values to filter on with a regular expression. Specify a map from the dimension name to a list of regexes that will be applied to select from that dimension. 78 | aws_tag_select | Optional. A tag configuration to filter on, based on mapping from the tagged resource ID to a CloudWatch dimension. 79 | tag_selections | Optional, under `aws_tag_select`. Specify a map from a tag key to a list of tag values to apply [tag filtering](https://docs.aws.amazon.com/resourcegroupstagging/latest/APIReference/API_GetResources.html#resourcegrouptagging-GetResources-request-TagFilters) on resources from which metrics will be gathered. 80 | resource_type_selection | Required, under `aws_tag_select`. Specify the [resource type](https://docs.aws.amazon.com/general/latest/gr/aws-arns-and-namespaces.html#genref-aws-service-namesspaces) to filter on. `resource_type_selection` should be comprised as `service:resource_type`, as per the [resource group tagging API](https://docs.aws.amazon.com/resourcegroupstagging/latest/APIReference/API_GetResources.html#resourcegrouptagging-GetResources-request-TagFilters). Where `resource_type` could be an empty string, like in S3 case: `resource_type_selection: "s3:"`. 81 | resource_id_dimension | Required, under `aws_tag_select`. For the current metric, specify which CloudWatch dimension maps to the ARN [resource ID](https://docs.aws.amazon.com/general/latest/gr/aws-arns-and-namespaces.html#arns-syntax). 82 | arn_resource_id_regexp | If the Cloudwatch dimension specified in `resource_id_dimension` doesn't conform to the convention for resource ID an alternative regular expression to extract the resource ID from the ARN can be given here. The default is `(?:([^:/]+)|[^:/]+/([^:]+))$`. The first non empty match group will be used. 83 | aws_statistics | Optional. A list of statistics to retrieve, values can include Sum, SampleCount, Minimum, Maximum, Average. Defaults to all statistics unless extended statistics are requested. 84 | aws_extended_statistics | Optional. A list of extended statistics to retrieve. Extended statistics currently include percentiles in the form `pN` or `pN.N`. 85 | delay_seconds | Optional. The newest data to request. Used to avoid collecting data that has not fully converged. Defaults to 600s. Can be set globally and per metric. 86 | range_seconds | Optional. How far back to request data for. Useful for cases such as Billing metrics that are only set every few hours. Defaults to 600s. Can be set globally and per metric. 87 | period_seconds | Optional. [Period](http://docs.aws.amazon.com/AmazonCloudWatch/latest/DeveloperGuide/cloudwatch_concepts.html#CloudWatchPeriods) to request the metric for. Only the most recent data point is used. Defaults to 60s. Can be set globally and per metric. 88 | set_timestamp | Optional. Boolean for whether to set the Prometheus metric timestamp as the original Cloudwatch timestamp. For some metrics which are updated very infrequently (such as S3/BucketSize), Prometheus may refuse to scrape them if this is set to true (see #100). Defaults to true. Can be set globally and per metric. 89 | use_get_metric_data | Optional. Boolean (experimental) Use GetMetricData API to get metrics instead of GetMetricStatistics. Can be set globally and per metric. 90 | list_metrics_cache_ttl | Optional. Number of seconds to cache the result of calling the ListMetrics API. Defaults to 0 (no cache). Can be set globally and per metric. 91 | warn_on_empty_list_dimensions | Optional. Boolean Emit warning if the exporter cannot determine what metrics to request 92 | 93 | 94 | The above config will export time series such as 95 | ``` 96 | # HELP aws_elb_request_count_sum CloudWatch metric AWS/ELB RequestCount Dimensions: ["AvailabilityZone","LoadBalancerName"] Statistic: Sum Unit: Count 97 | # TYPE aws_elb_request_count_sum gauge 98 | aws_elb_request_count_sum{job="aws_elb",instance="",load_balancer_name="mylb",availability_zone="eu-west-1c",} 42.0 99 | aws_elb_request_count_sum{job="aws_elb",instance="",load_balancer_name="myotherlb",availability_zone="eu-west-1c",} 7.0 100 | ``` 101 | 102 | If the `aws_tag_select` feature was used, an additional information metric will be exported for each AWS tagged resource matched by the resource type selection and tag selection (if specified), such as 103 | ``` 104 | # HELP aws_resource_info AWS information available for resource 105 | # TYPE aws_resource_info gauge 106 | aws_resource_info{job="aws_elb",instance="",arn="arn:aws:elasticloadbalancing:eu-west-1:121212121212:loadbalancer/mylb",load_balancer_name="mylb",tag_Monitoring="enabled",tag_MyOtherKey="MyOtherValue",} 1.0 107 | ``` 108 | aws_recource_info can be joined with other metrics using group_left in PromQL such as the following: 109 | ``` 110 | aws_elb_request_count_sum 111 | * on(load_balancer_name) group_left(tag_MyOtherKey) 112 | aws_resource_info 113 | ``` 114 | All metrics are exported as gauges. 115 | 116 | In addition `cloudwatch_exporter_scrape_error` will be non-zero if an error 117 | occurred during the scrape, and `cloudwatch_exporter_scrape_duration_seconds` 118 | contains the duration of that scrape. `cloudwatch_exporter_build_info` contains 119 | labels referencing the current build version and build release date. 120 | 121 | ### Build Info Metric 122 | 123 | `cloudwatch_exporter_build_info` is a default cloudwatch exporter metric that contains the current 124 | cloudwatch exporter version and release date as label values. The numeric metric value is statically 125 | set to 1. If the metrics label values are "unknown" the build information scrap failed. 126 | 127 | ### CloudWatch doesn't always report data 128 | 129 | Cloudwatch reports data either always or only in some cases, example only if there is a non-zero value. The CloudWatch Exporter mirrors this behavior, so you should refer to the Cloudwatch documentation to find out if your metric is always reported or not. 130 | 131 | ### Timestamps 132 | 133 | CloudWatch has been observed to sometimes take minutes for reported values to converge. The 134 | default `delay_seconds` will result in data that is at least 10 minutes old 135 | being requested to mitigate this. The samples exposed will have the timestamps of the 136 | data from CloudWatch, so usual staleness semantics will not apply and values will persist 137 | for 5m for instant vectors. 138 | 139 | In practice this means that if you evaluate an instant vector at the current 140 | time, you will not see data from CloudWatch. An expression such as 141 | `aws_elb_request_count_sum offset 10m` will allow you to access the data, and 142 | should be used in recording rules and alerts. 143 | 144 | For certain metrics which update relatively rarely, such as from S3, 145 | `set_timestamp` should be configured to false so that they are not exposed with 146 | a timestamp. This is as the true timestamp from CloudWatch could be so old that 147 | Prometheus would reject the sample. 148 | 149 | #### FAQ: I can see the metrics in `/metrics` but not in the Prometheus web console 150 | 151 | The metrics will be visible in Prometheus if you look more than `delay_seconds` in the past. 152 | Try the graph view. 153 | 154 | This is an unfortunate result of a fundamental mismatch between CloudWatch and Prometheus. 155 | CloudWatch metrics converge over time, that is, the value at time `T` can change up to some later time `T+dT`. 156 | Meanwhile, Prometheus assumes that once it has scraped a sample, that is the truth, and the past does not change. 157 | 158 | To compensate for this, by default the exporter [delays fetching metrics](https://github.com/prometheus/cloudwatch_exporter/blob/master/README.md#timestamps), that is, it only asks for data 10 minutes later, when _almost_ all AWS services have converged. 159 | It also reports to Prometheus that this sample is from the past. 160 | Because Prometheus, for an instant request, only looks back 5 minutes, it never sees any data "now". 161 | 162 | ### Special handling for certain DynamoDB metrics 163 | 164 | The DynamoDB metrics listed below break the usual CloudWatch data model. 165 | 166 | * ConsumedReadCapacityUnits 167 | * ConsumedWriteCapacityUnits 168 | * ProvisionedReadCapacityUnits 169 | * ProvisionedWriteCapacityUnits 170 | * ReadThrottleEvents 171 | * WriteThrottleEvents 172 | 173 | When these metrics are requested in the TableName dimension CloudWatch will 174 | return data only for the table itself, not for its Global Secondary Indexes. 175 | Retrieving data for indexes requires requesting data across both the TableName 176 | and GlobalSecondaryIndexName dimensions. This behaviour is different to that 177 | of every other CloudWatch namespace and requires that the exporter handle these 178 | metrics differently to avoid generating duplicate HELP and TYPE lines. 179 | 180 | When exporting one of the problematic metrics for an index the exporter will use 181 | a metric name in the format `aws_dynamodb_METRIC_index_STATISTIC` rather than 182 | the usual `aws_dynamodb_METRIC_STATISTIC`. The regular naming scheme will still 183 | be used when exporting these metrics for a table, and when exporting any other 184 | DynamoDB metrics not listed above. 185 | 186 | ### Reloading Configuration 187 | 188 | There are two ways to reload configuration: 189 | 190 | 1. Send a SIGHUP signal to the pid: `kill -HUP 1234` 191 | 2. POST to the `reload` endpoint: `curl -X POST localhost:9106/-/reload` 192 | 193 | If an error occurs during the reload, check the exporter's log output. 194 | 195 | ### Cost 196 | 197 | Amazon charges for every CloudWatch API request or for every Cloudwatch metric requested, see the [current charges](http://aws.amazon.com/cloudwatch/pricing/). 198 | 199 | - In case of using `GetMetricStatistics` (default) - Every metric retrieved requires one API request, which can include multiple 200 | statistics. 201 | - In addition, when `aws_dimensions` is provided, the exporter needs to do API requests to determine what metrics to request. This should be negligible compared to the requests for the metrics themselves. 202 | 203 | In the case that all `aws_dimensions` are provided in the `aws_dimension_select` list, the exporter will not perform the 204 | above API request. It will request all possible combination of values for those dimensions. 205 | This will reduce cost as the values for the dimensions do not need to be queried anymore, assuming that all possible value combinations are present in CloudWatch. 206 | 207 | If you have 100 API requests every minute, with the price of USD$10 per million 208 | requests (as of Aug 2018), that is around $45 per month. The 209 | `cloudwatch_requests_total` counter tracks how many requests are being made. 210 | 211 | When using the `aws_tag_select` feature, additional requests are made to the Resource Groups Tagging API, but these are [free](https://aws.amazon.com/blogs/aws/new-aws-resource-tagging-api/). 212 | The `tagging_api_requests_total` counter tracks how many requests are being made for these. 213 | 214 | ### Experimental GetMetricData 215 | We are transitioning to use `GetMetricsData` instead of `GetMetricsStatistics`. 216 | The benefits of using `GetMetricsData` is mainly around much better performence. 217 | 218 | Please refer to [this doc](https://aws.amazon.com/premiumsupport/knowledge-center/cloudwatch-getmetricdata-api/) explaining why it is best practice to use `GetMetricData` 219 | 220 | API | performence | Costs | Stability 221 | --- |--- |--- |--- 222 | `GetMetricStatistics` | May be slow at scale | Charged per API request | stable. (Default option) 223 | `GetMetricData` | Can retrieve data faster at scale | Charged per **metric** requested | New (opt-in via configuration) 224 | 225 | #### Transition plan 226 | At first this feature would be opt-in to allow you to decide when and how to test it 227 | On later versions we would swap the default so everyone can enjoy the benefits. 228 | 229 | Cloudwatch exporter also expose a new self metric called `cloudwatch_metrics_requested_total` that allows you to track number of requested metrics in addition to the number of API requests. 230 | 231 | ## Docker Images 232 | 233 | To run the CloudWatch exporter on Docker, you can use the image from 234 | 235 | * [prom/cloudwatch-exporter](https://hub.docker.com/r/prom/cloudwatch-exporter/) 236 | * [quay.io/prometheus/cloudwatch-exporter](https://quay.io/repository/prometheus/cloudwatch-exporter) 237 | 238 | The available tags are 239 | 240 | * `main`: snapshot updated on every push to the main branch 241 | * `latest`: the latest released version 242 | * `vX.Y.Z`: the specific version X.Y.Z. Note that up to version 0.11.0, the format was `cloudwatch-exporter_X.Y.Z`. 243 | 244 | The image exposes port 9106 and expects the config in `/config/config.yml`. 245 | To configure it, you can bind-mount a config from your host: 246 | 247 | ```sh 248 | docker run -p 9106 -v /path/on/host/config.yml:/config/config.yml quay.io/prometheus/cloudwatch-exporter 249 | ``` 250 | 251 | Specify the config as the CMD: 252 | 253 | ```sh 254 | docker run -p 9106 -v /path/on/host/us-west-1.yml:/config/us-west-1.yml quay.io/prometheus/cloudwatch-exporter /config/us-west-1.yml 255 | ``` 256 | 257 | Or create a config file named `config.yml` along with following 258 | Dockerfile in the same directory and build it with `docker build`: 259 | 260 | ```Dockerfile 261 | FROM prom/cloudwatch-exporter 262 | ADD config.yml /config/ 263 | ``` 264 | -------------------------------------------------------------------------------- /RELEASING.md: -------------------------------------------------------------------------------- 1 | # Releasing the CloudWatch exporter 2 | 3 | Only maintainers can do this. 4 | The process is based on the [`java_client` release process](https://github.com/prometheus/client_java/wiki/Development). 5 | 6 | ## Requirements 7 | 8 | * [Temurin JDK 21](https://adoptium.net/) 9 | * Maven 10 | * GPG 11 | 12 | ## Access to the OSS Sonatype repository 13 | 14 | Sign up through [Sonatype JIRA](https://issues.sonatype.org) if you don't have an account already. 15 | [File a Publishing Support ticket](https://central.sonatype.org/faq/get-support/#producers) ([example](https://issues.sonatype.org/browse/OSSRH-70163)) to gain access to the `io.prometheus` group in the Sonatype OSSRH. 16 | The same login will be used for the repository. 17 | 18 | Verify that you can log into [OSSRH](https://oss.sonatype.org/). 19 | The CloudWatch Exporter is at [io.prometheus.cloudwatch](https://oss.sonatype.org/#nexus-search;quick~io.prometheus.cloudwatch). 20 | 21 | Set up [Maven publishing](https://central.sonatype.org/publish/publish-maven/), specifically the `` block in `~/.m2/settings.xml`. 22 | Fetch your user token according to [these instructions](https://central.sonatype.org/publish/generate-token/). 23 | A minimal config: 24 | 25 | ```xml 26 | 30 | 31 | 32 | 33 | ossrh 34 | 35 | token-user 36 | token-password 37 | 38 | 39 | 40 | ``` 41 | 42 | The project setup is already done. 43 | 44 | ## Push a snapshot 45 | 46 | To push a snapshot, check out the latest main branch and run 47 | 48 | ```sh 49 | mvn clean deploy 50 | ``` 51 | 52 | This should succeed. 53 | 54 | ## Start a release 55 | 56 | To prepare a release: 57 | 58 | ```sh 59 | mvn release:clean release:prepare 60 | ``` 61 | 62 | This will 63 | 64 | 1. prompt for the version 65 | 2. update `pom.xml` with this version 66 | 3. create and push a git tag 67 | 4. build everything 68 | 5. GPG-sign the artifacts 69 | 70 | To actually release: 71 | 72 | ```sh 73 | mvn release:perform 74 | ``` 75 | 76 | This will upload everything to OSSRH into a **staging repository**. 77 | To locate it, [log into Sonatype OSS](https://oss.sonatype.org/), then open [Staging Repositories](https://oss.sonatype.org/#stagingRepositories). 78 | If it spins forever, open the [main page](https://oss.sonatype.org/) and log in first. 79 | If nothing shows up, you probably forgot to `mvn release:perform`. 80 | 81 | Press "Close" to promote the release. 82 | 83 | The staging repository will show "Activity: Operation in progress" for a few seconds. 84 | Refresh or check the Activity tab to see what's going on. 85 | 86 | Once closing is done, the "Release" button unlocks. 87 | Press it. 88 | 89 | This runs for a while, and the new version should become available on [OSSRH](https://oss.sonatype.org/#nexus-search;quick~io.prometheus.cloudwatch). 90 | It usually appears immediately after the release process is done, but can take a few hours to show up. 91 | 92 | ## Docker images 93 | 94 | As part of the release process, `mvn` will create the git tag. 95 | This tag is picked up by [CircleCI](https://app.circleci.com/pipelines/github/prometheus/cloudwatch_exporter?branch=master), which builds and pushes the [Docker images](README.md#docker-images). 96 | 97 | ## GitHub Release 98 | 99 | Create a [new GitHub release](https://github.com/prometheus/cloudwatch_exporter/releases/new). 100 | Select the tag for this version that Maven pushed. 101 | 102 | Use the format `A.B.C / YYYY-MM-DD` as the release title. 103 | Summarize the changes. 104 | 105 | The release files and signatures are available in `target/checkout/target/`. 106 | Upload the `.jar` and `.jar.asc` files to the GitHub release. 107 | 108 | Publish the release. 109 | 110 | ## Announcement 111 | 112 | Announce the changes to [prometheus-announce](mailto:prometheus-announce@groups.google.com), linking to OSSRH and the GitHub release. 113 | -------------------------------------------------------------------------------- /SECURITY.md: -------------------------------------------------------------------------------- 1 | # Reporting a security issue 2 | 3 | The Prometheus security policy, including how to report vulnerabilities, can be 4 | found here: 5 | 6 | 7 | -------------------------------------------------------------------------------- /example.yml: -------------------------------------------------------------------------------- 1 | --- 2 | region: eu-west-1 3 | metrics: 4 | - aws_namespace: AWS/NetworkELB 5 | aws_metric_name: HealthyHostCount 6 | aws_dimensions: [AvailabilityZone, LoadBalancer, TargetGroup] 7 | aws_statistics: [Average] 8 | 9 | - aws_namespace: AWS/NetworkELB 10 | aws_metric_name: UnHealthyHostCount 11 | aws_dimensions: [AvailabilityZone, LoadBalancer, TargetGroup] 12 | aws_statistics: [Average] 13 | 14 | - aws_namespace: AWS/ApplicationELB 15 | aws_metric_name: HealthyHostCount 16 | aws_dimensions: [AvailabilityZone, LoadBalancer, TargetGroup] 17 | aws_statistics: [Average] 18 | 19 | - aws_namespace: AWS/ApplicationELB 20 | aws_metric_name: UnHealthyHostCount 21 | aws_dimensions: [AvailabilityZone, LoadBalancer, TargetGroup] 22 | aws_statistics: [Average] 23 | 24 | - aws_namespace: AWS/ApplicationELB 25 | aws_metric_name: RequestCount 26 | aws_dimensions: [AvailabilityZone, LoadBalancer] 27 | aws_statistics: [Average] 28 | 29 | - aws_namespace: AWS/ElastiCache 30 | aws_metric_name: CPUUtilization 31 | aws_dimensions: [CacheClusterId] 32 | aws_statistics: [Average] 33 | 34 | - aws_namespace: AWS/ElastiCache 35 | aws_metric_name: NetworkBytesIn 36 | aws_dimensions: [CacheClusterId] 37 | aws_statistics: [Average] 38 | 39 | - aws_namespace: AWS/ElastiCache 40 | aws_metric_name: NetworkBytesOut 41 | aws_dimensions: [CacheClusterId] 42 | aws_statistics: [Average] 43 | 44 | - aws_namespace: AWS/ElastiCache 45 | aws_metric_name: FreeableMemory 46 | aws_dimensions: [CacheClusterId] 47 | aws_statistics: [Average] 48 | 49 | - aws_namespace: AWS/ElastiCache 50 | aws_metric_name: BytesUsedForCache 51 | aws_dimensions: [CacheClusterId] 52 | aws_statistics: [Average] 53 | 54 | - aws_namespace: AWS/ElastiCache 55 | aws_metric_name: CurrConnections 56 | aws_dimensions: [CacheClusterId] 57 | aws_statistics: [Average] 58 | 59 | - aws_namespace: AWS/ElastiCache 60 | aws_metric_name: NewConnections 61 | aws_dimensions: [CacheClusterId] 62 | aws_statistics: [Average] 63 | 64 | - aws_namespace: AWS/ElastiCache 65 | aws_metric_name: CacheHits 66 | aws_dimensions: [CacheClusterId] 67 | aws_statistics: [Average] 68 | 69 | - aws_namespace: AWS/ElastiCache 70 | aws_metric_name: CacheMisses 71 | aws_dimensions: [CacheClusterId] 72 | aws_statistics: [Average] 73 | 74 | - aws_namespace: AWS/ElastiCache 75 | aws_metric_name: ReplicationLag 76 | aws_dimensions: [CacheClusterId] 77 | aws_statistics: [Average] 78 | 79 | - aws_namespace: AWS/Redshift 80 | aws_metric_name: DatabaseConnections 81 | aws_dimensions: [ClusterIdentifier] 82 | aws_statistics: [Average] 83 | 84 | - aws_namespace: AWS/Redshift 85 | aws_metric_name: HealthStatus 86 | aws_dimensions: [ClusterIdentifier] 87 | aws_statistics: [Average] 88 | 89 | - aws_namespace: AWS/Redshift 90 | aws_metric_name: MaintenanceMode 91 | aws_dimensions: [ClusterIdentifier] 92 | aws_statistics: [Average] 93 | 94 | - aws_namespace: AWS/Redshift 95 | aws_metric_name: CPUUtilization 96 | aws_dimensions: [NodeID, ClusterIdentifier] 97 | aws_statistics: [Average] 98 | 99 | - aws_namespace: AWS/Redshift 100 | aws_metric_name: PercentageDiskSpaceUsed 101 | aws_dimensions: [NodeID, ClusterIdentifier] 102 | aws_statistics: [Average] 103 | 104 | - aws_namespace: AWS/Redshift 105 | aws_metric_name: NetworkReceiveThroughput 106 | aws_dimensions: [NodeID, ClusterIdentifier] 107 | aws_statistics: [Average] 108 | 109 | - aws_namespace: AWS/Redshift 110 | aws_metric_name: NetworkTransmitThroughput 111 | aws_dimensions: [NodeID, ClusterIdentifier] 112 | aws_statistics: [Average] 113 | 114 | - aws_namespace: AWS/Redshift 115 | aws_metric_name: ReadLatency 116 | aws_dimensions: [NodeID, ClusterIdentifier] 117 | aws_statistics: [Average] 118 | 119 | - aws_namespace: AWS/Redshift 120 | aws_metric_name: ReadThroughput 121 | aws_dimensions: [NodeID, ClusterIdentifier] 122 | aws_statistics: [Average] 123 | 124 | - aws_namespace: AWS/Redshift 125 | aws_metric_name: ReadIOPS 126 | aws_dimensions: [NodeID, ClusterIdentifier] 127 | aws_statistics: [Average] 128 | 129 | - aws_namespace: AWS/Redshift 130 | aws_metric_name: WriteLatency 131 | aws_dimensions: [NodeID, ClusterIdentifier] 132 | aws_statistics: [Average] 133 | 134 | - aws_namespace: AWS/Redshift 135 | aws_metric_name: WriteThroughput 136 | aws_dimensions: [NodeID, ClusterIdentifier] 137 | aws_statistics: [Average] 138 | 139 | - aws_namespace: AWS/Redshift 140 | aws_metric_name: WriteIOPS 141 | aws_dimensions: [NodeID, ClusterIdentifier] 142 | aws_statistics: [Average] 143 | 144 | # S3 Storage metrics are published to Cloudwatch 1x per day with a timestamp of midnight UTC, hence period_seconds: 86400 145 | # Publishing does not always occur at the same time, but it will occur before the next day, hence range_seconds: 172800 146 | - aws_namespace: AWS/S3 147 | aws_metric_name: BucketSizeBytes 148 | aws_dimensions: [BucketName, StorageType] 149 | aws_statistics: [Average] # Valid statistics (https://docs.aws.amazon.com/AmazonS3/latest/dev/cloudwatch-monitoring.html): Average 150 | range_seconds: 172800 151 | period_seconds: 86400 152 | 153 | - aws_namespace: AWS/S3 154 | aws_metric_name: NumberOfObjects 155 | aws_dimensions: [BucketName, StorageType] 156 | aws_statistics: [Average] # Valid statistics (https://docs.aws.amazon.com/AmazonS3/latest/dev/cloudwatch-monitoring.html): Average 157 | range_seconds: 172800 158 | period_seconds: 86400 159 | 160 | # For CloudFront metrics, you have to set the region to us-east-1 161 | - aws_namespace: AWS/CloudFront 162 | aws_metric_name: Requests 163 | aws_statistics: [Sum] 164 | aws_dimensions: [DistributionId, Region] 165 | aws_dimension_select: 166 | Region: [Global] 167 | 168 | - aws_namespace: AWS/CloudFront 169 | aws_metric_name: BytesDownloaded 170 | aws_statistics: [Sum] 171 | aws_dimensions: [DistributionId, Region] 172 | aws_dimension_select: 173 | Region: [Global] 174 | 175 | - aws_namespace: AWS/CloudFront 176 | aws_metric_name: 4xxErrorRate 177 | aws_statistics: [Average] 178 | aws_dimensions: [DistributionId, Region] 179 | aws_dimension_select: 180 | Region: [Global] 181 | 182 | - aws_namespace: AWS/CloudFront 183 | aws_metric_name: 5xxErrorRate 184 | aws_statistics: [Average] 185 | aws_dimensions: [DistributionId, Region] 186 | aws_dimension_select: 187 | Region: [Global] 188 | 189 | - aws_namespace: AWS/CloudFront 190 | aws_metric_name: BytesUploaded 191 | aws_statistics: [Sum] 192 | aws_dimensions: [DistributionId, Region] 193 | aws_dimension_select: 194 | Region: [Global] 195 | 196 | - aws_namespace: AWS/CloudFront 197 | aws_metric_name: TotalErrorRate 198 | aws_statistics: [Average] 199 | aws_dimensions: [DistributionId, Region] 200 | aws_dimension_select: 201 | Region: [Global] 202 | -------------------------------------------------------------------------------- /examples/AmazonMQ.yml: -------------------------------------------------------------------------------- 1 | region: us-east-1 2 | metrics: 3 | - aws_dimensions: 4 | - Broker 5 | aws_metric_name: TotalProducerCount 6 | aws_namespace: AWS/AmazonMQ 7 | aws_statistics: 8 | - Maximum 9 | 10 | - aws_dimensions: 11 | - Broker 12 | aws_metric_name: TotalConsumerCount 13 | aws_namespace: AWS/AmazonMQ 14 | aws_statistics: 15 | - Maximum 16 | - aws_dimensions: 17 | - Broker 18 | aws_metric_name: JournalFilesForFullRecovery 19 | aws_namespace: AWS/AmazonMQ 20 | aws_statistics: 21 | - Maximum 22 | - aws_dimensions: 23 | - Broker 24 | aws_metric_name: JournalFilesForFastRecovery 25 | aws_namespace: AWS/AmazonMQ 26 | aws_statistics: 27 | - Maximum 28 | - aws_dimensions: 29 | - Broker 30 | aws_metric_name: HeapUsage 31 | aws_namespace: AWS/AmazonMQ 32 | aws_statistics: 33 | - Maximum 34 | - aws_dimensions: 35 | - Broker 36 | aws_metric_name: CpuUtilization 37 | aws_namespace: AWS/AmazonMQ 38 | aws_statistics: 39 | - Maximum 40 | - aws_dimensions: 41 | - Broker 42 | aws_metric_name: TotalConsumerCount 43 | aws_namespace: AWS/AmazonMQ 44 | aws_statistics: 45 | - SampleCount 46 | - aws_dimensions: 47 | - Broker 48 | aws_metric_name: StorePercentUsage 49 | aws_namespace: AWS/AmazonMQ 50 | aws_statistics: 51 | - Maximum 52 | - aws_dimensions: 53 | - Broker 54 | aws_metric_name: NetworkIn 55 | aws_namespace: AWS/AmazonMQ 56 | aws_statistics: 57 | - Maximum 58 | - aws_dimensions: 59 | - Broker 60 | aws_metric_name: NetworkOut 61 | aws_namespace: AWS/AmazonMQ 62 | aws_statistics: 63 | - Maximum 64 | - aws_dimensions: 65 | - Queue 66 | aws_metric_name: QueueSize 67 | aws_namespace: AWS/AmazonMQ 68 | aws_statistics: 69 | - Maximum 70 | - aws_dimensions: 71 | - Broker 72 | - Topic 73 | - Queue 74 | aws_metric_name: ConsumerCount 75 | aws_namespace: AWS/AmazonMQ 76 | aws_statistics: 77 | - Maximum 78 | - aws_dimensions: 79 | - Broker 80 | - Topic 81 | - Queue 82 | aws_metric_name: DispatchCount 83 | aws_namespace: AWS/AmazonMQ 84 | aws_statistics: 85 | - Maximum 86 | - aws_dimensions: 87 | - Broker 88 | - Topic 89 | - Queue 90 | aws_metric_name: ProducerCount 91 | aws_namespace: AWS/AmazonMQ 92 | aws_statistics: 93 | - Maximum 94 | - aws_dimensions: 95 | - Broker 96 | - Topic 97 | aws_metric_name: ReceiveCount 98 | aws_namespace: AWS/AmazonMQ 99 | aws_statistics: 100 | - Maximum 101 | - aws_dimensions: 102 | - Broker 103 | - Topic 104 | - Queue 105 | aws_metric_name: EnqueueCount 106 | aws_namespace: AWS/AmazonMQ 107 | aws_statistics: 108 | - Maximum 109 | - aws_dimensions: 110 | - Broker 111 | - Topic 112 | - Queue 113 | aws_metric_name: DequeueCount 114 | aws_namespace: AWS/AmazonMQ 115 | aws_statistics: 116 | - Maximum 117 | - aws_dimensions: 118 | - Broker 119 | - Topic 120 | - Queue 121 | aws_metric_name: ExpiredCount 122 | aws_namespace: AWS/AmazonMQ 123 | aws_statistics: 124 | - Maximum 125 | - aws_dimensions: 126 | - Broker 127 | - Topic 128 | - Queue 129 | aws_metric_name: EnqueueTime 130 | aws_namespace: AWS/AmazonMQ 131 | aws_statistics: 132 | - Maximum 133 | - aws_dimensions: 134 | - Broker 135 | - Topic 136 | aws_metric_name: MemoryUsage 137 | aws_namespace: AWS/AmazonMQ 138 | aws_statistics: 139 | - Maximum 140 | -------------------------------------------------------------------------------- /examples/ApiGateway.yml: -------------------------------------------------------------------------------- 1 | region: us-east-1 2 | metrics: 3 | - aws_dimensions: 4 | - Stage 5 | - ApiName 6 | aws_metric_name: Count 7 | aws_namespace: AWS/ApiGateway 8 | aws_statistics: 9 | - SampleCount 10 | - aws_dimensions: 11 | - Stage 12 | - ApiName 13 | aws_metric_name: Latency 14 | aws_namespace: AWS/ApiGateway 15 | aws_statistics: 16 | - Average 17 | - aws_dimensions: 18 | - Stage 19 | - ApiName 20 | aws_metric_name: IntegrationLatency 21 | aws_namespace: AWS/ApiGateway 22 | aws_statistics: 23 | - Average 24 | - aws_dimensions: 25 | - Stage 26 | - ApiName 27 | aws_metric_name: 4XXError 28 | aws_namespace: AWS/ApiGateway 29 | aws_statistics: 30 | - Sum 31 | - aws_dimensions: 32 | - Stage 33 | - ApiName 34 | aws_metric_name: 5XXError 35 | aws_namespace: AWS/ApiGateway 36 | aws_statistics: 37 | - Sum 38 | - aws_dimensions: 39 | - Stage 40 | - ApiName 41 | aws_metric_name: CacheHitCount 42 | aws_namespace: AWS/ApiGateway 43 | aws_statistics: 44 | - Sum 45 | - aws_dimensions: 46 | - Stage 47 | - ApiName 48 | aws_metric_name: CacheMissCount 49 | aws_namespace: AWS/ApiGateway 50 | aws_statistics: 51 | - Sum 52 | -------------------------------------------------------------------------------- /examples/AppRunner.yml: -------------------------------------------------------------------------------- 1 | region: us-east-1 2 | metrics: 3 | - aws_namespace: AWS/AppRunner 4 | aws_metric_name: Requests 5 | aws_dimensions: [ServiceID, ServiceName] 6 | aws_statistics: [Sum] 7 | - aws_namespace: AWS/AppRunner 8 | aws_metric_name: 2xxStatusResponses 9 | aws_dimensions: [ServiceID, ServiceName] 10 | aws_statistics: [Sum] 11 | - aws_namespace: AWS/AppRunner 12 | aws_metric_name: 4xxStatusResponses 13 | aws_dimensions: [ServiceID, ServiceName] 14 | aws_statistics: [Sum] 15 | - aws_namespace: AWS/AppRunner 16 | aws_metric_name: 5xxStatusResponses 17 | aws_dimensions: [ServiceID, ServiceName] 18 | aws_statistics: [Sum] 19 | - aws_namespace: AWS/AppRunner 20 | aws_metric_name: ActiveConnections 21 | aws_dimensions: [ServiceID, ServiceName] 22 | aws_statistics: [Sum] 23 | - aws_namespace: AWS/AppRunner 24 | aws_metric_name: DroppedConnections 25 | aws_dimensions: [ServiceID, ServiceName] 26 | aws_statistics: [Sum] 27 | - aws_namespace: AWS/AppRunner 28 | aws_metric_name: RequestLatency 29 | aws_dimensions: [ServiceID, ServiceName] 30 | aws_statistics: [Average] 31 | - aws_namespace: AWS/AppRunner 32 | aws_metric_name: ActiveInstances 33 | aws_dimensions: [ServiceID, ServiceName] 34 | aws_statistics: [Average] 35 | - aws_namespace: AWS/AppRunner 36 | aws_metric_name: ProvisionedInstances 37 | aws_dimensions: [ServiceID, ServiceName] 38 | aws_statistics: [Average] 39 | - aws_namespace: AWS/AppRunner 40 | aws_metric_name: CPUUtilization 41 | aws_dimensions: [ServiceID, ServiceName] 42 | aws_statistics: [Average] 43 | - aws_namespace: AWS/AppRunner 44 | aws_metric_name: MemoryUtilization 45 | aws_dimensions: [ServiceID, ServiceName] 46 | aws_statistics: [Average] 47 | -------------------------------------------------------------------------------- /examples/ApplicationELB.yml: -------------------------------------------------------------------------------- 1 | region: us-east-1 2 | metrics: 3 | - aws_namespace: AWS/ApplicationELB 4 | aws_metric_name: HealthyHostCount 5 | aws_dimensions: 6 | - LoadBalancer 7 | - TargetGroup 8 | aws_statistics: 9 | - Minimum 10 | # In case you want to use some tag to select target group to monitor, or to have additional `info` metric 11 | # with all target group tags as labels, use `aws_tag_select`. 12 | # Since the TargetGroup dimension doesn't follow the convention for how to extract resource ids from ARN 13 | # `arn_resource_id_regexp` is specified with an alternative regular expression. 14 | aws_tag_select: 15 | resource_type_selection: elasticloadbalancing:targetgroup 16 | resource_id_dimension: TargetGroup 17 | arn_resource_id_regexp: "(targetgroup/.*)$" 18 | tag_selections: 19 | Environment: 20 | - production 21 | - aws_namespace: AWS/ApplicationELB 22 | aws_metric_name: UnHealthyHostCount 23 | aws_dimensions: 24 | - LoadBalancer 25 | aws_statistics: 26 | - Sum 27 | - aws_namespace: AWS/ApplicationELB 28 | aws_metric_name: RequestCount 29 | aws_dimensions: 30 | - LoadBalancer 31 | aws_statistics: 32 | - Average 33 | - aws_namespace: AWS/ApplicationELB 34 | aws_metric_name: TargetResponseTime 35 | aws_dimensions: 36 | - LoadBalancer 37 | aws_statistics: 38 | - Average 39 | - aws_namespace: AWS/ApplicationELB 40 | aws_metric_name: ActiveConnectionCount 41 | aws_dimensions: 42 | - LoadBalancer 43 | aws_statistics: 44 | - Sum 45 | - aws_namespace: AWS/ApplicationELB 46 | aws_metric_name: NewConnectionCount 47 | aws_dimensions: 48 | - LoadBalancer 49 | aws_statistics: 50 | - Sum 51 | - aws_namespace: AWS/ApplicationELB 52 | aws_metric_name: RejectedConnectionCount 53 | aws_dimensions: 54 | - LoadBalancer 55 | aws_statistics: 56 | - Sum 57 | - aws_namespace: AWS/ApplicationELB 58 | aws_metric_name: TargetConnectionErrorCount 59 | aws_dimensions: 60 | - LoadBalancer 61 | aws_statistics: 62 | - Sum 63 | - aws_namespace: AWS/ApplicationELB 64 | aws_metric_name: RequestCount 65 | aws_dimensions: 66 | - LoadBalancer 67 | aws_statistics: 68 | - Sum 69 | - aws_namespace: AWS/ApplicationELB 70 | aws_metric_name: IPv6RequestCount 71 | aws_dimensions: 72 | - LoadBalancer 73 | aws_statistics: 74 | - Sum 75 | - aws_namespace: AWS/ApplicationELB 76 | aws_metric_name: RequestCountPerTarget 77 | aws_dimensions: 78 | - LoadBalancer 79 | aws_statistics: 80 | - Sum 81 | - aws_namespace: AWS/ApplicationELB 82 | aws_metric_name: NonStickyRequestCount 83 | aws_dimensions: 84 | - LoadBalancer 85 | aws_statistics: 86 | - Sum 87 | - aws_namespace: AWS/ApplicationELB 88 | aws_metric_name: HTTPCode_Target_2XX_Count 89 | aws_dimensions: 90 | - LoadBalancer 91 | aws_statistics: 92 | - Sum 93 | - aws_namespace: AWS/ApplicationELB 94 | aws_metric_name: HTTPCode_Target_3XX_Count 95 | aws_dimensions: 96 | - LoadBalancer 97 | aws_statistics: 98 | - Sum 99 | - aws_namespace: AWS/ApplicationELB 100 | aws_metric_name: HTTPCode_Target_4XX_Count 101 | aws_dimensions: 102 | - LoadBalancer 103 | aws_statistics: 104 | - Sum 105 | - aws_namespace: AWS/ApplicationELB 106 | aws_metric_name: HTTPCode_Target_5XX_Count 107 | aws_dimensions: 108 | - LoadBalancer 109 | aws_statistics: 110 | - Sum 111 | - aws_namespace: AWS/ApplicationELB 112 | aws_metric_name: HTTPCode_ELB_3XX_Count 113 | aws_dimensions: 114 | - LoadBalancer 115 | aws_statistics: 116 | - Sum 117 | - aws_namespace: AWS/ApplicationELB 118 | aws_metric_name: HTTPCode_ELB_4XX_Count 119 | aws_dimensions: 120 | - LoadBalancer 121 | aws_statistics: 122 | - Sum 123 | - aws_namespace: AWS/ApplicationELB 124 | aws_metric_name: HTTPCode_ELB_5XX_Count 125 | aws_dimensions: 126 | - LoadBalancer 127 | aws_statistics: 128 | - Sum 129 | - aws_namespace: AWS/ApplicationELB 130 | aws_metric_name: ProcessedBytes 131 | aws_dimensions: 132 | - LoadBalancer 133 | aws_statistics: 134 | - Sum 135 | - aws_namespace: AWS/ApplicationELB 136 | aws_metric_name: IPv6ProcessedBytes 137 | aws_dimensions: 138 | - LoadBalancer 139 | aws_statistics: 140 | - Sum 141 | - aws_namespace: AWS/ApplicationELB 142 | aws_metric_name: ConsumedLCUs 143 | # ALBs take 30 minutes to report this metrics. 144 | delay_seconds: 1800 145 | aws_dimensions: 146 | - LoadBalancer 147 | aws_statistics: 148 | - Sum 149 | - aws_namespace: AWS/ApplicationELB 150 | aws_metric_name: ClientTLSNegotiationErrorCount 151 | aws_dimensions: 152 | - LoadBalancer 153 | aws_statistics: 154 | - Sum 155 | - aws_namespace: AWS/ApplicationELB 156 | aws_metric_name: TargetTLSNegotiationErrorCount 157 | aws_dimensions: 158 | - LoadBalancer 159 | aws_statistics: 160 | - Sum 161 | - aws_namespace: AWS/ApplicationELB 162 | aws_metric_name: RuleEvaluations 163 | aws_dimensions: 164 | - LoadBalancer 165 | aws_statistics: 166 | - Sum 167 | -------------------------------------------------------------------------------- /examples/Athena.yml: -------------------------------------------------------------------------------- 1 | region: us-east-1 2 | metrics: 3 | - aws_dimensions: 4 | - QueryState 5 | - QueryType 6 | aws_metric_name: ProcessedBytes 7 | aws_namespace: AWS/Athena 8 | aws_statistics: 9 | - Maximum 10 | - aws_dimensions: 11 | - QueryState 12 | - QueryType 13 | aws_metric_name: TotalExecutionTime 14 | aws_namespace: AWS/Athena 15 | aws_statistics: 16 | - Maximum 17 | - aws_dimensions: 18 | - QueryType 19 | - QueryState 20 | aws_metric_name: Total 21 | aws_namespace: AWS/Athena 22 | -------------------------------------------------------------------------------- /examples/AuroraServerless.yml: -------------------------------------------------------------------------------- 1 | region: us-east-1 2 | metrics: 3 | - aws_dimensions: 4 | - DBInstanceIdentifier 5 | aws_metric_name: BufferCacheHitRatio 6 | aws_namespace: AWS/RDS 7 | aws_statistics: 8 | - Average 9 | - aws_dimensions: 10 | - DBInstanceIdentifier 11 | aws_metric_name: CommitLatency 12 | aws_namespace: AWS/RDS 13 | aws_statistics: 14 | - Average 15 | - aws_dimensions: 16 | - DBInstanceIdentifier 17 | aws_metric_name: CommitThroughput 18 | aws_namespace: AWS/RDS 19 | aws_statistics: 20 | - Average 21 | - aws_dimensions: 22 | - DBInstanceIdentifier 23 | aws_metric_name: CPUUtilization 24 | aws_namespace: AWS/RDS 25 | aws_statistics: 26 | - Average 27 | - aws_dimensions: 28 | - DBInstanceIdentifier 29 | aws_metric_name: DatabaseConnections 30 | aws_namespace: AWS/RDS 31 | aws_statistics: 32 | - Sum 33 | - aws_dimensions: 34 | - DBInstanceIdentifier 35 | aws_metric_name: DBLoad 36 | aws_namespace: AWS/RDS 37 | aws_statistics: 38 | - Sum 39 | - aws_dimensions: 40 | - DBInstanceIdentifier 41 | aws_metric_name: DBLoadCPU 42 | aws_namespace: AWS/RDS 43 | aws_statistics: 44 | - Sum 45 | - aws_dimensions: 46 | - DBInstanceIdentifier 47 | aws_metric_name: DBLoadNonCPU 48 | aws_namespace: AWS/RDS 49 | aws_statistics: 50 | - Sum 51 | - aws_dimensions: 52 | - DBInstanceIdentifier 53 | aws_metric_name: Deadlocks 54 | aws_namespace: AWS/RDS 55 | aws_statistics: 56 | - Sum 57 | - aws_dimensions: 58 | - DBInstanceIdentifier 59 | aws_metric_name: DiskQueueDepth 60 | aws_namespace: AWS/RDS 61 | aws_statistics: 62 | - Average 63 | - aws_dimensions: 64 | - DBInstanceIdentifier 65 | aws_metric_name: FreeableMemory 66 | aws_namespace: AWS/RDS 67 | aws_statistics: 68 | - Average 69 | - aws_dimensions: 70 | - DBInstanceIdentifier 71 | aws_metric_name: ReadIOPS 72 | aws_namespace: AWS/RDS 73 | aws_statistics: 74 | - Average 75 | - aws_dimensions: 76 | - DBInstanceIdentifier 77 | aws_metric_name: ReadLatency 78 | aws_namespace: AWS/RDS 79 | aws_statistics: 80 | - Average 81 | - aws_dimensions: 82 | - DBInstanceIdentifier 83 | aws_metric_name: ReadThroughput 84 | aws_namespace: AWS/RDS 85 | aws_statistics: 86 | - Average 87 | - aws_dimensions: 88 | - DBInstanceIdentifier 89 | aws_metric_name: SwapUsage 90 | aws_namespace: AWS/RDS 91 | aws_statistics: 92 | - Average 93 | - aws_dimensions: 94 | - DBInstanceIdentifier 95 | aws_metric_name: WriteIOPS 96 | aws_namespace: AWS/RDS 97 | aws_statistics: 98 | - Average 99 | - aws_dimensions: 100 | - DBInstanceIdentifier 101 | aws_metric_name: WriteLatency 102 | aws_namespace: AWS/RDS 103 | aws_statistics: 104 | - Average 105 | - aws_dimensions: 106 | - DBInstanceIdentifier 107 | aws_metric_name: WriteThroughput 108 | aws_namespace: AWS/RDS 109 | aws_statistics: 110 | - Average 111 | 112 | 113 | - aws_dimensions: 114 | - DBClusterIdentifier 115 | aws_metric_name: ACUUtilization 116 | aws_namespace: AWS/RDS 117 | aws_statistics: 118 | - Average 119 | - aws_dimensions: 120 | - DBClusterIdentifier 121 | aws_metric_name: CPUUtilization 122 | aws_namespace: AWS/RDS 123 | aws_statistics: 124 | - Maximum 125 | - aws_dimensions: 126 | - DBClusterIdentifier 127 | aws_metric_name: FreeableMemory 128 | aws_namespace: AWS/RDS 129 | aws_statistics: 130 | - Sum 131 | - aws_dimensions: 132 | - DBClusterIdentifier 133 | aws_metric_name: FreeLocalStorage 134 | aws_namespace: AWS/RDS 135 | aws_statistics: 136 | - Minimum 137 | - aws_dimensions: 138 | - DBClusterIdentifier 139 | aws_metric_name: ServerlessDatabaseCapacity 140 | aws_namespace: AWS/RDS 141 | aws_statistics: 142 | - Average 143 | - aws_dimensions: 144 | - DBClusterIdentifier 145 | aws_metric_name: TempStorageIops 146 | aws_namespace: AWS/RDS 147 | aws_statistics: 148 | - Average 149 | - aws_dimensions: 150 | - DBClusterIdentifier 151 | aws_metric_name: TempStorageThroughput 152 | aws_namespace: AWS/RDS 153 | aws_statistics: 154 | - Sum 155 | - aws_dimensions: 156 | - DBClusterIdentifier 157 | aws_metric_name: VolumeBytesUsed 158 | aws_namespace: AWS/RDS 159 | aws_statistics: 160 | - Average 161 | - aws_dimensions: 162 | - DBClusterIdentifier 163 | aws_metric_name: VolumeReadIOPs 164 | aws_namespace: AWS/RDS 165 | aws_statistics: 166 | - Average 167 | - aws_dimensions: 168 | - DBClusterIdentifier 169 | aws_metric_name: VolumeWriteIOPs 170 | aws_namespace: AWS/RDS 171 | aws_statistics: 172 | - Average 173 | -------------------------------------------------------------------------------- /examples/AutoScaling.yml: -------------------------------------------------------------------------------- 1 | region: us-east-1 2 | metrics: 3 | - aws_dimensions: 4 | - AutoScalingGroupName 5 | aws_metric_name: GroupTotalInstances 6 | aws_namespace: AWS/AutoScaling 7 | aws_statistics: 8 | - Average 9 | - aws_dimensions: 10 | - AutoScalingGroupName 11 | aws_metric_name: GroupMaxSize 12 | aws_namespace: AWS/AutoScaling 13 | aws_statistics: 14 | - Average 15 | - aws_dimensions: 16 | - AutoScalingGroupName 17 | aws_metric_name: GroupMinSize 18 | aws_namespace: AWS/AutoScaling 19 | aws_statistics: 20 | - Average 21 | - aws_dimensions: 22 | - AutoScalingGroupName 23 | aws_metric_name: GroupTerminatingInstances 24 | aws_namespace: AWS/AutoScaling 25 | aws_statistics: 26 | - Average 27 | - aws_dimensions: 28 | - AutoScalingGroupName 29 | aws_metric_name: GroupPendingInstances 30 | aws_namespace: AWS/AutoScaling 31 | aws_statistics: 32 | - Average 33 | - aws_dimensions: 34 | - AutoScalingGroupName 35 | aws_metric_name: GroupStandbyInstances 36 | aws_namespace: AWS/AutoScaling 37 | aws_statistics: 38 | - Average 39 | - aws_dimensions: 40 | - AutoScalingGroupName 41 | aws_metric_name: GroupDesiredCapacity 42 | aws_namespace: AWS/AutoScaling 43 | aws_statistics: 44 | - Average 45 | - aws_dimensions: 46 | - AutoScalingGroupName 47 | aws_metric_name: GroupInServiceInstances 48 | aws_namespace: AWS/AutoScaling 49 | aws_statistics: 50 | - Average 51 | -------------------------------------------------------------------------------- /examples/Backup.yml: -------------------------------------------------------------------------------- 1 | region: us-east-1 2 | metrics: 3 | - aws_dimensions: 4 | - BackupVaultName 5 | aws_metric_name: NumberOfBackupJobsCreated 6 | aws_namespace: AWS/Backup 7 | aws_statistics: 8 | - Sum 9 | - aws_dimensions: 10 | - BackupVaultName 11 | aws_metric_name: NumberOfBackupJobsFailed 12 | aws_namespace: AWS/Backup 13 | aws_statistics: 14 | - Sum 15 | - aws_dimensions: 16 | - BackupVaultName 17 | aws_metric_name: NumberOfBackupJobsCompleted 18 | aws_namespace: AWS/Backup 19 | aws_statistics: 20 | - Sum 21 | - aws_dimensions: 22 | - BackupVaultName 23 | aws_metric_name: NumberOfCopyJobsCreated 24 | aws_namespace: AWS/Backup 25 | aws_statistics: 26 | - Sum 27 | - aws_dimensions: 28 | - BackupVaultName 29 | aws_metric_name: NumberOfCopyJobsFailed 30 | aws_namespace: AWS/Backup 31 | aws_statistics: 32 | - Sum 33 | - aws_dimensions: 34 | - BackupVaultName 35 | aws_metric_name: NumberOfCopyJobsCompleted 36 | aws_namespace: AWS/Backup 37 | aws_statistics: 38 | - Sum -------------------------------------------------------------------------------- /examples/CloudFront.yml: -------------------------------------------------------------------------------- 1 | region: us-east-1 2 | metrics: 3 | - aws_dimensions: 4 | - DistributionId 5 | - Region 6 | aws_metric_name: Requests 7 | aws_namespace: AWS/CloudFront 8 | aws_statistics: 9 | - Sum 10 | - aws_dimensions: 11 | - DistributionId 12 | - Region 13 | aws_metric_name: BytesDownloaded 14 | aws_namespace: AWS/CloudFront 15 | aws_statistics: 16 | - Sum 17 | - aws_dimensions: 18 | - DistributionId 19 | - Region 20 | aws_metric_name: BytesUploaded 21 | aws_namespace: AWS/CloudFront 22 | aws_statistics: 23 | - Sum 24 | - aws_dimensions: 25 | - DistributionId 26 | - Region 27 | aws_metric_name: 4xxErrorRate 28 | aws_namespace: AWS/CloudFront 29 | aws_statistics: 30 | - Sum 31 | - aws_dimensions: 32 | - DistributionId 33 | - Region 34 | aws_metric_name: 5xxErrorRate 35 | aws_namespace: AWS/CloudFront 36 | aws_statistics: 37 | - Sum 38 | - aws_dimensions: 39 | - DistributionId 40 | - Region 41 | aws_metric_name: TotalErrorRate 42 | aws_namespace: AWS/CloudFront 43 | aws_statistics: 44 | - Sum 45 | -------------------------------------------------------------------------------- /examples/DDoSProtection.yml: -------------------------------------------------------------------------------- 1 | region: us-east-1 2 | metrics: 3 | - aws_dimensions: 4 | aws_metric_name: DDoSDetected 5 | aws_namespace: AWS/DDoSProtection 6 | aws_statistics: 7 | - Sum 8 | - aws_dimensions: 9 | - ACKFlood 10 | - ChargenReflection 11 | - DNSReflection 12 | - GenericUDPReflection 13 | - MemcachedReflection 14 | - MSSQLReflection 15 | - NetBIOSReflection 16 | - NTPReflection 17 | - PortMapper 18 | - RequestFlood 19 | - RIPReflection 20 | - SNMPReflection 21 | - SSDPReflection 22 | - SYNFlood 23 | - UDPFragment 24 | - UDPTraffic 25 | - UDPReflection 26 | aws_metric_name: DDoSAttackBitsPerSecond 27 | aws_namespace: AWS/DDoSProtection 28 | aws_statistics: 29 | - Sum 30 | - aws_dimensions: 31 | - ACKFlood 32 | - ChargenReflection 33 | - DNSReflection 34 | - GenericUDPReflection 35 | - MemcachedReflection 36 | - MSSQLReflection 37 | - NetBIOSReflection 38 | - NTPReflection 39 | - PortMapper 40 | - RequestFlood 41 | - RIPReflection 42 | - SNMPReflection 43 | - SSDPReflection 44 | - SYNFlood 45 | - UDPFragment 46 | - UDPTraffic 47 | - UDPReflection 48 | aws_metric_name: DDoSAttackPacketsPerSecond 49 | aws_namespace: AWS/DDoSProtection 50 | aws_statistics: 51 | - Sum 52 | - aws_dimensions: 53 | - ACKFlood 54 | - ChargenReflection 55 | - DNSReflection 56 | - GenericUDPReflection 57 | - MemcachedReflection 58 | - MSSQLReflection 59 | - NetBIOSReflection 60 | - NTPReflection 61 | - PortMapper 62 | - RequestFlood 63 | - RIPReflection 64 | - SNMPReflection 65 | - SSDPReflection 66 | - SYNFlood 67 | - UDPFragment 68 | - UDPTraffic 69 | - UDPReflection 70 | aws_metric_name: DDoSAttackRequestsPerSecond 71 | aws_namespace: AWS/DDoSProtection 72 | aws_statistics: 73 | - Sum 74 | - aws_dimensions: 75 | - ResourceArn 76 | - MitigationAction 77 | aws_metric_name: VolumePacketsPerSecond 78 | aws_namespace: AWS/DDoSProtection 79 | aws_statistics: 80 | - Sum 81 | - aws_dimensions: 82 | - ResourceArn 83 | - Protocol 84 | - SourceIp 85 | aws_metric_name: VolumePacketsPerSecond 86 | aws_namespace: AWS/DDoSProtection 87 | aws_statistics: 88 | - Sum 89 | - aws_dimensions: 90 | - ResourceArn 91 | - Protocol 92 | - SourceIp 93 | aws_metric_name: VolumeBitsPerSecond 94 | aws_namespace: AWS/DDoSProtection 95 | aws_statistics: 96 | - Sum 97 | -------------------------------------------------------------------------------- /examples/DMS.yml: -------------------------------------------------------------------------------- 1 | region: us-east-1 2 | metrics: 3 | - aws_dimensions: 4 | - ReplicationInstanceIdentifier 5 | aws_metric_name: ReadLatency 6 | aws_namespace: AWS/DMS 7 | aws_statistics: 8 | - Average 9 | - aws_dimensions: 10 | - ReplicationInstanceIdentifier 11 | aws_metric_name: WriteLatency 12 | aws_namespace: AWS/DMS 13 | aws_statistics: 14 | - Average 15 | - aws_dimensions: 16 | - ReplicationInstanceIdentifier 17 | aws_metric_name: ReadThroughput 18 | aws_namespace: AWS/DMS 19 | aws_statistics: 20 | - Average 21 | - aws_dimensions: 22 | - ReplicationInstanceIdentifier 23 | aws_metric_name: WriteThroughput 24 | aws_namespace: AWS/DMS 25 | aws_statistics: 26 | - Average 27 | - aws_dimensions: 28 | - ReplicationInstanceIdentifier 29 | aws_metric_name: CPUUtilization 30 | aws_namespace: AWS/DMS 31 | aws_statistics: 32 | - Average 33 | - aws_dimensions: 34 | - ReplicationInstanceIdentifier 35 | aws_metric_name: AvailableMemory 36 | aws_namespace: AWS/DMS 37 | aws_statistics: 38 | - Average 39 | -------------------------------------------------------------------------------- /examples/DocumentDB.yml: -------------------------------------------------------------------------------- 1 | --- 2 | region: us-east-1 3 | metrics: 4 | - aws_dimensions: 5 | - DBInstanceIdentifier 6 | aws_metric_name: CPUUtilization 7 | aws_namespace: AWS/DocDB 8 | aws_statistics: 9 | - Average 10 | - aws_dimensions: 11 | - DBInstanceIdentifier 12 | aws_metric_name: DatabaseConnections 13 | aws_namespace: AWS/DocDB 14 | aws_statistics: 15 | - Maximum 16 | - aws_dimensions: 17 | - DBInstanceIdentifier 18 | aws_metric_name: FreeableMemory 19 | aws_namespace: AWS/DocDB 20 | aws_statistics: 21 | - Average 22 | - aws_dimensions: 23 | - DBInstanceIdentifier 24 | aws_metric_name: WriteIOPS 25 | aws_namespace: AWS/DocDB 26 | aws_statistics: 27 | - Sum 28 | - aws_dimensions: 29 | - DBInstanceIdentifier 30 | aws_metric_name: ReadIOPS 31 | aws_namespace: AWS/DocDB 32 | aws_statistics: 33 | - Sum 34 | - aws_dimensions: 35 | - DBInstanceIdentifier 36 | aws_metric_name: WriteLatency 37 | aws_namespace: AWS/DocDB 38 | aws_statistics: 39 | - Average 40 | - aws_dimensions: 41 | - DBInstanceIdentifier 42 | aws_metric_name: ReadLatency 43 | aws_namespace: AWS/DocDB 44 | aws_statistics: 45 | - Average 46 | - aws_dimensions: 47 | - DBInstanceIdentifier 48 | aws_metric_name: ReadThroughput 49 | aws_namespace: AWS/DocDB 50 | aws_statistics: 51 | - Average 52 | - aws_dimensions: 53 | - DBInstanceIdentifier 54 | aws_metric_name: WriteThroughput 55 | aws_namespace: AWS/DocDB 56 | aws_statistics: 57 | - Average 58 | - aws_dimensions: 59 | - DBInstanceIdentifier 60 | aws_metric_name: FreeLocalStorage 61 | aws_namespace: AWS/DocDB 62 | aws_statistics: 63 | - Average 64 | - aws_dimensions: 65 | - DBInstanceIdentifier 66 | aws_metric_name: VolumeBytesUsed 67 | aws_namespace: AWS/DocDB 68 | aws_statistics: 69 | - Average 70 | - aws_dimensions: 71 | - DBInstanceIdentifier 72 | aws_metric_name: DiskQueueDepth 73 | aws_namespace: AWS/DocDB 74 | aws_statistics: 75 | - Average 76 | - aws_dimensions: 77 | - DBInstanceIdentifier 78 | aws_metric_name: NetworkTransmitThroughput 79 | aws_namespace: AWS/DocDB 80 | aws_statistics: 81 | - Average 82 | - aws_dimensions: 83 | - DBInstanceIdentifier 84 | aws_metric_name: NetworkReceiveThroughput 85 | aws_namespace: AWS/DocDB 86 | aws_statistics: 87 | - Average 88 | - aws_dimensions: 89 | - DBInstanceIdentifier 90 | aws_metric_name: DatabaseCursors 91 | aws_namespace: AWS/DocDB 92 | aws_statistics: 93 | - Average 94 | - aws_dimensions: 95 | - DBInstanceIdentifier 96 | aws_metric_name: DatabaseCursorsMax 97 | aws_namespace: AWS/DocDB 98 | aws_statistics: 99 | - Average 100 | - aws_dimensions: 101 | - DBInstanceIdentifier 102 | aws_metric_name: DatabaseCursorsTimedOut 103 | aws_namespace: AWS/DocDB 104 | aws_statistics: 105 | - Average 106 | - aws_dimensions: 107 | - DBInstanceIdentifier 108 | aws_metric_name: BufferCacheHitRatio 109 | aws_namespace: AWS/DocDB 110 | aws_statistics: 111 | - Average 112 | - aws_dimensions: 113 | - DBInstanceIdentifier 114 | aws_metric_name: IndexBufferCacheHitRatio 115 | aws_namespace: AWS/DocDB 116 | aws_statistics: 117 | - Average 118 | - aws_dimensions: 119 | - DBInstanceIdentifier 120 | aws_metric_name: CPUCreditBalance 121 | aws_namespace: AWS/DocDB 122 | aws_statistics: 123 | - Average 124 | - aws_dimensions: 125 | - DBInstanceIdentifier 126 | aws_metric_name: CPUCreditUsage 127 | aws_namespace: AWS/DocDB 128 | aws_statistics: 129 | - Average 130 | - aws_dimensions: 131 | - DBInstanceIdentifier 132 | aws_metric_name: OpcountersDelete 133 | aws_namespace: AWS/DocDB 134 | aws_statistics: 135 | - Average 136 | - aws_dimensions: 137 | - DBInstanceIdentifier 138 | aws_metric_name: OpcountersCommand 139 | aws_namespace: AWS/DocDB 140 | aws_statistics: 141 | - Average 142 | - aws_dimensions: 143 | - DBInstanceIdentifier 144 | aws_metric_name: OpcountersGetmore 145 | aws_namespace: AWS/DocDB 146 | aws_statistics: 147 | - Average 148 | - aws_dimensions: 149 | - DBInstanceIdentifier 150 | aws_metric_name: OpcountersQuery 151 | aws_namespace: AWS/DocDB 152 | aws_statistics: 153 | - Average 154 | - aws_dimensions: 155 | - DBInstanceIdentifier 156 | aws_metric_name: OpcountersUpdate 157 | aws_namespace: AWS/DocDB 158 | aws_statistics: 159 | - Average 160 | - aws_dimensions: 161 | - DBInstanceIdentifier 162 | aws_metric_name: DBInstanceReplicaLag 163 | aws_namespace: AWS/DocDB 164 | aws_statistics: 165 | - Average 166 | - aws_dimensions: 167 | - DBInstanceIdentifier 168 | aws_metric_name: DBClusterReplicaLagMaximum 169 | aws_namespace: AWS/DocDB 170 | aws_statistics: 171 | - Average -------------------------------------------------------------------------------- /examples/DynamoDB.yml: -------------------------------------------------------------------------------- 1 | region: us-east-1 2 | metrics: 3 | - aws_dimensions: 4 | - TableName 5 | - GlobalSecondaryIndexName 6 | aws_metric_name: ConsumedReadCapacityUnits 7 | aws_namespace: AWS/DynamoDB 8 | aws_statistics: 9 | - Maximum 10 | - aws_dimensions: 11 | - TableName 12 | - GlobalSecondaryIndexName 13 | aws_metric_name: ConsumedWriteCapacityUnits 14 | aws_namespace: AWS/DynamoDB 15 | aws_statistics: 16 | - Maximum 17 | - aws_dimensions: 18 | - TableName 19 | - Operation 20 | aws_metric_name: ThrottledRequests 21 | aws_namespace: AWS/DynamoDB 22 | aws_statistics: 23 | - Sum 24 | - aws_dimensions: 25 | - TableName 26 | - Operation 27 | aws_metric_name: SystemErrors 28 | aws_namespace: AWS/DynamoDB 29 | aws_statistics: 30 | - Sum 31 | - aws_dimensions: 32 | - TableName 33 | - Operation 34 | aws_metric_name: SuccessfulRequestLatency 35 | aws_namespace: AWS/DynamoDB 36 | aws_statistics: 37 | - Maximum 38 | - aws_dimensions: 39 | - TableName 40 | - GlobalSecondaryIndexName 41 | aws_metric_name: WriteThrottleEvents 42 | aws_namespace: AWS/DynamoDB 43 | aws_statistics: 44 | - Sum 45 | - aws_dimensions: 46 | - TableName 47 | - GlobalSecondaryIndexName 48 | aws_metric_name: ReadThrottleEvents 49 | aws_namespace: AWS/DynamoDB 50 | aws_statistics: 51 | - Sum 52 | -------------------------------------------------------------------------------- /examples/EBS.yml: -------------------------------------------------------------------------------- 1 | region: us-east-1 2 | metrics: 3 | - aws_dimensions: 4 | - VolumeId 5 | aws_metric_name: VolumeWriteBytes 6 | aws_namespace: AWS/EBS 7 | aws_statistics: 8 | - Maximum 9 | - Average 10 | - aws_dimensions: 11 | - VolumeId 12 | aws_metric_name: VolumeReadBytes 13 | aws_namespace: AWS/EBS 14 | aws_statistics: 15 | - Maximum 16 | - Average 17 | - aws_dimensions: 18 | - VolumeId 19 | aws_metric_name: VolumeReadOps 20 | aws_namespace: AWS/EBS 21 | aws_statistics: 22 | - Average 23 | - aws_dimensions: 24 | - VolumeId 25 | aws_metric_name: VolumeWriteOps 26 | aws_namespace: AWS/EBS 27 | aws_statistics: 28 | - Average 29 | - aws_dimensions: 30 | - VolumeId 31 | aws_metric_name: VolumeTotalReadTime 32 | aws_namespace: AWS/EBS 33 | aws_statistics: 34 | - Sum 35 | - Average 36 | - aws_dimensions: 37 | - VolumeId 38 | aws_metric_name: VolumeTotalWriteTime 39 | aws_namespace: AWS/EBS 40 | aws_statistics: 41 | - Sum 42 | - Average 43 | - aws_dimensions: 44 | - VolumeId 45 | aws_metric_name: VolumeQueueLength 46 | aws_namespace: AWS/EBS 47 | aws_statistics: 48 | - Average 49 | - aws_dimensions: 50 | - VolumeId 51 | aws_metric_name: BurstBalance 52 | aws_namespace: AWS/EBS 53 | aws_statistics: 54 | - Average 55 | - aws_dimensions: 56 | - VolumeId 57 | aws_metric_name: VolumeIdleTime 58 | aws_namespace: AWS/EBS 59 | aws_statistics: 60 | - Sum 61 | 62 | -------------------------------------------------------------------------------- /examples/EC2.yml: -------------------------------------------------------------------------------- 1 | region: us-east-1 2 | metrics: 3 | - aws_dimensions: 4 | - InstanceId 5 | aws_metric_name: CPUUtilization 6 | aws_namespace: AWS/EC2 7 | aws_statistics: 8 | - Average 9 | aws_tag_select: 10 | resource_type_selection: ec2:instance 11 | resource_id_dimension: InstanceId 12 | - aws_dimensions: 13 | - InstanceId 14 | aws_metric_name: NetworkIn 15 | aws_namespace: AWS/EC2 16 | aws_statistics: 17 | - Average 18 | - aws_dimensions: 19 | - InstanceId 20 | aws_metric_name: NetworkOut 21 | aws_namespace: AWS/EC2 22 | aws_statistics: 23 | - Average 24 | - aws_dimensions: 25 | - InstanceId 26 | aws_metric_name: NetworkPacketsIn 27 | aws_namespace: AWS/EC2 28 | aws_statistics: 29 | - Average 30 | - aws_dimensions: 31 | - InstanceId 32 | aws_metric_name: NetworkPacketsOut 33 | aws_namespace: AWS/EC2 34 | aws_statistics: 35 | - Average 36 | - aws_dimensions: 37 | - InstanceId 38 | aws_metric_name: DiskWriteBytes 39 | aws_namespace: AWS/EC2 40 | aws_statistics: 41 | - Average 42 | - aws_dimensions: 43 | - InstanceId 44 | aws_metric_name: DiskReadBytes 45 | aws_namespace: AWS/EC2 46 | aws_statistics: 47 | - Average 48 | - aws_dimensions: 49 | - InstanceId 50 | aws_metric_name: CPUCreditBalance 51 | aws_namespace: AWS/EC2 52 | aws_statistics: 53 | - Average 54 | - aws_dimensions: 55 | - InstanceId 56 | aws_metric_name: CPUCreditUsage 57 | aws_namespace: AWS/EC2 58 | aws_statistics: 59 | - Average 60 | - aws_dimensions: 61 | - InstanceId 62 | aws_metric_name: StatusCheckFailed 63 | aws_namespace: AWS/EC2 64 | aws_statistics: 65 | - Sum 66 | - aws_dimensions: 67 | - InstanceId 68 | aws_metric_name: StatusCheckFailed_Instance 69 | aws_namespace: AWS/EC2 70 | aws_statistics: 71 | - Sum 72 | - aws_dimensions: 73 | - InstanceId 74 | aws_metric_name: StatusCheckFailed_System 75 | aws_namespace: AWS/EC2 76 | aws_statistics: 77 | - Sum 78 | -------------------------------------------------------------------------------- /examples/ECS.yml: -------------------------------------------------------------------------------- 1 | region: us-east-1 2 | metrics: 3 | - aws_dimensions: 4 | - ClusterName 5 | - ServiceName 6 | aws_metric_name: CPUUtilization 7 | aws_namespace: AWS/ECS 8 | aws_statistics: 9 | - Average 10 | - aws_dimensions: 11 | - ClusterName 12 | - ServiceName 13 | aws_metric_name: MemoryUtilization 14 | aws_namespace: AWS/ECS 15 | aws_statistics: 16 | - Average 17 | - aws_dimensions: 18 | - ClusterName 19 | aws_metric_name: GPUReservation 20 | aws_namespace: AWS/ECS 21 | aws_statistics: 22 | - Average 23 | - aws_dimensions: 24 | - ClusterName 25 | aws_metric_name: CPUReservation 26 | aws_namespace: AWS/ECS 27 | aws_statistics: 28 | - Average 29 | - aws_dimensions: 30 | - ClusterName 31 | aws_metric_name: MemoryReservation 32 | aws_namespace: AWS/ECS 33 | aws_statistics: 34 | - Average 35 | -------------------------------------------------------------------------------- /examples/EFS.yml: -------------------------------------------------------------------------------- 1 | region: us-east-1 2 | metrics: 3 | - aws_dimensions: 4 | - FileSystemId 5 | aws_metric_name: ClientConnections 6 | aws_namespace: AWS/EFS 7 | aws_statistics: 8 | - Maximum 9 | - aws_dimensions: 10 | - FileSystemId 11 | aws_metric_name: DataWriteIOBytes 12 | aws_namespace: AWS/EFS 13 | aws_statistics: 14 | - Maximum 15 | - aws_dimensions: 16 | - FileSystemId 17 | aws_metric_name: DataReadIOBytes 18 | aws_namespace: AWS/EFS 19 | aws_statistics: 20 | - Maximum 21 | - aws_dimensions: 22 | - FileSystemId 23 | aws_metric_name: PermittedThroughput 24 | aws_namespace: AWS/EFS 25 | aws_statistics: 26 | - Maximum 27 | - aws_dimensions: 28 | - FileSystemId 29 | aws_metric_name: BurstCreditBalance 30 | aws_namespace: AWS/EFS 31 | aws_statistics: 32 | - Average 33 | - aws_dimensions: 34 | - FileSystemId 35 | aws_metric_name: PercentIOLimit 36 | aws_namespace: AWS/EFS 37 | aws_statistics: 38 | - Average 39 | -------------------------------------------------------------------------------- /examples/ELB.yml: -------------------------------------------------------------------------------- 1 | region: us-east-1 2 | metrics: 3 | - aws_dimensions: 4 | - AvailabilityZone 5 | - LoadBalancerName 6 | aws_metric_name: BackendConnectionErrors 7 | aws_namespace: AWS/ELB 8 | aws_statistics: 9 | - Sum 10 | - aws_dimensions: 11 | - AvailabilityZone 12 | - LoadBalancerName 13 | aws_metric_name: HTTPCode_Backend_5XX 14 | aws_namespace: AWS/ELB 15 | aws_statistics: 16 | - Sum 17 | - aws_dimensions: 18 | - AvailabilityZone 19 | - LoadBalancerName 20 | aws_metric_name: HTTPCode_Backend_4XX 21 | aws_namespace: AWS/ELB 22 | aws_statistics: 23 | - Sum 24 | - aws_dimensions: 25 | - AvailabilityZone 26 | - LoadBalancerName 27 | aws_metric_name: HTTPCode_Backend_3XX 28 | aws_namespace: AWS/ELB 29 | aws_statistics: 30 | - Sum 31 | - aws_dimensions: 32 | - AvailabilityZone 33 | - LoadBalancerName 34 | aws_metric_name: HTTPCode_Backend_2XX 35 | aws_namespace: AWS/ELB 36 | aws_statistics: 37 | - Sum 38 | - aws_dimensions: 39 | - LoadBalancerName 40 | - AvailabilityZone 41 | aws_metric_name: HTTPCode_ELB_5XX 42 | aws_namespace: AWS/ELB 43 | aws_statistics: 44 | - Sum 45 | - aws_dimensions: 46 | - LoadBalancerName 47 | - AvailabilityZone 48 | aws_metric_name: RequestCount 49 | aws_namespace: AWS/ELB 50 | aws_statistics: 51 | - Average 52 | - aws_dimensions: 53 | - LoadBalancerName 54 | - AvailabilityZone 55 | aws_metric_name: HTTPCode_ELB_4XX 56 | aws_namespace: AWS/ELB 57 | aws_statistics: 58 | - Sum 59 | - aws_dimensions: 60 | - AvailabilityZone 61 | - LoadBalancerName 62 | aws_metric_name: Latency 63 | aws_namespace: AWS/ELB 64 | aws_statistics: 65 | - Average 66 | - aws_dimensions: 67 | - LoadBalancerName 68 | - AvailabilityZone 69 | aws_metric_name: SurgeQueueLength 70 | aws_namespace: AWS/ELB 71 | - aws_dimensions: 72 | - LoadBalancer 73 | aws_metric_name: ActiveFlowCount 74 | aws_namespace: AWS/ELB 75 | aws_statistics: 76 | - Average 77 | - aws_dimensions: 78 | - LoadBalancer 79 | aws_metric_name: ActiveFlowCount_TLS 80 | aws_namespace: AWS/ELB 81 | aws_statistics: 82 | - Average 83 | - aws_dimensions: 84 | - LoadBalancer 85 | aws_metric_name: ProcessedBytes 86 | aws_namespace: AWS/ELB 87 | aws_statistics: 88 | - Sum 89 | - aws_dimensions: 90 | - LoadBalancer 91 | aws_metric_name: ProcessedBytes_TLS 92 | aws_namespace: AWS/ELB 93 | aws_statistics: 94 | - Sum 95 | - aws_dimensions: 96 | - LoadBalancer 97 | aws_metric_name: HealthyHostCount 98 | aws_namespace: AWS/ELB 99 | aws_statistics: 100 | - Minimum 101 | - aws_dimensions: 102 | - LoadBalancer 103 | aws_metric_name: HealthyHostCount 104 | aws_namespace: AWS/ELB 105 | aws_statistics: 106 | - Maximum 107 | - aws_dimensions: 108 | - LoadBalancer 109 | aws_metric_name: UnHealthyHostCount 110 | aws_namespace: AWS/ELB 111 | aws_statistics: 112 | - Maximum 113 | - aws_dimensions: 114 | - LoadBalancer 115 | aws_metric_name: UnHealthyHostCount 116 | aws_namespace: AWS/ELB 117 | aws_statistics: 118 | - Minimum 119 | - aws_dimensions: 120 | - LoadBalancer 121 | aws_metric_name: NewFlowCount 122 | aws_namespace: AWS/ELB 123 | aws_statistics: 124 | - Sum 125 | - aws_dimensions: 126 | - LoadBalancer 127 | aws_metric_name: NewFlowCount_TLS 128 | aws_namespace: AWS/ELB 129 | aws_statistics: 130 | - Sum 131 | - aws_dimensions: 132 | - LoadBalancer 133 | aws_metric_name: TCP_Client_Reset_Count 134 | aws_namespace: AWS/ELB 135 | aws_statistics: 136 | - Sum 137 | - aws_dimensions: 138 | - LoadBalancer 139 | aws_metric_name: TCP_Target_Reset_Count 140 | aws_namespace: AWS/ELB 141 | aws_statistics: 142 | - Sum 143 | - aws_dimensions: 144 | - LoadBalancer 145 | aws_metric_name: TCP_ELB_Reset_Count 146 | aws_namespace: AWS/ELB 147 | aws_statistics: 148 | - Sum 149 | - aws_dimensions: 150 | - LoadBalancer 151 | aws_metric_name: ClientTLSNegotiationErrorCount 152 | aws_namespace: AWS/ELB 153 | aws_statistics: 154 | - Sum 155 | - aws_dimensions: 156 | - LoadBalancer 157 | aws_metric_name: TargetTLSNegotiationErrorCount 158 | aws_namespace: AWS/ELB 159 | aws_statistics: 160 | - Sum 161 | - aws_dimensions: 162 | - LoadBalancer 163 | aws_metric_name: ConsumedLCUs 164 | aws_namespace: AWS/ELB 165 | aws_statistics: 166 | - Sum 167 | -------------------------------------------------------------------------------- /examples/ElastiCache.yml: -------------------------------------------------------------------------------- 1 | region: us-east-1 2 | metrics: 3 | - aws_dimensions: 4 | - CacheNodeId 5 | - CacheClusterId 6 | aws_metric_name: CPUUtilization 7 | aws_namespace: AWS/ElastiCache 8 | aws_statistics: 9 | - Average 10 | - aws_dimensions: 11 | - CacheNodeId 12 | - CacheClusterId 13 | aws_metric_name: CPUCreditBalance 14 | aws_namespace: AWS/ElastiCache 15 | aws_statistics: 16 | - Average 17 | - aws_dimensions: 18 | - CacheNodeId 19 | - CacheClusterId 20 | aws_metric_name: FreeableMemory 21 | aws_namespace: AWS/ElastiCache 22 | aws_statistics: 23 | - Average 24 | - aws_dimensions: 25 | - CacheNodeId 26 | - CacheClusterId 27 | aws_metric_name: NetworkBytesIn 28 | aws_namespace: AWS/ElastiCache 29 | aws_statistics: 30 | - Average 31 | - aws_dimensions: 32 | - CacheNodeId 33 | - CacheClusterId 34 | aws_metric_name: NetworkBytesOut 35 | aws_namespace: AWS/ElastiCache 36 | aws_statistics: 37 | - Average 38 | - aws_dimensions: 39 | - CacheNodeId 40 | - CacheClusterId 41 | aws_metric_name: SwapUsage 42 | aws_namespace: AWS/ElastiCache 43 | aws_statistics: 44 | - Average 45 | - aws_dimensions: 46 | - CacheNodeId 47 | - CacheClusterId 48 | aws_metric_name: CacheHits 49 | aws_namespace: AWS/ElastiCache 50 | aws_statistics: 51 | - Average 52 | - aws_dimensions: 53 | - CacheNodeId 54 | - CacheClusterId 55 | aws_metric_name: CacheMisses 56 | aws_namespace: AWS/ElastiCache 57 | aws_statistics: 58 | - Average 59 | - aws_dimensions: 60 | - CacheNodeId 61 | - CacheClusterId 62 | aws_metric_name: CurrConnections 63 | aws_namespace: AWS/ElastiCache 64 | aws_statistics: 65 | - Average 66 | - aws_dimensions: 67 | - CacheNodeId 68 | - CacheClusterId 69 | aws_metric_name: NewConnections 70 | aws_namespace: AWS/ElastiCache 71 | aws_statistics: 72 | - Average 73 | - aws_dimensions: 74 | - CacheNodeId 75 | - CacheClusterId 76 | aws_metric_name: GetTypeCmds 77 | aws_namespace: AWS/ElastiCache 78 | aws_statistics: 79 | - Average 80 | - aws_dimensions: 81 | - CacheNodeId 82 | - CacheClusterId 83 | aws_metric_name: SetTypeCmds 84 | aws_namespace: AWS/ElastiCache 85 | aws_statistics: 86 | - Average 87 | - aws_dimensions: 88 | - CacheNodeId 89 | - CacheClusterId 90 | aws_metric_name: EngineCPUUtilization 91 | aws_namespace: AWS/ElastiCache 92 | aws_statistics: 93 | - Average 94 | - aws_dimensions: 95 | - CacheNodeId 96 | - CacheClusterId 97 | aws_metric_name: BytesUsedForCache 98 | aws_namespace: AWS/ElastiCache 99 | aws_statistics: 100 | - Average 101 | - aws_dimensions: 102 | - CacheNodeId 103 | - CacheClusterId 104 | aws_metric_name: HashBasedCmds 105 | aws_namespace: AWS/ElastiCache 106 | aws_statistics: 107 | - Average 108 | - aws_dimensions: 109 | - CacheNodeId 110 | - CacheClusterId 111 | aws_metric_name: HyperLogLogBasedCmds 112 | aws_namespace: AWS/ElastiCache 113 | aws_statistics: 114 | - Average 115 | - aws_dimensions: 116 | - CacheNodeId 117 | - CacheClusterId 118 | aws_metric_name: KeyBasedCmds 119 | aws_namespace: AWS/ElastiCache 120 | aws_statistics: 121 | - Average 122 | - aws_dimensions: 123 | - CacheNodeId 124 | - CacheClusterId 125 | aws_metric_name: ListBasedCmds 126 | aws_namespace: AWS/ElastiCache 127 | aws_statistics: 128 | - Average 129 | - aws_dimensions: 130 | - CacheNodeId 131 | - CacheClusterId 132 | aws_metric_name: SetBasedCmds 133 | aws_namespace: AWS/ElastiCache 134 | aws_statistics: 135 | - Average 136 | - aws_dimensions: 137 | - CacheNodeId 138 | - CacheClusterId 139 | aws_metric_name: SetTypeCmds 140 | aws_namespace: AWS/ElastiCache 141 | aws_statistics: 142 | - Average 143 | - aws_dimensions: 144 | - CacheNodeId 145 | - CacheClusterId 146 | aws_metric_name: SortedSetBasedCmds 147 | aws_namespace: AWS/ElastiCache 148 | aws_statistics: 149 | - Average 150 | - aws_dimensions: 151 | - CacheNodeId 152 | - CacheClusterId 153 | aws_metric_name: StringBasedCmds 154 | aws_namespace: AWS/ElastiCache 155 | aws_statistics: 156 | - Average 157 | - aws_dimensions: 158 | - CacheNodeId 159 | - CacheClusterId 160 | aws_metric_name: StreamBasedCmds 161 | aws_namespace: AWS/ElastiCache 162 | aws_statistics: 163 | - Average 164 | - aws_dimensions: 165 | - CacheNodeId 166 | - CacheClusterId 167 | aws_metric_name: CurrItems 168 | aws_namespace: AWS/ElastiCache 169 | aws_statistics: 170 | - Average 171 | - aws_dimensions: 172 | - CacheNodeId 173 | - CacheClusterId 174 | aws_metric_name: ActiveDefragHits 175 | aws_namespace: AWS/ElastiCache 176 | aws_statistics: 177 | - Average 178 | - aws_dimensions: 179 | - CacheNodeId 180 | - CacheClusterId 181 | aws_metric_name: Evictions 182 | aws_namespace: AWS/ElastiCache 183 | aws_statistics: 184 | - Average 185 | - aws_dimensions: 186 | - CacheNodeId 187 | - CacheClusterId 188 | aws_metric_name: Reclaimed 189 | aws_namespace: AWS/ElastiCache 190 | aws_statistics: 191 | - Average 192 | - aws_dimensions: 193 | - CacheNodeId 194 | - CacheClusterId 195 | aws_metric_name: SaveInProgress 196 | aws_namespace: AWS/ElastiCache 197 | aws_statistics: 198 | - Average 199 | - aws_dimensions: 200 | - CacheNodeId 201 | - CacheClusterId 202 | aws_metric_name: ReplicationLag 203 | aws_namespace: AWS/ElastiCache 204 | aws_statistics: 205 | - Average 206 | - aws_dimensions: 207 | - CacheNodeId 208 | - CacheClusterId 209 | aws_metric_name: ReplicationBytes 210 | aws_namespace: AWS/ElastiCache 211 | aws_statistics: 212 | - Average 213 | -------------------------------------------------------------------------------- /examples/Fargate.yml: -------------------------------------------------------------------------------- 1 | region: us-east-1 2 | metrics: 3 | - aws_dimensions: 4 | - ClusterName 5 | - ServiceName 6 | aws_metric_name: CPUUtilization 7 | aws_namespace: AWS/Fargate 8 | aws_statistics: 9 | - Average 10 | - aws_dimensions: 11 | - ClusterName 12 | - ServiceName 13 | aws_metric_name: MemoryUtilization 14 | aws_namespace: AWS/Fargate 15 | aws_statistics: 16 | - Average 17 | -------------------------------------------------------------------------------- /examples/Firehose.yml: -------------------------------------------------------------------------------- 1 | region: us-east-1 2 | metrics: 3 | - aws_dimensions: 4 | - DeliveryStreamName 5 | aws_metric_name: IncomingRecords 6 | aws_namespace: AWS/Firehose 7 | aws_statistics: 8 | - Sum 9 | - aws_dimensions: 10 | - DeliveryStreamName 11 | aws_metric_name: IncomingBytes 12 | aws_namespace: AWS/Firehose 13 | aws_statistics: 14 | - Sum 15 | - aws_dimensions: 16 | - DeliveryStreamName 17 | aws_metric_name: IncomingPutRequests 18 | aws_namespace: AWS/Firehose 19 | aws_statistics: 20 | - Sum 21 | - aws_dimensions: 22 | - DeliveryStreamName 23 | aws_metric_name: PutRecord.Latency 24 | aws_namespace: AWS/Firehose 25 | aws_statistics: 26 | - Sum 27 | - aws_dimensions: 28 | - DeliveryStreamName 29 | aws_metric_name: PutRecordBatch.Latency 30 | aws_namespace: AWS/Firehose 31 | aws_statistics: 32 | - Sum 33 | - aws_dimensions: 34 | - DeliveryStreamName 35 | aws_metric_name: DataReadFromKinesisStream.Records 36 | aws_namespace: AWS/Firehose 37 | aws_statistics: 38 | - Sum 39 | - aws_dimensions: 40 | - DeliveryStreamName 41 | aws_metric_name: DataReadFromKinesisStream.Bytes 42 | aws_namespace: AWS/Firehose 43 | aws_statistics: 44 | - Sum 45 | - aws_dimensions: 46 | - DeliveryStreamName 47 | aws_metric_name: ThrottledGetRecords 48 | aws_namespace: AWS/Firehose 49 | aws_statistics: 50 | - Sum 51 | - aws_dimensions: 52 | - DeliveryStreamName 53 | aws_metric_name: SucceedProcessing.Records 54 | aws_namespace: AWS/Firehose 55 | aws_statistics: 56 | - Sum 57 | - aws_dimensions: 58 | - DeliveryStreamName 59 | aws_metric_name: SucceedProcessing.Bytes 60 | aws_namespace: AWS/Firehose 61 | aws_statistics: 62 | - Sum 63 | - aws_dimensions: 64 | - DeliveryStreamName 65 | aws_metric_name: ExecuteProcessing.Duration 66 | aws_namespace: AWS/Firehose 67 | aws_statistics: 68 | - Sum 69 | - aws_dimensions: 70 | - DeliveryStreamName 71 | aws_metric_name: ExecuteProcessing.Success 72 | aws_namespace: AWS/Firehose 73 | aws_statistics: 74 | - Sum 75 | - aws_dimensions: 76 | - DeliveryStreamName 77 | aws_metric_name: DeliveryToS3.Success 78 | aws_namespace: AWS/Firehose 79 | aws_statistics: 80 | - Sum 81 | - aws_dimensions: 82 | - DeliveryStreamName 83 | aws_metric_name: DeliveryToS3.DataFreshness 84 | aws_namespace: AWS/Firehose 85 | aws_statistics: 86 | - Sum 87 | - aws_dimensions: 88 | - DeliveryStreamName 89 | aws_metric_name: DeliveryToS3.Records 90 | aws_namespace: AWS/Firehose 91 | aws_statistics: 92 | - Sum 93 | - aws_dimensions: 94 | - DeliveryStreamName 95 | aws_metric_name: DeliveryToS3.Bytes 96 | aws_namespace: AWS/Firehose 97 | aws_statistics: 98 | - Sum 99 | - aws_dimensions: 100 | - DeliveryStreamName 101 | aws_metric_name: DeliveryToElasticsearch.Success 102 | aws_namespace: AWS/Firehose 103 | aws_statistics: 104 | - Sum 105 | - aws_dimensions: 106 | - DeliveryStreamName 107 | aws_metric_name: DeliveryToElasticsearch.DataFreshness 108 | aws_namespace: AWS/Firehose 109 | aws_statistics: 110 | - Sum 111 | - aws_dimensions: 112 | - DeliveryStreamName 113 | aws_metric_name: DeliveryToElasticsearch.Records 114 | aws_namespace: AWS/Firehose 115 | aws_statistics: 116 | - Sum 117 | - aws_dimensions: 118 | - DeliveryStreamName 119 | aws_metric_name: DeliveryToElasticsearch.Bytes 120 | aws_namespace: AWS/Firehose 121 | aws_statistics: 122 | - Sum 123 | - aws_dimensions: 124 | - DeliveryStreamName 125 | aws_metric_name: DeliveryToRedshift.Success 126 | aws_namespace: AWS/Firehose 127 | aws_statistics: 128 | - Sum 129 | - aws_dimensions: 130 | - DeliveryStreamName 131 | aws_metric_name: DeliveryToRedshift.DataFreshness 132 | aws_namespace: AWS/Firehose 133 | aws_statistics: 134 | - Sum 135 | - aws_dimensions: 136 | - DeliveryStreamName 137 | aws_metric_name: DeliveryToRedshift.Records 138 | aws_namespace: AWS/Firehose 139 | aws_statistics: 140 | - Sum 141 | - aws_dimensions: 142 | - DeliveryStreamName 143 | aws_metric_name: DeliveryToRedshift.Bytes 144 | aws_namespace: AWS/Firehose 145 | aws_statistics: 146 | - Sum 147 | - aws_dimensions: 148 | - DeliveryStreamName 149 | aws_metric_name: DeliveryToHttpEndpoint.Success 150 | aws_namespace: AWS/Firehose 151 | aws_statistics: 152 | - Sum 153 | - aws_dimensions: 154 | - DeliveryStreamName 155 | aws_metric_name: DeliveryToHttpEndpoint.DataFreshness 156 | aws_namespace: AWS/Firehose 157 | aws_statistics: 158 | - Sum 159 | - aws_dimensions: 160 | - DeliveryStreamName 161 | aws_metric_name: DeliveryToHttpEndpoint.Records 162 | aws_namespace: AWS/Firehose 163 | aws_statistics: 164 | - Sum 165 | - aws_dimensions: 166 | - DeliveryStreamName 167 | aws_metric_name: DeliveryToHttpEndpoint.ProcessedRecords 168 | aws_namespace: AWS/Firehose 169 | aws_statistics: 170 | - Sum 171 | - aws_dimensions: 172 | - DeliveryStreamName 173 | aws_metric_name: DeliveryToHttpEndpoint.Bytes 174 | aws_namespace: AWS/Firehose 175 | aws_statistics: 176 | - Sum 177 | - aws_dimensions: 178 | - DeliveryStreamName 179 | aws_metric_name: DeliveryToHttpEndpoint.ProcessedBytes 180 | aws_namespace: AWS/Firehose 181 | aws_statistics: 182 | - Sum 183 | -------------------------------------------------------------------------------- /examples/Kafka.yml: -------------------------------------------------------------------------------- 1 | region: us-east-1 2 | period_seconds: 240 3 | metrics: 4 | - aws_dimensions: [Cluster Name, Broker ID] 5 | aws_metric_name: RootDiskUsed 6 | aws_namespace: AWS/Kafka 7 | aws_statistics: 8 | - Average 9 | - aws_dimensions: [Cluster Name, Broker ID] 10 | aws_metric_name: KafkaDataLogsDiskUsed 11 | aws_namespace: AWS/Kafka 12 | aws_statistics: 13 | - Average 14 | - aws_dimensions: [Cluster Name, Broker ID] 15 | aws_metric_name: KafkaAppLogsDiskUsed 16 | aws_namespace: AWS/Kafka 17 | aws_statistics: 18 | - Average 19 | - aws_dimensions: [Cluster Name, Broker ID] 20 | aws_metric_name: MemoryFree 21 | aws_namespace: AWS/Kafka 22 | aws_statistics: 23 | - Average 24 | - aws_dimensions: [Cluster Name, Broker ID] 25 | aws_metric_name: MemoryUsed 26 | aws_namespace: AWS/Kafka 27 | aws_statistics: 28 | - Average 29 | - aws_dimensions: [Cluster Name, Broker ID] 30 | aws_metric_name: NetworkRxPackets 31 | aws_namespace: AWS/Kafka 32 | aws_statistics: 33 | - Average 34 | - aws_dimensions: [Cluster Name, Broker ID] 35 | aws_metric_name: NetworkRxPackets 36 | aws_namespace: AWS/Kafka 37 | aws_statistics: 38 | - Maximum 39 | - aws_dimensions: [Cluster Name, Broker ID] 40 | aws_metric_name: NetworkTxPackets 41 | aws_namespace: AWS/Kafka 42 | aws_statistics: 43 | - Maximum 44 | - aws_dimensions: [Cluster Name, Broker ID] 45 | aws_metric_name: SwapFree 46 | aws_namespace: AWS/Kafka 47 | aws_statistics: 48 | - Average 49 | - aws_dimensions: [Cluster Name, Broker ID] 50 | aws_metric_name: SwapUsed 51 | aws_namespace: AWS/Kafka 52 | aws_statistics: 53 | - Average 54 | - aws_dimensions: [Cluster Name, Broker ID] 55 | aws_metric_name: GlobalTopicCount 56 | aws_namespace: AWS/Kafka 57 | aws_statistics: 58 | - Maximum 59 | - aws_dimensions: [Cluster Name, Broker ID] 60 | aws_metric_name: CpuUser 61 | aws_namespace: AWS/Kafka 62 | aws_statistics: 63 | - Average 64 | -------------------------------------------------------------------------------- /examples/Kinesis.yml: -------------------------------------------------------------------------------- 1 | region: us-east-1 2 | metrics: 3 | - aws_dimensions: 4 | - StreamName 5 | aws_metric_name: IncomingBytes 6 | aws_namespace: AWS/Kinesis 7 | aws_statistics: 8 | - Sum 9 | - aws_dimensions: 10 | - StreamName 11 | aws_metric_name: PutRecord.Latency 12 | aws_namespace: AWS/Kinesis 13 | aws_statistics: 14 | - Average 15 | - aws_dimensions: 16 | - StreamName 17 | aws_metric_name: PutRecords.Latency 18 | aws_namespace: AWS/Kinesis 19 | aws_statistics: 20 | - Average 21 | - aws_dimensions: 22 | - StreamName 23 | aws_metric_name: GetRecords.Latency 24 | aws_namespace: AWS/Kinesis 25 | aws_statistics: 26 | - Average 27 | - aws_dimensions: 28 | - StreamName 29 | aws_metric_name: GetRecords.Records 30 | aws_namespace: AWS/Kinesis 31 | aws_statistics: 32 | - Sum 33 | - aws_dimensions: 34 | - StreamName 35 | aws_metric_name: GetRecords.Bytes 36 | aws_namespace: AWS/Kinesis 37 | aws_statistics: 38 | - Sum 39 | - aws_dimensions: 40 | - StreamName 41 | aws_metric_name: GetRecords.IteratorAgeMilliseconds 42 | aws_namespace: AWS/Kinesis 43 | aws_statistics: 44 | - Average 45 | - aws_dimensions: 46 | - StreamName 47 | aws_metric_name: IncomingRecords 48 | aws_namespace: AWS/Kinesis 49 | aws_statistics: 50 | - Sum 51 | - aws_dimensions: 52 | - StreamName 53 | aws_metric_name: IncomingBytes 54 | aws_namespace: AWS/Kinesis 55 | aws_statistics: 56 | - Sum 57 | - aws_dimensions: 58 | - StreamName 59 | aws_metric_name: WriteProvisionedThroughputExceeded 60 | aws_namespace: AWS/Kinesis 61 | aws_statistics: 62 | - Average 63 | - aws_dimensions: 64 | - StreamName 65 | aws_metric_name: ReadProvisionedThroughputExceeded 66 | aws_namespace: AWS/Kinesis 67 | aws_statistics: 68 | - Average 69 | -------------------------------------------------------------------------------- /examples/Lambda.yml: -------------------------------------------------------------------------------- 1 | region: us-east-1 2 | metrics: 3 | - aws_dimensions: 4 | - FunctionName 5 | - Resource 6 | aws_metric_name: Invocations 7 | aws_namespace: AWS/Lambda 8 | aws_statistics: 9 | - Sum 10 | - aws_dimensions: 11 | - FunctionName 12 | - Resource 13 | aws_metric_name: Errors 14 | aws_namespace: AWS/Lambda 15 | aws_statistics: 16 | - Sum 17 | - aws_dimensions: 18 | - FunctionName 19 | - Resource 20 | aws_metric_name: Duration 21 | aws_namespace: AWS/Lambda 22 | aws_statistics: 23 | - Average 24 | - aws_dimensions: 25 | - FunctionName 26 | - Resource 27 | aws_metric_name: Duration 28 | aws_namespace: AWS/Lambda 29 | aws_statistics: 30 | - Maximum 31 | - aws_dimensions: 32 | - FunctionName 33 | - Resource 34 | aws_metric_name: Duration 35 | aws_namespace: AWS/Lambda 36 | aws_statistics: 37 | - Minimum 38 | - aws_dimensions: 39 | - FunctionName 40 | - Resource 41 | aws_metric_name: Throttles 42 | aws_namespace: AWS/Lambda 43 | aws_statistics: 44 | - Sum 45 | - aws_dimensions: 46 | - FunctionName 47 | - Resource 48 | aws_metric_name: ConcurrentExecutions 49 | aws_namespace: AWS/Lambda 50 | aws_statistics: 51 | - Sum 52 | - aws_dimensions: 53 | - FunctionName 54 | - Resource 55 | aws_metric_name: UnreservedConcurrentExecutions 56 | aws_namespace: AWS/Lambda 57 | aws_statistics: 58 | - Sum 59 | -------------------------------------------------------------------------------- /examples/NATGateway.yml: -------------------------------------------------------------------------------- 1 | region: us-east-1 2 | metrics: 3 | - aws_dimensions: 4 | - NatGatewayId 5 | aws_metric_name: ActiveConnectionCount 6 | aws_namespace: AWS/NATGateway 7 | aws_statistics: 8 | - Max 9 | - aws_dimensions: 10 | - NatGatewayId 11 | aws_metric_name: BytesInFromDestination 12 | aws_namespace: AWS/NATGateway 13 | aws_statistics: 14 | - Sum 15 | - aws_dimensions: 16 | - NatGatewayId 17 | aws_metric_name: BytesInFromSource 18 | aws_namespace: AWS/NATGateway 19 | aws_statistics: 20 | - Sum 21 | - aws_dimensions: 22 | - NatGatewayId 23 | aws_metric_name: BytesOutToDestination 24 | aws_namespace: AWS/NATGateway 25 | aws_statistics: 26 | - Sum 27 | - aws_dimensions: 28 | - NatGatewayId 29 | aws_metric_name: BytesOutToSource 30 | aws_namespace: AWS/NATGateway 31 | aws_statistics: 32 | - Sum 33 | - aws_dimensions: 34 | - NatGatewayId 35 | aws_metric_name: ConnectionAttemptCount 36 | aws_namespace: AWS/NATGateway 37 | aws_statistics: 38 | - Sum 39 | - aws_dimensions: 40 | - NatGatewayId 41 | aws_metric_name: ConnectionEstablishedCount 42 | aws_namespace: AWS/NATGateway 43 | aws_statistics: 44 | - Sum 45 | - aws_dimensions: 46 | - NatGatewayId 47 | aws_metric_name: IdleTimeoutCount 48 | aws_namespace: AWS/NATGateway 49 | aws_statistics: 50 | - Sum 51 | - aws_dimensions: 52 | - NatGatewayId 53 | aws_metric_name: PacketsDropCount 54 | aws_namespace: AWS/NATGateway 55 | aws_statistics: 56 | - Sum 57 | - aws_dimensions: 58 | - NatGatewayId 59 | aws_metric_name: PacketsInFromDestination 60 | aws_namespace: AWS/NATGateway 61 | aws_statistics: 62 | - Sum 63 | - aws_dimensions: 64 | - NatGatewayId 65 | aws_metric_name: PacketsInFromSource 66 | aws_namespace: AWS/NATGateway 67 | aws_statistics: 68 | - Sum 69 | - aws_dimensions: 70 | - NatGatewayId 71 | aws_metric_name: PacketsOutToDestination 72 | aws_namespace: AWS/NATGateway 73 | aws_statistics: 74 | - Sum 75 | - aws_dimensions: 76 | - NatGatewayId 77 | aws_metric_name: PacketsOutToSource 78 | aws_namespace: AWS/NATGateway 79 | aws_statistics: 80 | - Sum 81 | -------------------------------------------------------------------------------- /examples/NetworkELB.yml: -------------------------------------------------------------------------------- 1 | region: us-east-1 2 | metrics: 3 | - aws_dimensions: 4 | - AvailabilityZone 5 | - LoadBalancer 6 | - TargetGroup 7 | aws_metric_name: ActiveFlowCount 8 | aws_namespace: AWS/NetworkELB 9 | aws_statistics: 10 | - Average 11 | - aws_dimensions: 12 | - AvailabilityZone 13 | - LoadBalancer 14 | - TargetGroup 15 | aws_metric_name: ActiveFlowCount_TCP 16 | aws_namespace: AWS/NetworkELB 17 | aws_statistics: 18 | - Average 19 | - aws_dimensions: 20 | - AvailabilityZone 21 | - LoadBalancer 22 | - TargetGroup 23 | aws_metric_name: ActiveFlowCount_UDP 24 | aws_namespace: AWS/NetworkELB 25 | aws_statistics: 26 | - Average 27 | - aws_dimensions: 28 | - AvailabilityZone 29 | - LoadBalancer 30 | - TargetGroup 31 | aws_metric_name: ClientTLSNegotiationErrorCount 32 | aws_namespace: AWS/NetworkELB 33 | aws_statistics: 34 | - Sum 35 | - aws_dimensions: 36 | - LoadBalancer 37 | aws_metric_name: ConsumedLCUs 38 | aws_namespace: AWS/NetworkELB 39 | aws_statistics: 40 | - Average 41 | - aws_dimensions: 42 | - LoadBalancer 43 | aws_metric_name: ConsumedLCUs_TCP 44 | aws_namespace: AWS/NetworkELB 45 | aws_statistics: 46 | - Average 47 | - aws_dimensions: 48 | - LoadBalancer 49 | aws_metric_name: ConsumedLCUs_TLS 50 | aws_namespace: AWS/NetworkELB 51 | aws_statistics: 52 | - Average 53 | - aws_dimensions: 54 | - LoadBalancer 55 | aws_metric_name: ConsumedLCUs_UDP 56 | aws_namespace: AWS/NetworkELB 57 | aws_statistics: 58 | - Average 59 | - aws_dimensions: 60 | - AvailabilityZone 61 | - LoadBalancer 62 | - TargetGroup 63 | aws_metric_name: HealthyHostCount 64 | aws_namespace: AWS/NetworkELB 65 | aws_statistics: 66 | - Minimum 67 | - aws_dimensions: 68 | - AvailabilityZone 69 | - LoadBalancer 70 | - TargetGroup 71 | aws_metric_name: NewFlowCount 72 | aws_namespace: AWS/NetworkELB 73 | aws_statistics: 74 | - Sum 75 | - aws_dimensions: 76 | - AvailabilityZone 77 | - LoadBalancer 78 | - TargetGroup 79 | aws_metric_name: NewFlowCount_TCP 80 | aws_namespace: AWS/NetworkELB 81 | aws_statistics: 82 | - Sum 83 | - aws_dimensions: 84 | - AvailabilityZone 85 | - LoadBalancer 86 | - TargetGroup 87 | aws_metric_name: NewFlowCount_TLS 88 | aws_namespace: AWS/NetworkELB 89 | aws_statistics: 90 | - Sum 91 | - aws_dimensions: 92 | - AvailabilityZone 93 | - LoadBalancer 94 | - TargetGroup 95 | aws_metric_name: NewFlowCount_UDP 96 | aws_namespace: AWS/NetworkELB 97 | aws_statistics: 98 | - Sum 99 | - aws_dimensions: 100 | - AvailabilityZone 101 | - LoadBalancer 102 | - TargetGroup 103 | aws_metric_name: ProcessedBytes 104 | aws_namespace: AWS/NetworkELB 105 | aws_statistics: 106 | - Sum 107 | - aws_dimensions: 108 | - AvailabilityZone 109 | - LoadBalancer 110 | - TargetGroup 111 | aws_metric_name: ProcessedBytes_TLS 112 | aws_namespace: AWS/NetworkELB 113 | aws_statistics: 114 | - Sum 115 | - aws_dimensions: 116 | - AvailabilityZone 117 | - LoadBalancer 118 | - TargetGroup 119 | aws_metric_name: ProcessedBytes_UDP 120 | aws_namespace: AWS/NetworkELB 121 | aws_statistics: 122 | - Sum 123 | - aws_dimensions: 124 | - AvailabilityZone 125 | - LoadBalancer 126 | - TargetGroup 127 | aws_metric_name: ProcessedPackets 128 | aws_namespace: AWS/NetworkELB 129 | aws_statistics: 130 | - Sum 131 | - aws_dimensions: 132 | - AvailabilityZone 133 | - LoadBalancer 134 | - TargetGroup 135 | aws_metric_name: TargetTLSNegotiationErrorCount 136 | aws_namespace: AWS/NetworkELB 137 | aws_statistics: 138 | - Sum 139 | - aws_dimensions: 140 | - AvailabilityZone 141 | - LoadBalancer 142 | - TargetGroup 143 | aws_metric_name: TCP_Client_Reset_Count 144 | aws_namespace: AWS/NetworkELB 145 | aws_statistics: 146 | - Sum 147 | - aws_dimensions: 148 | - AvailabilityZone 149 | - LoadBalancer 150 | - TargetGroup 151 | aws_metric_name: TCP_Target_Reset_Count 152 | aws_namespace: AWS/NetworkELB 153 | aws_statistics: 154 | - Sum 155 | - aws_dimensions: 156 | - AvailabilityZone 157 | - LoadBalancer 158 | - TargetGroup 159 | aws_metric_name: UnHealthyHostCount 160 | aws_namespace: AWS/NetworkELB 161 | aws_statistics: 162 | - Maximum 163 | 164 | -------------------------------------------------------------------------------- /examples/RDS.yml: -------------------------------------------------------------------------------- 1 | region: us-east-1 2 | metrics: 3 | - aws_dimensions: 4 | - DBInstanceIdentifier 5 | aws_metric_name: DatabaseConnections 6 | aws_namespace: AWS/RDS 7 | aws_statistics: 8 | - Maximum 9 | - aws_dimensions: 10 | - DBInstanceIdentifier 11 | aws_metric_name: FreeStorageSpace 12 | aws_namespace: AWS/RDS 13 | aws_statistics: 14 | - Average 15 | - aws_dimensions: 16 | - DBInstanceIdentifier 17 | aws_metric_name: FreeableMemory 18 | aws_namespace: AWS/RDS 19 | aws_statistics: 20 | - Average 21 | - aws_dimensions: 22 | - DBInstanceIdentifier 23 | aws_metric_name: CPUUtilization 24 | aws_namespace: AWS/RDS 25 | aws_statistics: 26 | - Average 27 | - aws_dimensions: 28 | - DBInstanceIdentifier 29 | aws_metric_name: ReadIOPS 30 | aws_namespace: AWS/RDS 31 | aws_statistics: 32 | - Sum 33 | - aws_dimensions: 34 | - DBInstanceIdentifier 35 | aws_metric_name: WriteIOPS 36 | aws_namespace: AWS/RDS 37 | aws_statistics: 38 | - Sum 39 | - aws_dimensions: 40 | - DBInstanceIdentifier 41 | aws_metric_name: ReadLatency 42 | aws_namespace: AWS/RDS 43 | aws_statistics: 44 | - Average 45 | - aws_dimensions: 46 | - DBInstanceIdentifier 47 | aws_metric_name: WriteLatency 48 | aws_namespace: AWS/RDS 49 | aws_statistics: 50 | - Average 51 | - aws_dimensions: 52 | - DBInstanceIdentifier 53 | aws_metric_name: ReadThroughput 54 | aws_namespace: AWS/RDS 55 | aws_statistics: 56 | - Average 57 | - aws_dimensions: 58 | - DBInstanceIdentifier 59 | aws_metric_name: WriteThroughput 60 | aws_namespace: AWS/RDS 61 | aws_statistics: 62 | - Average 63 | - aws_dimensions: 64 | - DBInstanceIdentifier 65 | aws_metric_name: CPUCreditUsage 66 | aws_namespace: AWS/RDS 67 | aws_statistics: 68 | - Average 69 | - aws_dimensions: 70 | - DBInstanceIdentifier 71 | aws_metric_name: CPUCreditBalance 72 | aws_namespace: AWS/RDS 73 | aws_statistics: 74 | - Average 75 | - aws_dimensions: 76 | - DBInstanceIdentifier 77 | aws_metric_name: DiskQueueDepth 78 | aws_namespace: AWS/RDS 79 | aws_statistics: 80 | - Average 81 | - aws_dimensions: 82 | - DBInstanceIdentifier 83 | aws_metric_name: NetworkTransmitThroughput 84 | aws_namespace: AWS/RDS 85 | aws_statistics: 86 | - Average 87 | - aws_dimensions: 88 | - DBInstanceIdentifier 89 | aws_metric_name: NetworkReceiveThroughput 90 | aws_namespace: AWS/RDS 91 | aws_statistics: 92 | - Average 93 | - aws_dimensions: 94 | - DBInstanceIdentifier 95 | aws_metric_name: TransactionLogsDiskUsage 96 | aws_namespace: AWS/RDS 97 | aws_statistics: 98 | - Average 99 | -------------------------------------------------------------------------------- /examples/Redshift.yml: -------------------------------------------------------------------------------- 1 | region: us-east-1 2 | metrics: 3 | - aws_dimensions: 4 | - ClusterIdentifier 5 | aws_metric_name: HealthStatus 6 | aws_namespace: AWS/Redshift 7 | aws_statistics: 8 | - Average 9 | - aws_dimensions: 10 | - ClusterIdentifier 11 | aws_metric_name: CPUUtilization 12 | aws_namespace: AWS/Redshift 13 | aws_statistics: 14 | - Average 15 | - aws_dimensions: 16 | - ClusterIdentifier 17 | aws_metric_name: DatabaseConnections 18 | aws_namespace: AWS/Redshift 19 | aws_statistics: 20 | - Average 21 | - aws_dimensions: 22 | - ClusterIdentifier 23 | aws_metric_name: MaintenanceMode 24 | aws_namespace: AWS/Redshift 25 | aws_statistics: 26 | - Average 27 | - aws_dimensions: 28 | - ClusterIdentifier 29 | aws_metric_name: NetworkReceiveThroughput$AVG 30 | aws_namespace: AWS/Redshift 31 | - aws_dimensions: 32 | - ClusterIdentifier 33 | aws_metric_name: NetworkTransmitThroughput 34 | aws_namespace: AWS/Redshift 35 | aws_statistics: 36 | - Average 37 | - aws_dimensions: 38 | - ClusterIdentifier 39 | aws_metric_name: ReadIOPS 40 | aws_namespace: AWS/Redshift 41 | aws_statistics: 42 | - Maximum 43 | - aws_dimensions: 44 | - ClusterIdentifier 45 | aws_metric_name: WriteIOPS 46 | aws_namespace: AWS/Redshift 47 | aws_statistics: 48 | - Maximum 49 | - aws_dimensions: 50 | - ClusterIdentifier 51 | aws_metric_name: ReadLatency 52 | aws_namespace: AWS/Redshift 53 | aws_statistics: 54 | - Maximum 55 | - aws_dimensions: 56 | - ClusterIdentifier 57 | aws_metric_name: WriteLatency 58 | aws_namespace: AWS/Redshift 59 | aws_statistics: 60 | - Maximum 61 | - aws_dimensions: 62 | - ClusterIdentifier 63 | aws_metric_name: ReadThroughput 64 | aws_namespace: AWS/Redshift 65 | aws_statistics: 66 | - Average 67 | - aws_dimensions: 68 | - ClusterIdentifier 69 | aws_metric_name: WriteThroughput 70 | aws_namespace: AWS/Redshift 71 | aws_statistics: 72 | - Average 73 | - aws_dimensions: 74 | - ClusterIdentifier 75 | aws_metric_name: QueryDuration 76 | aws_namespace: AWS/Redshift 77 | aws_statistics: 78 | - Average 79 | - aws_dimensions: 80 | - ClusterIdentifier 81 | aws_metric_name: QueriesCompletedPerSecond 82 | aws_namespace: AWS/Redshift 83 | aws_statistics: 84 | - Average 85 | -------------------------------------------------------------------------------- /examples/Route53.yml: -------------------------------------------------------------------------------- 1 | region: us-east-1 2 | metrics: 3 | - aws_dimensions: 4 | - HealthCheckId 5 | aws_metric_name: TimeToFirstByte 6 | aws_namespace: AWS/Route53 7 | aws_statistics: 8 | - Average 9 | - aws_dimensions: 10 | - HealthCheckId 11 | aws_metric_name: HealthCheckPercentageHealthy 12 | aws_namespace: AWS/Route53 13 | aws_statistics: 14 | - Average 15 | - aws_dimensions: 16 | - HealthCheckId 17 | aws_metric_name: HealthCheckStatus 18 | aws_namespace: AWS/Route53 19 | aws_statistics: 20 | - Minimum 21 | - aws_dimensions: 22 | - HealthCheckId 23 | aws_metric_name: ChildHealthCheckHealthyCount 24 | aws_namespace: AWS/Route53 25 | aws_statistics: 26 | - Average 27 | - aws_dimensions: 28 | - HealthCheckId 29 | aws_metric_name: ConnectionTime 30 | aws_namespace: AWS/Route53 31 | aws_statistics: 32 | - Average 33 | - aws_dimensions: 34 | - HealthCheckId 35 | aws_metric_name: SSLHandshakeTime 36 | aws_namespace: AWS/Route53 37 | aws_statistics: 38 | - Average 39 | -------------------------------------------------------------------------------- /examples/S3.yml: -------------------------------------------------------------------------------- 1 | region: us-east-1 2 | metrics: 3 | - aws_dimensions: 4 | - BucketName 5 | - FilterId 6 | aws_metric_name: 4xxErrors 7 | aws_namespace: AWS/S3 8 | aws_statistics: 9 | - Sum 10 | - aws_dimensions: 11 | - BucketName 12 | - FilterId 13 | aws_metric_name: 5xxErrors 14 | aws_namespace: AWS/S3 15 | aws_statistics: 16 | - Sum 17 | - aws_dimensions: 18 | - BucketName 19 | - FilterId 20 | aws_metric_name: AllRequests 21 | aws_namespace: AWS/S3 22 | aws_statistics: 23 | - Sum 24 | - aws_dimensions: 25 | - BucketName 26 | - FilterId 27 | aws_metric_name: FirstByteLatency 28 | aws_namespace: AWS/S3 29 | aws_statistics: 30 | - Average 31 | - aws_dimensions: 32 | - BucketName 33 | - FilterId 34 | aws_metric_name: TotalRequestLatency 35 | aws_namespace: AWS/S3 36 | aws_statistics: 37 | - Average 38 | - aws_dimensions: 39 | - BucketName 40 | - FilterId 41 | aws_metric_name: BytesDownloaded 42 | aws_namespace: AWS/S3 43 | aws_statistics: 44 | - Sum 45 | - Average 46 | - aws_dimensions: 47 | - BucketName 48 | - FilterId 49 | aws_metric_name: BytesUploaded 50 | aws_namespace: AWS/S3 51 | aws_statistics: 52 | - Sum 53 | - Average 54 | - aws_dimensions: 55 | - BucketName 56 | - FilterId 57 | aws_metric_name: PutRequests 58 | aws_namespace: AWS/S3 59 | aws_statistics: 60 | - Sum 61 | - aws_dimensions: 62 | - BucketName 63 | - FilterId 64 | aws_metric_name: ListRequests 65 | aws_namespace: AWS/S3 66 | aws_statistics: 67 | - Sum 68 | - aws_dimensions: 69 | - BucketName 70 | - FilterId 71 | aws_metric_name: HeadRequests 72 | aws_namespace: AWS/S3 73 | aws_statistics: 74 | - Sum 75 | - aws_dimensions: 76 | - BucketName 77 | - FilterId 78 | aws_metric_name: GetRequests 79 | aws_namespace: AWS/S3 80 | aws_statistics: 81 | - Sum 82 | - aws_namespace: AWS/S3 83 | aws_metric_name: BucketSizeBytes 84 | aws_dimensions: [BucketName, StorageType] 85 | aws_statistics: [Average] 86 | range_seconds: 172800 87 | period_seconds: 86400 88 | set_timestamp: false 89 | - aws_namespace: AWS/S3 90 | aws_metric_name: NumberOfObjects 91 | aws_dimensions: [BucketName, StorageType] 92 | aws_statistics: [Average] 93 | range_seconds: 172800 94 | period_seconds: 86400 95 | set_timestamp: false 96 | # In case you want to use some bucket level Tag to select buckets to monitor, 97 | # or to have additional `info` metric with all bucket Tags as labels, use `aws_tag_select`: 98 | aws_tag_select: 99 | tag_selections: 100 | Monitoring: ["enabled"] 101 | resource_type_selection: "s3:" 102 | resource_id_dimension: BucketName -------------------------------------------------------------------------------- /examples/SES.yml: -------------------------------------------------------------------------------- 1 | region: us-east-1 2 | metrics: 3 | - aws_namespace: AWS/SES 4 | aws_metric_name: Send 5 | - aws_namespace: AWS/SES 6 | aws_metric_name: Delivery 7 | - aws_namespace: AWS/SES 8 | aws_metric_name: Bounce 9 | - aws_namespace: AWS/SES 10 | aws_metric_name: Complaint 11 | - aws_namespace: AWS/SES 12 | aws_metric_name: Reputation.BounceRate 13 | - aws_namespace: AWS/SES 14 | aws_metric_name: Reputation.ComplaintRate 15 | -------------------------------------------------------------------------------- /examples/SNS.yml: -------------------------------------------------------------------------------- 1 | region: us-east-1 2 | metrics: 3 | - aws_dimensions: 4 | - TopicName 5 | aws_metric_name: NumberOfMessagesPublished 6 | aws_namespace: AWS/SNS 7 | aws_statistics: 8 | - Sum 9 | - aws_dimensions: 10 | - TopicName 11 | aws_metric_name: NumberOfNotificationsDelivered 12 | aws_namespace: AWS/SNS 13 | aws_statistics: 14 | - Sum 15 | - aws_dimensions: 16 | - TopicName 17 | aws_metric_name: NumberOfNotificationsFailed 18 | aws_namespace: AWS/SNS 19 | aws_statistics: 20 | - Sum 21 | - aws_dimensions: 22 | - TopicName 23 | aws_metric_name: PublishSize 24 | aws_namespace: AWS/SNS 25 | aws_statistics: 26 | - Average 27 | - aws_dimensions: 28 | - TopicName 29 | aws_metric_name: NumberOfNotificationsFilteredOut 30 | aws_namespace: AWS/SNS 31 | aws_statistics: 32 | - Sum 33 | - aws_dimensions: 34 | - TopicName 35 | aws_metric_name: NumberOfNotificationsFilteredOut-InvalidAttributes 36 | aws_namespace: AWS/SNS 37 | aws_statistics: 38 | - Sum 39 | - aws_dimensions: 40 | - TopicName 41 | aws_metric_name: NumberOfNotificationsFilteredOut-NoMessageAttributes 42 | aws_namespace: AWS/SNS 43 | aws_statistics: 44 | - Sum 45 | -------------------------------------------------------------------------------- /examples/SQS.yml: -------------------------------------------------------------------------------- 1 | region: us-east-1 2 | metrics: 3 | - aws_dimensions: 4 | - QueueName 5 | aws_metric_name: NumberOfMessagesSent 6 | aws_namespace: AWS/SQS 7 | aws_statistics: 8 | - Average 9 | - aws_dimensions: 10 | - QueueName 11 | aws_metric_name: NumberOfMessagesReceived 12 | aws_namespace: AWS/SQS 13 | aws_statistics: 14 | - Average 15 | - aws_dimensions: 16 | - QueueName 17 | aws_metric_name: NumberOfEmptyReceives 18 | aws_namespace: AWS/SQS 19 | aws_statistics: 20 | - Average 21 | - aws_dimensions: 22 | - QueueName 23 | aws_metric_name: NumberOfMessagesDeleted 24 | aws_namespace: AWS/SQS 25 | aws_statistics: 26 | - Average 27 | - aws_dimensions: 28 | - QueueName 29 | aws_metric_name: ApproximateNumberOfMessagesDelayed 30 | aws_namespace: AWS/SQS 31 | aws_statistics: 32 | - Average 33 | - aws_dimensions: 34 | - QueueName 35 | aws_metric_name: ApproximateAgeOfOldestMessage 36 | aws_namespace: AWS/SQS 37 | aws_statistics: 38 | - Average 39 | - aws_dimensions: 40 | - QueueName 41 | aws_metric_name: ApproximateNumberOfMessagesNotVisible 42 | aws_namespace: AWS/SQS 43 | aws_statistics: 44 | - Average 45 | - aws_dimensions: 46 | - QueueName 47 | aws_metric_name: ApproximateNumberOfMessagesVisible 48 | aws_namespace: AWS/SQS 49 | aws_statistics: 50 | - Average 51 | -------------------------------------------------------------------------------- /examples/Sagemaker.yml: -------------------------------------------------------------------------------- 1 | region: us-east-1 2 | metrics: 3 | - aws_dimensions: 4 | - EndpointName 5 | - VariantName 6 | aws_metric_name: Invocation4XXErrors 7 | aws_namespace: AWS/SageMaker 8 | aws_statistics: 9 | - Sum 10 | - aws_dimensions: 11 | - EndpointName 12 | - VariantName 13 | aws_metric_name: Invocation5XXErrors 14 | aws_namespace: AWS/SageMaker 15 | aws_statistics: 16 | - Sum 17 | - aws_dimensions: 18 | - EndpointName 19 | - VariantName 20 | aws_metric_name: Invocations 21 | aws_namespace: AWS/SageMaker 22 | aws_statistics: 23 | - Sum 24 | - aws_dimensions: 25 | - EndpointName 26 | - VariantName 27 | aws_metric_name: InvocationsPerInstance 28 | aws_namespace: AWS/SageMaker 29 | aws_statistics: 30 | - Sum 31 | - aws_dimensions: 32 | - EndpointName 33 | - VariantName 34 | aws_metric_name: ModelLatency 35 | aws_namespace: AWS/SageMaker 36 | aws_statistics: 37 | - Average 38 | - aws_dimensions: 39 | - EndpointName 40 | - VariantName 41 | aws_metric_name: OverheadLatency 42 | aws_namespace: AWS/SageMaker 43 | aws_statistics: 44 | - Average 45 | - aws_dimensions: 46 | - EndpointName 47 | - VariantName 48 | aws_metric_name: OverallLatency 49 | aws_namespace: AWS/SageMaker 50 | aws_statistics: 51 | - Average 52 | -------------------------------------------------------------------------------- /examples/VPN.yml: -------------------------------------------------------------------------------- 1 | region: us-east-1 2 | metrics: 3 | - aws_dimensions: 4 | - VpnId 5 | - TunnelIpAddress 6 | aws_metric_name: TunnelState 7 | aws_namespace: AWS/VPN 8 | aws_statistics: 9 | - Average 10 | - aws_dimensions: 11 | - VpnId 12 | - TunnelIpAddress 13 | aws_metric_name: TunnelDataIn 14 | aws_namespace: AWS/VPN 15 | aws_statistics: 16 | - Sum 17 | - aws_dimensions: 18 | - VpnId 19 | - TunnelIpAddress 20 | aws_metric_name: TunnelDataOut 21 | aws_namespace: AWS/VPN 22 | aws_statistics: 23 | - Sum 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | -------------------------------------------------------------------------------- /examples/WAF.yml: -------------------------------------------------------------------------------- 1 | region: us-east-1 2 | metrics: 3 | - aws_dimensions: 4 | - Region 5 | - Rule 6 | - RuleGroup 7 | - WebACL 8 | aws_metric_name: AllowedRequests 9 | aws_namespace: AWS/WAF 10 | aws_statistics: 11 | - Sum 12 | - aws_dimensions: 13 | - Region 14 | - Rule 15 | - RuleGroup 16 | - WebACL 17 | aws_metric_name: BlockedRequests 18 | aws_namespace: AWS/WAF 19 | aws_statistics: 20 | - Sum 21 | - aws_dimensions: 22 | - Region 23 | - Rule 24 | - RuleGroup 25 | - WebACL 26 | aws_metric_name: CountedRequests 27 | aws_namespace: AWS/WAF 28 | aws_statistics: 29 | - Sum 30 | - aws_dimensions: 31 | - Region 32 | - Rule 33 | - RuleGroup 34 | - WebACL 35 | aws_metric_name: PassedRequests 36 | aws_namespace: AWS/WAF 37 | aws_statistics: 38 | - Sum 39 | - aws_dimensions: 40 | - Region 41 | - RuleGroup 42 | - WebACL 43 | - LabelNamespace 44 | - Label 45 | aws_metric_name: AllowedRequests 46 | aws_namespace: AWS/WAF 47 | aws_statistics: 48 | - Sum 49 | - aws_dimensions: 50 | - Region 51 | - RuleGroup 52 | - WebACL 53 | - LabelNamespace 54 | - Label 55 | aws_metric_name: BlockedRequests 56 | aws_namespace: AWS/WAF 57 | aws_statistics: 58 | - Sum 59 | - aws_dimensions: 60 | - Region 61 | - RuleGroup 62 | - WebACL 63 | - LabelNamespace 64 | - Label 65 | aws_metric_name: CountedRequests 66 | aws_namespace: AWS/WAF 67 | aws_statistics: 68 | - Sum 69 | - aws_dimensions: 70 | - Region 71 | - BotCategory 72 | - WebACL 73 | aws_metric_name: SampleAllowedRequests 74 | aws_namespace: AWS/WAF 75 | aws_statistics: 76 | - Sum 77 | - aws_dimensions: 78 | - Region 79 | - BotCategory 80 | - WebACL 81 | aws_metric_name: SampleBlockedRequests 82 | aws_namespace: AWS/WAF 83 | aws_statistics: 84 | - Sum 85 | - aws_dimensions: 86 | aws_metric_name: DDoSDetected 87 | aws_namespace: AWS/WAF 88 | aws_statistics: 89 | - Sum 90 | - aws_dimensions: 91 | - ACKFlood 92 | - ChargenReflection 93 | - DNSReflection 94 | - GenericUDPReflection 95 | - MemcachedReflection 96 | - MSSQLReflection 97 | - NetBIOSReflection 98 | - NTPReflection 99 | - PortMapper 100 | - RequestFlood 101 | - RIPReflection 102 | - SNMPReflection 103 | - SSDPReflection 104 | - SYNFlood 105 | - UDPFragment 106 | - UDPTraffic 107 | - UDPReflection 108 | aws_metric_name: DDoSAttackBitsPerSecond 109 | aws_namespace: AWS/WAF 110 | aws_statistics: 111 | - Sum 112 | - aws_dimensions: 113 | - ACKFlood 114 | - ChargenReflection 115 | - DNSReflection 116 | - GenericUDPReflection 117 | - MemcachedReflection 118 | - MSSQLReflection 119 | - NetBIOSReflection 120 | - NTPReflection 121 | - PortMapper 122 | - RequestFlood 123 | - RIPReflection 124 | - SNMPReflection 125 | - SSDPReflection 126 | - SYNFlood 127 | - UDPFragment 128 | - UDPTraffic 129 | - UDPReflection 130 | aws_metric_name: DDoSAttackPacketsPerSecond 131 | aws_namespace: AWS/WAF 132 | aws_statistics: 133 | - Sum 134 | - aws_dimensions: 135 | - ACKFlood 136 | - ChargenReflection 137 | - DNSReflection 138 | - GenericUDPReflection 139 | - MemcachedReflection 140 | - MSSQLReflection 141 | - NetBIOSReflection 142 | - NTPReflection 143 | - PortMapper 144 | - RequestFlood 145 | - RIPReflection 146 | - SNMPReflection 147 | - SSDPReflection 148 | - SYNFlood 149 | - UDPFragment 150 | - UDPTraffic 151 | - UDPReflection 152 | aws_metric_name: DDoSAttackRequestsPerSecond 153 | aws_namespace: AWS/WAF 154 | aws_statistics: 155 | - Sum 156 | - aws_dimensions: 157 | - ResourceArn 158 | - MitigationAction 159 | aws_metric_name: VolumePacketsPerSecond 160 | aws_namespace: AWS/WAF 161 | aws_statistics: 162 | - Sum 163 | - aws_dimensions: 164 | - ResourceArn 165 | - Protocol 166 | - SourceIp 167 | aws_metric_name: VolumePacketsPerSecond 168 | aws_namespace: AWS/WAF 169 | aws_statistics: 170 | - Sum 171 | - aws_dimensions: 172 | - ResourceArn 173 | - Protocol 174 | - SourceIp 175 | aws_metric_name: VolumeBitsPerSecond 176 | aws_namespace: AWS/WAF 177 | aws_statistics: 178 | - Sum 179 | -------------------------------------------------------------------------------- /examples/WAFV2.yml: -------------------------------------------------------------------------------- 1 | region: us-east-1 2 | metrics: 3 | - aws_dimensions: 4 | - Region 5 | - Rule 6 | - RuleGroup 7 | - WebACL 8 | aws_metric_name: AllowedRequests 9 | aws_namespace: AWS/WAFV2 10 | aws_statistics: 11 | - Sum 12 | # In case you want to use some tag to select web acls to monitor, or to have additional `info` metric 13 | # with all web acl tags as labels, use `aws_tag_select`. 14 | # Since the WebACL dimension doesn't follow the convention for how to extract resource ids from ARN 15 | # `arn_resource_id_regexp` is specified with an alternative regular expression. 16 | aws_tag_select: 17 | resource_type_selection: wafv2:regional/webacl 18 | resource_id_dimension: WebACL 19 | arn_resource_id_regexp: "([^/]+)/[^/]+$" 20 | tag_selections: 21 | Environment: 22 | - production 23 | - aws_dimensions: 24 | - Region 25 | - Rule 26 | - RuleGroup 27 | - WebACL 28 | aws_metric_name: BlockedRequests 29 | aws_namespace: AWS/WAFV2 30 | aws_statistics: 31 | - Sum 32 | - aws_dimensions: 33 | - Region 34 | - Rule 35 | - RuleGroup 36 | - WebACL 37 | aws_metric_name: CountedRequests 38 | aws_namespace: AWS/WAFV2 39 | aws_statistics: 40 | - Sum 41 | - aws_dimensions: 42 | - Region 43 | - Rule 44 | - RuleGroup 45 | - WebACL 46 | aws_metric_name: PassedRequests 47 | aws_namespace: AWS/WAFV2 48 | aws_statistics: 49 | - Sum 50 | - aws_dimensions: 51 | - Region 52 | - RuleGroup 53 | - WebACL 54 | - LabelNamespace 55 | - Label 56 | aws_metric_name: AllowedRequests 57 | aws_namespace: AWS/WAFV2 58 | aws_statistics: 59 | - Sum 60 | - aws_dimensions: 61 | - Region 62 | - RuleGroup 63 | - WebACL 64 | - LabelNamespace 65 | - Label 66 | aws_metric_name: BlockedRequests 67 | aws_namespace: AWS/WAFV2 68 | aws_statistics: 69 | - Sum 70 | - aws_dimensions: 71 | - Region 72 | - RuleGroup 73 | - WebACL 74 | - LabelNamespace 75 | - Label 76 | aws_metric_name: CountedRequests 77 | aws_namespace: AWS/WAFV2 78 | aws_statistics: 79 | - Sum 80 | - aws_dimensions: 81 | - Region 82 | - BotCategory 83 | - WebACL 84 | aws_metric_name: SampleAllowedRequests 85 | aws_namespace: AWS/WAFV2 86 | aws_statistics: 87 | - Sum 88 | - aws_dimensions: 89 | - Region 90 | - BotCategory 91 | - WebACL 92 | aws_metric_name: SampleBlockedRequests 93 | aws_namespace: AWS/WAFV2 94 | aws_statistics: 95 | - Sum 96 | - aws_dimensions: 97 | aws_metric_name: DDoSDetected 98 | aws_namespace: AWS/WAFV2 99 | aws_statistics: 100 | - Sum 101 | - aws_dimensions: 102 | - ACKFlood 103 | - ChargenReflection 104 | - DNSReflection 105 | - GenericUDPReflection 106 | - MemcachedReflection 107 | - MSSQLReflection 108 | - NetBIOSReflection 109 | - NTPReflection 110 | - PortMapper 111 | - RequestFlood 112 | - RIPReflection 113 | - SNMPReflection 114 | - SSDPReflection 115 | - SYNFlood 116 | - UDPFragment 117 | - UDPTraffic 118 | - UDPReflection 119 | aws_metric_name: DDoSAttackBitsPerSecond 120 | aws_namespace: AWS/WAFV2 121 | aws_statistics: 122 | - Sum 123 | - aws_dimensions: 124 | - ACKFlood 125 | - ChargenReflection 126 | - DNSReflection 127 | - GenericUDPReflection 128 | - MemcachedReflection 129 | - MSSQLReflection 130 | - NetBIOSReflection 131 | - NTPReflection 132 | - PortMapper 133 | - RequestFlood 134 | - RIPReflection 135 | - SNMPReflection 136 | - SSDPReflection 137 | - SYNFlood 138 | - UDPFragment 139 | - UDPTraffic 140 | - UDPReflection 141 | aws_metric_name: DDoSAttackPacketsPerSecond 142 | aws_namespace: AWS/WAFV2 143 | aws_statistics: 144 | - Sum 145 | - aws_dimensions: 146 | - ACKFlood 147 | - ChargenReflection 148 | - DNSReflection 149 | - GenericUDPReflection 150 | - MemcachedReflection 151 | - MSSQLReflection 152 | - NetBIOSReflection 153 | - NTPReflection 154 | - PortMapper 155 | - RequestFlood 156 | - RIPReflection 157 | - SNMPReflection 158 | - SSDPReflection 159 | - SYNFlood 160 | - UDPFragment 161 | - UDPTraffic 162 | - UDPReflection 163 | aws_metric_name: DDoSAttackRequestsPerSecond 164 | aws_namespace: AWS/WAFV2 165 | aws_statistics: 166 | - Sum 167 | - aws_dimensions: 168 | - ResourceArn 169 | - MitigationAction 170 | aws_metric_name: VolumePacketsPerSecond 171 | aws_namespace: AWS/WAFV2 172 | aws_statistics: 173 | - Sum 174 | - aws_dimensions: 175 | - ResourceArn 176 | - Protocol 177 | - SourceIp 178 | aws_metric_name: VolumePacketsPerSecond 179 | aws_namespace: AWS/WAFV2 180 | aws_statistics: 181 | - Sum 182 | - aws_dimensions: 183 | - ResourceArn 184 | - Protocol 185 | - SourceIp 186 | aws_metric_name: VolumeBitsPerSecond 187 | aws_namespace: AWS/WAFV2 188 | aws_statistics: 189 | - Sum 190 | -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4.0.0 3 | 4 | io.prometheus.cloudwatch 5 | cloudwatch_exporter 6 | 0.16.1-SNAPSHOT 7 | 8 | An exporter for AWS CloudWatch metrics, for use with Prometheus. 9 | 10 | http://github.com/prometheus/cloudwatch_exporter 11 | 12 | 13 | org.sonatype.oss 14 | oss-parent 15 | 7 16 | 17 | 18 | 19 | 20 | ossrh 21 | https://oss.sonatype.org/content/repositories/snapshots 22 | 23 | 24 | ossrh 25 | https://oss.sonatype.org/service/local/staging/deploy/maven2/ 26 | 27 | 28 | 29 | 30 | 31 | The Apache Software License, Version 2.0 32 | http://www.apache.org/licenses/LICENSE-2.0.txt 33 | repo 34 | 35 | 36 | 37 | 38 | scm:git:git@github.com:prometheus/cloudwatch_exporter.git 39 | scm:git:git@github.com:prometheus/cloudwatch_exporter.git 40 | git@github.com:prometheus/cloudwatch_exporter.git 41 | HEAD 42 | 43 | 44 | 45 | yyyy-MM-dd 46 | UTF-8 47 | UTF-8 48 | ${maven.build.timestamp} 49 | 2.29.40 50 | 0.16.0 51 | 52 | 53 | 54 | 55 | software.amazon.awssdk 56 | cloudwatch 57 | ${software.amazon.awssdk.version} 58 | 59 | 60 | software.amazon.awssdk 61 | sts 62 | ${software.amazon.awssdk.version} 63 | 64 | 65 | software.amazon.awssdk 66 | resourcegroupstaggingapi 67 | ${software.amazon.awssdk.version} 68 | 69 | 70 | commons-codec 71 | commons-codec 72 | 1.17.1 73 | 74 | 75 | org.slf4j 76 | slf4j-jdk14 77 | 2.0.16 78 | 79 | 80 | org.yaml 81 | snakeyaml 82 | 2.3 83 | 84 | 85 | io.prometheus 86 | simpleclient 87 | ${io.prometheus.version} 88 | 89 | 90 | io.prometheus 91 | simpleclient_servlet_jakarta 92 | ${io.prometheus.version} 93 | 94 | 95 | io.prometheus 96 | simpleclient_hotspot 97 | ${io.prometheus.version} 98 | 99 | 100 | org.eclipse.jetty 101 | jetty-servlet 102 | 11.0.24 103 | 104 | 105 | com.github.ben-manes.caffeine 106 | caffeine 107 | 3.1.8 108 | 109 | 110 | 111 | junit 112 | junit 113 | 4.13.2 114 | test 115 | 116 | 117 | org.mockito 118 | mockito-core 119 | 5.14.2 120 | test 121 | 122 | 123 | org.hamcrest 124 | hamcrest 125 | 3.0 126 | test 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | src/main/resources 135 | true 136 | 137 | 138 | 139 | 140 | org.apache.maven.plugins 141 | maven-compiler-plugin 142 | 3.13.0 143 | 144 | 11 145 | 146 | 147 | 148 | 149 | maven-assembly-plugin 150 | 151 | 152 | 153 | io.prometheus.cloudwatch.WebServer 154 | 155 | 156 | 157 | jar-with-dependencies 158 | 159 | 160 | 161 | 162 | make-assembly 163 | package 164 | 165 | single 166 | 167 | 168 | 169 | 170 | 171 | maven-release-plugin 172 | org.apache.maven.plugins 173 | 3.1.1 174 | 175 | true 176 | false 177 | release 178 | deploy 179 | v@{project.version} 180 | 181 | 182 | 183 | maven-deploy-plugin 184 | org.apache.maven.plugins 185 | 3.1.3 186 | 187 | 188 | org.apache.felix 189 | maven-bundle-plugin 190 | 6.0.0 191 | true 192 | 193 | 194 | org.apache.maven.plugins 195 | maven-surefire-plugin 196 | 3.5.2 197 | 198 | -Djdk.net.URLClassPath.disableClassPathURLCheck=true 199 | 200 | 201 | 202 | org.apache.maven.plugins 203 | maven-javadoc-plugin 204 | 3.11.2 205 | 206 | UTF-8 207 | UTF-8 208 | true 209 | 8 210 | ${java.home}/bin/javadoc 211 | 212 | 213 | 214 | generate-javadoc-site-report 215 | site 216 | 217 | javadoc 218 | 219 | 220 | 221 | 222 | 223 | com.spotify.fmt 224 | fmt-maven-plugin 225 | 2.25 226 | 227 | 228 | 229 | format 230 | 231 | 232 | 233 | 234 | 235 | 236 | 237 | 238 | 239 | release 240 | 241 | 242 | 243 | org.apache.maven.plugins 244 | maven-gpg-plugin 245 | 3.2.7 246 | 247 | 248 | sign-artifacts 249 | verify 250 | 251 | sign 252 | 253 | 254 | 255 | 256 | 257 | org.apache.maven.plugins 258 | maven-source-plugin 259 | 3.3.1 260 | 261 | 262 | attach-sources 263 | 264 | jar-no-fork 265 | 266 | 267 | 268 | 269 | 270 | org.apache.maven.plugins 271 | maven-javadoc-plugin 272 | 3.11.2 273 | 274 | 275 | attach-javadocs 276 | 277 | jar 278 | 279 | 280 | 281 | 282 | 283 | 284 | 285 | 286 | 287 | -------------------------------------------------------------------------------- /src/main/java/io/prometheus/cloudwatch/BuildInfoCollector.java: -------------------------------------------------------------------------------- 1 | package io.prometheus.cloudwatch; 2 | 3 | import io.prometheus.client.Collector; 4 | import java.io.IOException; 5 | import java.util.ArrayList; 6 | import java.util.List; 7 | import java.util.Properties; 8 | import java.util.logging.Level; 9 | import java.util.logging.Logger; 10 | 11 | public class BuildInfoCollector extends Collector { 12 | private static final Logger LOGGER = Logger.getLogger(CloudWatchCollector.class.getName()); 13 | 14 | public List collect() { 15 | List mfs = new ArrayList<>(); 16 | List samples; 17 | List labelNames = new ArrayList<>(); 18 | List labelValues = new ArrayList<>(); 19 | 20 | String buildVersion = ""; 21 | String releaseDate = ""; 22 | try { 23 | final Properties properties = new Properties(); 24 | properties.load( 25 | CloudWatchCollector.class.getClassLoader().getResourceAsStream(".properties")); 26 | buildVersion = properties.getProperty("BuildVersion"); 27 | releaseDate = properties.getProperty("ReleaseDate"); 28 | 29 | } catch (IOException e) { 30 | buildVersion = "unknown"; 31 | releaseDate = "unknown"; 32 | LOGGER.log(Level.WARNING, "CloudWatch build info scrape failed", e); 33 | } 34 | 35 | labelNames.add("build_version"); 36 | labelValues.add(buildVersion); 37 | labelNames.add("release_date"); 38 | labelValues.add(releaseDate); 39 | 40 | samples = new ArrayList<>(); 41 | samples.add( 42 | new MetricFamilySamples.Sample( 43 | "cloudwatch_exporter_build_info", labelNames, labelValues, 1)); 44 | mfs.add( 45 | new MetricFamilySamples( 46 | "cloudwatch_exporter_build_info", 47 | Type.GAUGE, 48 | "Non-zero if build info scrape failed.", 49 | samples)); 50 | 51 | return mfs; 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /src/main/java/io/prometheus/cloudwatch/CachingDimensionSource.java: -------------------------------------------------------------------------------- 1 | package io.prometheus.cloudwatch; 2 | 3 | import com.github.benmanes.caffeine.cache.Cache; 4 | import com.github.benmanes.caffeine.cache.Caffeine; 5 | import com.github.benmanes.caffeine.cache.Expiry; 6 | import java.time.Duration; 7 | import java.util.ArrayList; 8 | import java.util.List; 9 | import java.util.Map; 10 | import java.util.Objects; 11 | import java.util.function.Function; 12 | import java.util.stream.Collectors; 13 | 14 | final class CachingDimensionSource implements DimensionSource { 15 | 16 | private final DimensionSource delegate; 17 | private final Cache cache; 18 | 19 | /** 20 | * Create a new DimensionSource that will cache the results from another {@link DimensionSource} 21 | * 22 | * @param source 23 | * @param config - config used to configure the expiry (ttl) for entries in the cache 24 | * @return a new CachingDimensionSource 25 | */ 26 | CachingDimensionSource(DimensionSource source, DimensionCacheConfig config) { 27 | this.delegate = source; 28 | this.cache = 29 | Caffeine.newBuilder() 30 | .expireAfter(new DimensionExpiry(config.defaultExpiry, config.metricConfig)) 31 | .build(); 32 | } 33 | 34 | @Override 35 | public DimensionData getDimensions(MetricRule rule, List tagBasedResourceIds) { 36 | DimensionData cachedDimensions = 37 | this.cache.getIfPresent(new DimensionCacheKey(rule, tagBasedResourceIds)); 38 | if (cachedDimensions != null) { 39 | return cachedDimensions; 40 | } 41 | DimensionData dimensions = delegate.getDimensions(rule, tagBasedResourceIds); 42 | this.cache.put(new DimensionCacheKey(rule, tagBasedResourceIds), dimensions); 43 | return dimensions; 44 | } 45 | 46 | static class DimensionExpiry implements Expiry { 47 | 48 | private final Duration defaultExpiry; 49 | private final Map durationMap; 50 | 51 | public DimensionExpiry(Duration defaultExpiry, List expiryOverrides) { 52 | this.defaultExpiry = defaultExpiry; 53 | this.durationMap = 54 | expiryOverrides.stream() 55 | .collect(Collectors.toMap(Function.identity(), dcp -> dcp.listMetricsCacheTtl)); 56 | } 57 | 58 | @Override 59 | public long expireAfterCreate(DimensionCacheKey key, DimensionData value, long currentTime) { 60 | return durationMap.getOrDefault(key.rule, this.defaultExpiry).toNanos(); 61 | } 62 | 63 | @Override 64 | public long expireAfterUpdate( 65 | DimensionCacheKey key, DimensionData value, long currentTime, long currentDuration) { 66 | return currentDuration; 67 | } 68 | 69 | @Override 70 | public long expireAfterRead( 71 | DimensionCacheKey key, DimensionData value, long currentTime, long currentDuration) { 72 | return currentDuration; 73 | } 74 | } 75 | 76 | static class DimensionCacheConfig { 77 | final Duration defaultExpiry; 78 | final List metricConfig = new ArrayList<>(); 79 | 80 | DimensionCacheConfig(Duration defaultExpiry) { 81 | this.defaultExpiry = defaultExpiry; 82 | } 83 | 84 | /** 85 | * Add a MetricRule to be used to configure a custom TTL using the value from {@link 86 | * MetricRule#listMetricsCacheTtl} to override the default expiry 87 | * 88 | * @param metricRule 89 | * @return this 90 | */ 91 | DimensionCacheConfig addOverride(MetricRule metricRule) { 92 | this.metricConfig.add(metricRule); 93 | return this; 94 | } 95 | } 96 | 97 | static class DimensionCacheKey { 98 | private final MetricRule rule; 99 | private final List tagBasedResourceIds; 100 | 101 | DimensionCacheKey(MetricRule rule, List tagBasedResourceIds) { 102 | this.rule = rule; 103 | this.tagBasedResourceIds = tagBasedResourceIds; 104 | } 105 | 106 | @Override 107 | public boolean equals(Object o) { 108 | if (this == o) return true; 109 | if (o == null || getClass() != o.getClass()) return false; 110 | 111 | DimensionCacheKey that = (DimensionCacheKey) o; 112 | 113 | if (!Objects.equals(rule, that.rule)) return false; 114 | return Objects.equals(tagBasedResourceIds, that.tagBasedResourceIds); 115 | } 116 | 117 | @Override 118 | public int hashCode() { 119 | int result = rule != null ? rule.hashCode() : 0; 120 | result = 31 * result + (tagBasedResourceIds != null ? tagBasedResourceIds.hashCode() : 0); 121 | return result; 122 | } 123 | } 124 | } 125 | -------------------------------------------------------------------------------- /src/main/java/io/prometheus/cloudwatch/DataGetter.java: -------------------------------------------------------------------------------- 1 | package io.prometheus.cloudwatch; 2 | 3 | import java.time.Instant; 4 | import java.util.HashMap; 5 | import java.util.List; 6 | import java.util.Map; 7 | import software.amazon.awssdk.services.cloudwatch.model.Dimension; 8 | import software.amazon.awssdk.services.cloudwatch.model.Statistic; 9 | 10 | interface DataGetter { 11 | MetricRuleData metricRuleDataFor(List dimensions); 12 | 13 | class MetricRuleData { 14 | Map statisticValues; 15 | Map extendedValues; 16 | Instant timestamp; 17 | 18 | String unit; 19 | 20 | MetricRuleData(Instant timestamp, String unit) { 21 | this.timestamp = timestamp; 22 | this.unit = unit; 23 | this.statisticValues = new HashMap<>(); 24 | this.extendedValues = new HashMap<>(); 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/main/java/io/prometheus/cloudwatch/DefaultDimensionSource.java: -------------------------------------------------------------------------------- 1 | package io.prometheus.cloudwatch; 2 | 3 | import io.prometheus.client.Counter; 4 | import java.util.ArrayList; 5 | import java.util.List; 6 | import java.util.Map; 7 | import java.util.Set; 8 | import java.util.logging.Logger; 9 | import java.util.regex.Pattern; 10 | import software.amazon.awssdk.services.cloudwatch.CloudWatchClient; 11 | import software.amazon.awssdk.services.cloudwatch.model.Dimension; 12 | import software.amazon.awssdk.services.cloudwatch.model.DimensionFilter; 13 | import software.amazon.awssdk.services.cloudwatch.model.ListMetricsRequest; 14 | import software.amazon.awssdk.services.cloudwatch.model.ListMetricsResponse; 15 | import software.amazon.awssdk.services.cloudwatch.model.Metric; 16 | 17 | final class DefaultDimensionSource implements DimensionSource { 18 | 19 | private static final Logger LOGGER = Logger.getLogger(DefaultDimensionSource.class.getName()); 20 | private final Counter cloudwatchRequests; 21 | private final CloudWatchClient cloudWatchClient; 22 | 23 | public DefaultDimensionSource(CloudWatchClient cloudWatchClient, Counter cloudwatchRequests) { 24 | this.cloudWatchClient = cloudWatchClient; 25 | this.cloudwatchRequests = cloudwatchRequests; 26 | } 27 | 28 | public DimensionData getDimensions(MetricRule rule, List tagBasedResourceIds) { 29 | if (rule.awsDimensions != null 30 | && rule.awsDimensionSelect != null 31 | && !rule.awsDimensions.isEmpty() 32 | && rule.awsDimensions.size() == rule.awsDimensionSelect.size() 33 | && rule.awsDimensionSelect.keySet().containsAll(rule.awsDimensions) 34 | && rule.awsTagSelect == null) { 35 | // The full list of dimensions is known so no need to request it from cloudwatch. 36 | return new DimensionData(permuteDimensions(rule.awsDimensions, rule.awsDimensionSelect)); 37 | } else { 38 | return new DimensionData(listDimensions(rule, tagBasedResourceIds, cloudWatchClient)); 39 | } 40 | } 41 | 42 | private List> permuteDimensions( 43 | List dimensions, Map> dimensionValues) { 44 | ArrayList> result = new ArrayList<>(); 45 | 46 | if (dimensions.isEmpty()) { 47 | result.add(new ArrayList<>()); 48 | } else { 49 | List dimensionsCopy = new ArrayList<>(dimensions); 50 | String dimensionName = dimensionsCopy.remove(dimensionsCopy.size() - 1); 51 | for (List permutation : permuteDimensions(dimensionsCopy, dimensionValues)) { 52 | for (String dimensionValue : dimensionValues.get(dimensionName)) { 53 | Dimension.Builder dimensionBuilder = Dimension.builder(); 54 | dimensionBuilder.value(dimensionValue); 55 | dimensionBuilder.name(dimensionName); 56 | ArrayList permutationCopy = new ArrayList<>(permutation); 57 | permutationCopy.add(dimensionBuilder.build()); 58 | result.add(permutationCopy); 59 | } 60 | } 61 | } 62 | return result; 63 | } 64 | 65 | private List> listDimensions( 66 | MetricRule rule, List tagBasedResourceIds, CloudWatchClient cloudWatchClient) { 67 | List> dimensions = new ArrayList<>(); 68 | if (rule.awsDimensions == null) { 69 | dimensions.add(new ArrayList<>()); 70 | return dimensions; 71 | } 72 | 73 | ListMetricsRequest.Builder requestBuilder = ListMetricsRequest.builder(); 74 | requestBuilder.namespace(rule.awsNamespace); 75 | requestBuilder.metricName(rule.awsMetricName); 76 | 77 | // 10800 seconds is 3 hours, this setting causes metrics older than 3 hours to not be listed 78 | if (rule.rangeSeconds < 10800) { 79 | requestBuilder.recentlyActive("PT3H"); 80 | } 81 | 82 | List dimensionFilters = new ArrayList<>(); 83 | for (String dimension : rule.awsDimensions) { 84 | dimensionFilters.add(DimensionFilter.builder().name(dimension).build()); 85 | } 86 | requestBuilder.dimensions(dimensionFilters); 87 | 88 | String nextToken = null; 89 | do { 90 | requestBuilder.nextToken(nextToken); 91 | ListMetricsResponse response = cloudWatchClient.listMetrics(requestBuilder.build()); 92 | cloudwatchRequests.labels("listMetrics", rule.awsNamespace).inc(); 93 | for (Metric metric : response.metrics()) { 94 | if (metric.dimensions().size() != dimensionFilters.size()) { 95 | // AWS returns all the metrics with dimensions beyond the ones we ask for, 96 | // so filter them out. 97 | continue; 98 | } 99 | if (useMetric(rule, tagBasedResourceIds, metric)) { 100 | dimensions.add(metric.dimensions()); 101 | } 102 | } 103 | nextToken = response.nextToken(); 104 | } while (nextToken != null); 105 | if (rule.warnOnEmptyListDimensions && dimensions.isEmpty()) { 106 | LOGGER.warning( 107 | String.format( 108 | "(listDimensions) ignoring metric %s:%s due to dimensions mismatch", 109 | rule.awsNamespace, rule.awsMetricName)); 110 | } 111 | return dimensions; 112 | } 113 | 114 | /** 115 | * Check if a metric should be used according to `aws_dimension_select`, 116 | * `aws_dimension_select_regex` and dynamic `aws_tag_select` 117 | */ 118 | private boolean useMetric(MetricRule rule, List tagBasedResourceIds, Metric metric) { 119 | if (rule.awsDimensionSelect != null && !metricsIsInAwsDimensionSelect(rule, metric)) { 120 | return false; 121 | } 122 | if (rule.awsDimensionSelectRegex != null && !metricIsInAwsDimensionSelectRegex(rule, metric)) { 123 | return false; 124 | } 125 | if (rule.awsTagSelect != null && !metricIsInAwsTagSelect(rule, tagBasedResourceIds, metric)) { 126 | return false; 127 | } 128 | return true; 129 | } 130 | 131 | /** Check if a metric is matched in `aws_dimension_select` */ 132 | private boolean metricsIsInAwsDimensionSelect(MetricRule rule, Metric metric) { 133 | Set dimensionSelectKeys = rule.awsDimensionSelect.keySet(); 134 | for (Dimension dimension : metric.dimensions()) { 135 | String dimensionName = dimension.name(); 136 | String dimensionValue = dimension.value(); 137 | if (dimensionSelectKeys.contains(dimensionName)) { 138 | List allowedDimensionValues = rule.awsDimensionSelect.get(dimensionName); 139 | if (!allowedDimensionValues.contains(dimensionValue)) { 140 | return false; 141 | } 142 | } 143 | } 144 | return true; 145 | } 146 | 147 | /** Check if a metric is matched in `aws_dimension_select_regex` */ 148 | private boolean metricIsInAwsDimensionSelectRegex(MetricRule rule, Metric metric) { 149 | Set dimensionSelectRegexKeys = rule.awsDimensionSelectRegex.keySet(); 150 | for (Dimension dimension : metric.dimensions()) { 151 | String dimensionName = dimension.name(); 152 | String dimensionValue = dimension.value(); 153 | if (dimensionSelectRegexKeys.contains(dimensionName)) { 154 | List allowedDimensionValues = rule.awsDimensionSelectRegex.get(dimensionName); 155 | if (!regexListMatch(allowedDimensionValues, dimensionValue)) { 156 | return false; 157 | } 158 | } 159 | } 160 | return true; 161 | } 162 | 163 | /** Check if any regex string in a list matches a given input value */ 164 | protected static boolean regexListMatch(List regexList, String input) { 165 | for (String regex : regexList) { 166 | if (Pattern.matches(regex, input)) { 167 | return true; 168 | } 169 | } 170 | return false; 171 | } 172 | 173 | /** Check if a metric is matched in `aws_tag_select` */ 174 | private boolean metricIsInAwsTagSelect( 175 | MetricRule rule, List tagBasedResourceIds, Metric metric) { 176 | if (rule.awsTagSelect.tagSelections == null) { 177 | return true; 178 | } 179 | for (Dimension dimension : metric.dimensions()) { 180 | String dimensionName = dimension.name(); 181 | String dimensionValue = dimension.value(); 182 | if (rule.awsTagSelect.resourceIdDimension.equals(dimensionName) 183 | && !tagBasedResourceIds.contains(dimensionValue)) { 184 | return false; 185 | } 186 | } 187 | return true; 188 | } 189 | } 190 | -------------------------------------------------------------------------------- /src/main/java/io/prometheus/cloudwatch/DimensionSource.java: -------------------------------------------------------------------------------- 1 | package io.prometheus.cloudwatch; 2 | 3 | import java.util.List; 4 | import software.amazon.awssdk.services.cloudwatch.model.Dimension; 5 | 6 | interface DimensionSource { 7 | 8 | DimensionData getDimensions(MetricRule rule, List tagBasedResourceIds); 9 | 10 | class DimensionData { 11 | private final List> dimensions; 12 | 13 | DimensionData(List> dimensions) { 14 | this.dimensions = dimensions; 15 | } 16 | 17 | List> getDimensions() { 18 | return dimensions; 19 | } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/main/java/io/prometheus/cloudwatch/DisallowHttpMethods.java: -------------------------------------------------------------------------------- 1 | package io.prometheus.cloudwatch; 2 | 3 | import java.util.EnumSet; 4 | import org.eclipse.jetty.http.HttpMethod; 5 | import org.eclipse.jetty.http.HttpStatus; 6 | import org.eclipse.jetty.server.Connector; 7 | import org.eclipse.jetty.server.HttpConfiguration; 8 | import org.eclipse.jetty.server.Request; 9 | 10 | class DisallowHttpMethods implements HttpConfiguration.Customizer { 11 | private final EnumSet disallowedMethods; 12 | 13 | public DisallowHttpMethods(EnumSet disallowedMethods) { 14 | this.disallowedMethods = disallowedMethods; 15 | } 16 | 17 | @Override 18 | public void customize(Connector connector, HttpConfiguration channelConfig, Request request) { 19 | HttpMethod httpMethod = HttpMethod.fromString(request.getMethod()); 20 | if (disallowedMethods.contains(httpMethod)) { 21 | request.setHandled(true); 22 | request.getResponse().setStatus(HttpStatus.METHOD_NOT_ALLOWED_405); 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/main/java/io/prometheus/cloudwatch/DynamicReloadServlet.java: -------------------------------------------------------------------------------- 1 | package io.prometheus.cloudwatch; 2 | 3 | import jakarta.servlet.ServletException; 4 | import jakarta.servlet.http.HttpServlet; 5 | import jakarta.servlet.http.HttpServletRequest; 6 | import jakarta.servlet.http.HttpServletResponse; 7 | import java.io.IOException; 8 | 9 | public class DynamicReloadServlet extends HttpServlet { 10 | private static final long serialVersionUID = 9078784531819993933L; 11 | private final CloudWatchCollector collector; 12 | 13 | public DynamicReloadServlet(CloudWatchCollector collector) { 14 | this.collector = collector; 15 | } 16 | 17 | static final String CONTENT_TYPE = "text/plain"; 18 | 19 | @Override 20 | protected void doGet(HttpServletRequest req, HttpServletResponse resp) 21 | throws ServletException, IOException { 22 | resp.setStatus(HttpServletResponse.SC_METHOD_NOT_ALLOWED); 23 | resp.setContentType(CONTENT_TYPE); 24 | try { 25 | resp.getWriter().print("Only POST requests allowed"); 26 | } catch (IOException e) { 27 | // Ignored 28 | } 29 | } 30 | 31 | @Override 32 | protected void doPost(HttpServletRequest req, HttpServletResponse resp) 33 | throws ServletException, IOException { 34 | try { 35 | collector.reloadConfig(); 36 | } catch (IOException e) { 37 | resp.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR); 38 | resp.setContentType(CONTENT_TYPE); 39 | try { 40 | resp.getWriter().print("Reloading config failed"); 41 | } catch (IOException ee) { 42 | // Ignored 43 | } 44 | return; 45 | } 46 | 47 | resp.setContentType(CONTENT_TYPE); 48 | try { 49 | resp.getWriter().print("OK"); 50 | } catch (IOException e) { 51 | // Ignored 52 | } 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /src/main/java/io/prometheus/cloudwatch/GetMetricDataDataGetter.java: -------------------------------------------------------------------------------- 1 | package io.prometheus.cloudwatch; 2 | 3 | import io.prometheus.client.Counter; 4 | import java.time.Instant; 5 | import java.util.ArrayList; 6 | import java.util.Date; 7 | import java.util.HashMap; 8 | import java.util.List; 9 | import java.util.Map; 10 | import java.util.UUID; 11 | import java.util.stream.Collectors; 12 | import software.amazon.awssdk.services.cloudwatch.CloudWatchClient; 13 | import software.amazon.awssdk.services.cloudwatch.model.Dimension; 14 | import software.amazon.awssdk.services.cloudwatch.model.GetMetricDataRequest; 15 | import software.amazon.awssdk.services.cloudwatch.model.GetMetricDataResponse; 16 | import software.amazon.awssdk.services.cloudwatch.model.Metric; 17 | import software.amazon.awssdk.services.cloudwatch.model.MetricDataQuery; 18 | import software.amazon.awssdk.services.cloudwatch.model.MetricDataResult; 19 | import software.amazon.awssdk.services.cloudwatch.model.MetricStat; 20 | import software.amazon.awssdk.services.cloudwatch.model.ScanBy; 21 | import software.amazon.awssdk.services.cloudwatch.model.Statistic; 22 | 23 | class GetMetricDataDataGetter implements DataGetter { 24 | 25 | private static final int MAX_QUERIES_PER_REQUEST = 500; 26 | // https://aws.amazon.com/cloudwatch/pricing/ 27 | private final long start; 28 | private final MetricRule rule; 29 | private final CloudWatchClient client; 30 | private final Counter apiRequestsCounter; 31 | private final Counter metricsRequestedCounter; 32 | private final Map results; 33 | private double metricRequestedForBilling; 34 | 35 | private static String dimensionToString(Dimension d) { 36 | return String.format("%s=%s", d.name(), d.value()); 37 | } 38 | 39 | private static String dimensionsToKey(List dimentions) { 40 | return dimentions.stream() 41 | .map(GetMetricDataDataGetter::dimensionToString) 42 | .sorted() 43 | .collect(Collectors.joining(",")); 44 | } 45 | 46 | private List buildStatsList(MetricRule rule) { 47 | List stats = new ArrayList<>(); 48 | if (rule.awsStatistics != null) { 49 | stats.addAll( 50 | rule.awsStatistics.stream().map(Statistic::toString).collect(Collectors.toList())); 51 | } 52 | if (rule.awsExtendedStatistics != null) { 53 | stats.addAll(rule.awsExtendedStatistics); 54 | } 55 | return stats; 56 | } 57 | 58 | private List buildMetricDataQueries( 59 | MetricRule rule, List> dimensionsList) { 60 | List queries = new ArrayList<>(); 61 | List stats = buildStatsList(rule); 62 | for (String stat : stats) { 63 | for (List dl : dimensionsList) { 64 | Metric metric = buildMetric(dl); 65 | MetricStat metricStat = buildMetricStat(stat, metric); 66 | MetricDataQuery query = buildQuery(stat, dl, metricStat); 67 | queries.add(query); 68 | } 69 | } 70 | metricRequestedForBilling += queries.size(); 71 | return queries; 72 | } 73 | 74 | private MetricDataQuery buildQuery(String stat, List dl, MetricStat metric) { 75 | // random id - we don't care about it 76 | String id = "i" + UUID.randomUUID().toString().replace("-", ""); 77 | MetricDataQuery.Builder builder = MetricDataQuery.builder(); 78 | builder.id(id); 79 | 80 | // important - used to locate back the results 81 | String label = MetricLabels.labelFor(stat, dl); 82 | builder.label(label); 83 | builder.metricStat(metric); 84 | return builder.build(); 85 | } 86 | 87 | private MetricStat buildMetricStat(String stat, Metric metric) { 88 | MetricStat.Builder builder = MetricStat.builder(); 89 | builder.period(rule.periodSeconds); 90 | builder.stat(stat); 91 | builder.metric(metric); 92 | return builder.build(); 93 | } 94 | 95 | private Metric buildMetric(List dl) { 96 | Metric.Builder builder = Metric.builder(); 97 | builder.namespace(rule.awsNamespace); 98 | builder.metricName(rule.awsMetricName); 99 | builder.dimensions(dl); 100 | return builder.build(); 101 | } 102 | 103 | public static List> partitionByMaxSize(List list, int maxPartitionSize) { 104 | List> partitions = new ArrayList<>(); 105 | List remaining = list; 106 | while (remaining.size() > 0) { 107 | if (remaining.size() < maxPartitionSize) { 108 | partitions.add(remaining); 109 | break; 110 | } else { 111 | partitions.add(remaining.subList(0, maxPartitionSize)); 112 | remaining = remaining.subList(maxPartitionSize, remaining.size()); 113 | } 114 | } 115 | return partitions; 116 | } 117 | 118 | private List buildMetricDataRequests( 119 | MetricRule rule, List> dimensionsList) { 120 | Date startDate = new Date(start - 1000L * rule.delaySeconds); 121 | Date endDate = new Date(start - 1000L * (rule.delaySeconds + rule.rangeSeconds)); 122 | GetMetricDataRequest.Builder builder = GetMetricDataRequest.builder(); 123 | builder.endTime(startDate.toInstant()); 124 | builder.startTime(endDate.toInstant()); 125 | builder.scanBy(ScanBy.TIMESTAMP_DESCENDING); 126 | List queries = buildMetricDataQueries(rule, dimensionsList); 127 | List requests = new ArrayList<>(); 128 | for (List queriesPartition : 129 | partitionByMaxSize(queries, MAX_QUERIES_PER_REQUEST)) { 130 | requests.add(builder.metricDataQueries(queriesPartition).build()); 131 | } 132 | return requests; 133 | } 134 | 135 | private Map fetchAllDataPoints(List> dimensionsList) { 136 | List results = new ArrayList<>(); 137 | for (GetMetricDataRequest request : buildMetricDataRequests(rule, dimensionsList)) { 138 | GetMetricDataResponse response = client.getMetricData(request); 139 | apiRequestsCounter.labels("getMetricData", rule.awsNamespace).inc(); 140 | results.addAll(response.metricDataResults()); 141 | } 142 | metricsRequestedCounter 143 | .labels(rule.awsMetricName, rule.awsNamespace) 144 | .inc(metricRequestedForBilling); 145 | return toMap(results); 146 | } 147 | 148 | private Map toMap(List metricDataResults) { 149 | Map res = new HashMap<>(); 150 | for (MetricDataResult dataResult : metricDataResults) { 151 | if (dataResult.timestamps().isEmpty() || dataResult.values().isEmpty()) { 152 | continue; 153 | } 154 | StatAndDimensions statAndDimensions = MetricLabels.decode(dataResult.label()); 155 | String statString = statAndDimensions.stat; 156 | String labelsKey = statAndDimensions.dimetionsAsString; 157 | Instant timestamp = dataResult.timestamps().get(0); 158 | Double value = dataResult.values().get(0); 159 | MetricRuleData metricRuleData = 160 | res.getOrDefault(labelsKey, new MetricRuleData(timestamp, "N/A")); 161 | Statistic stat = Statistic.fromValue(statString); 162 | if (stat == Statistic.UNKNOWN_TO_SDK_VERSION) { 163 | metricRuleData.extendedValues.put(statString, value); 164 | } else { 165 | metricRuleData.statisticValues.put(stat, value); 166 | } 167 | res.put(labelsKey, metricRuleData); 168 | } 169 | return res; 170 | } 171 | 172 | GetMetricDataDataGetter( 173 | CloudWatchClient client, 174 | long start, 175 | MetricRule rule, 176 | Counter apiRequestsCounter, 177 | Counter metricsRequestedCounter, 178 | List> dimensionsList) { 179 | this.client = client; 180 | this.start = start; 181 | this.rule = rule; 182 | this.apiRequestsCounter = apiRequestsCounter; 183 | this.metricsRequestedCounter = metricsRequestedCounter; 184 | this.metricRequestedForBilling = 0d; 185 | this.results = fetchAllDataPoints(dimensionsList); 186 | } 187 | 188 | @Override 189 | public MetricRuleData metricRuleDataFor(List dimensions) { 190 | return results.get(dimensionsToKey(dimensions)); 191 | } 192 | 193 | private static class StatAndDimensions { 194 | String dimetionsAsString; 195 | String stat; 196 | 197 | StatAndDimensions(String stat, String dimetionsAsString) { 198 | this.stat = stat; 199 | this.dimetionsAsString = dimetionsAsString; 200 | } 201 | } 202 | 203 | static class MetricLabels { 204 | static String labelFor(String stat, List dimensions) { 205 | return String.format("%s/%s", stat, dimensionsToKey(dimensions)); 206 | } 207 | 208 | static StatAndDimensions decode(String label) { 209 | String[] labelParts = label.split("/", 2); 210 | if (labelParts.length != 2) { 211 | throw new UnexpectedLabel(label); 212 | } 213 | String statString = labelParts[0]; 214 | String labelsKey = labelParts[1]; 215 | return new StatAndDimensions(statString, labelsKey); 216 | } 217 | 218 | static class UnexpectedLabel extends RuntimeException { 219 | public UnexpectedLabel(String label) { 220 | super(String.format("Cannot decode label %s", label)); 221 | } 222 | } 223 | } 224 | } 225 | -------------------------------------------------------------------------------- /src/main/java/io/prometheus/cloudwatch/GetMetricStatisticsDataGetter.java: -------------------------------------------------------------------------------- 1 | package io.prometheus.cloudwatch; 2 | 3 | import io.prometheus.client.Counter; 4 | import java.util.Date; 5 | import java.util.List; 6 | import java.util.Map; 7 | import software.amazon.awssdk.services.cloudwatch.CloudWatchClient; 8 | import software.amazon.awssdk.services.cloudwatch.model.Datapoint; 9 | import software.amazon.awssdk.services.cloudwatch.model.Dimension; 10 | import software.amazon.awssdk.services.cloudwatch.model.GetMetricStatisticsRequest; 11 | import software.amazon.awssdk.services.cloudwatch.model.GetMetricStatisticsResponse; 12 | import software.amazon.awssdk.services.cloudwatch.model.Statistic; 13 | 14 | class GetMetricStatisticsDataGetter implements DataGetter { 15 | private long start; 16 | private MetricRule rule; 17 | private CloudWatchClient client; 18 | private Counter apiRequestsCounter; 19 | private Counter metricsRequestedCounter; 20 | 21 | GetMetricStatisticsDataGetter( 22 | CloudWatchClient client, 23 | long start, 24 | MetricRule rule, 25 | Counter apiRequestsCounter, 26 | Counter metricsRequestedCounter) { 27 | this.client = client; 28 | this.start = start; 29 | this.rule = rule; 30 | this.apiRequestsCounter = apiRequestsCounter; 31 | this.metricsRequestedCounter = metricsRequestedCounter; 32 | } 33 | 34 | private GetMetricStatisticsRequest.Builder metricStatisticsRequestBuilder() { 35 | Date startDate = new Date(start - 1000 * rule.delaySeconds); 36 | Date endDate = new Date(start - 1000 * (rule.delaySeconds + rule.rangeSeconds)); 37 | GetMetricStatisticsRequest.Builder builder = GetMetricStatisticsRequest.builder(); 38 | builder.namespace(rule.awsNamespace); 39 | builder.metricName(rule.awsMetricName); 40 | builder.statistics(rule.awsStatistics); 41 | builder.extendedStatistics(rule.awsExtendedStatistics); 42 | builder.endTime(startDate.toInstant()); 43 | builder.startTime(endDate.toInstant()); 44 | builder.period(rule.periodSeconds); 45 | return builder; 46 | } 47 | 48 | @Override 49 | public MetricRuleData metricRuleDataFor(List dimensions) { 50 | GetMetricStatisticsRequest.Builder builder = metricStatisticsRequestBuilder(); 51 | builder.dimensions(dimensions); 52 | GetMetricStatisticsResponse response = client.getMetricStatistics(builder.build()); 53 | apiRequestsCounter.labels("getMetricStatistics", rule.awsNamespace).inc(); 54 | metricsRequestedCounter.labels(rule.awsMetricName, rule.awsNamespace).inc(); 55 | Datapoint latestDp = getNewestDatapoint(response.datapoints()); 56 | return toMetricValues(latestDp); 57 | } 58 | 59 | private Datapoint getNewestDatapoint(List datapoints) { 60 | Datapoint newest = null; 61 | for (Datapoint d : datapoints) { 62 | if (newest == null || newest.timestamp().isBefore(d.timestamp())) { 63 | newest = d; 64 | } 65 | } 66 | return newest; 67 | } 68 | 69 | private MetricRuleData toMetricValues(Datapoint dp) { 70 | if (dp == null) { 71 | return null; 72 | } 73 | MetricRuleData values = new MetricRuleData(dp.timestamp(), dp.unitAsString()); 74 | if (dp.sum() != null) { 75 | values.statisticValues.put(Statistic.SUM, dp.sum()); 76 | } 77 | if (dp.sampleCount() != null) { 78 | values.statisticValues.put(Statistic.SAMPLE_COUNT, dp.sampleCount()); 79 | } 80 | if (dp.minimum() != null) { 81 | values.statisticValues.put(Statistic.MINIMUM, dp.minimum()); 82 | } 83 | if (dp.maximum() != null) { 84 | values.statisticValues.put(Statistic.MAXIMUM, dp.maximum()); 85 | } 86 | if (dp.average() != null) { 87 | values.statisticValues.put(Statistic.AVERAGE, dp.average()); 88 | } 89 | if (dp.extendedStatistics() != null) { 90 | for (Map.Entry entry : dp.extendedStatistics().entrySet()) { 91 | values.extendedValues.put(entry.getKey(), entry.getValue()); 92 | } 93 | } 94 | return values; 95 | } 96 | } 97 | -------------------------------------------------------------------------------- /src/main/java/io/prometheus/cloudwatch/HealthServlet.java: -------------------------------------------------------------------------------- 1 | package io.prometheus.cloudwatch; 2 | 3 | import jakarta.servlet.ServletException; 4 | import jakarta.servlet.http.HttpServlet; 5 | import jakarta.servlet.http.HttpServletRequest; 6 | import jakarta.servlet.http.HttpServletResponse; 7 | import java.io.IOException; 8 | 9 | public class HealthServlet extends HttpServlet { 10 | private static final long serialVersionUID = 5543118274931292897L; 11 | 12 | @Override 13 | protected void doGet(HttpServletRequest req, HttpServletResponse resp) 14 | throws ServletException, IOException { 15 | resp.setContentType("text/plain"); 16 | resp.getWriter().print("ok"); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/main/java/io/prometheus/cloudwatch/HomePageServlet.java: -------------------------------------------------------------------------------- 1 | package io.prometheus.cloudwatch; 2 | 3 | import jakarta.servlet.ServletException; 4 | import jakarta.servlet.http.HttpServlet; 5 | import jakarta.servlet.http.HttpServletRequest; 6 | import jakarta.servlet.http.HttpServletResponse; 7 | import java.io.IOException; 8 | 9 | public class HomePageServlet extends HttpServlet { 10 | private static final long serialVersionUID = 3239704246954810347L; 11 | 12 | @Override 13 | protected void doGet(HttpServletRequest req, HttpServletResponse resp) 14 | throws ServletException, IOException { 15 | resp.setContentType("text/html"); 16 | try { 17 | resp.getWriter() 18 | .print( 19 | "\n" 20 | + "CloudWatch Exporter\n" 21 | + "\n" 22 | + "

CloudWatch Exporter

\n" 23 | + "

Metrics

\n" 24 | + "\n" 25 | + ""); 26 | } catch (IOException e) { 27 | // Ignored 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/main/java/io/prometheus/cloudwatch/MetricRule.java: -------------------------------------------------------------------------------- 1 | package io.prometheus.cloudwatch; 2 | 3 | import java.time.Duration; 4 | import java.util.List; 5 | import java.util.Map; 6 | import java.util.Objects; 7 | import software.amazon.awssdk.services.cloudwatch.model.Statistic; 8 | 9 | class MetricRule { 10 | String awsNamespace; 11 | String awsMetricName; 12 | int periodSeconds; 13 | int rangeSeconds; 14 | int delaySeconds; 15 | List awsStatistics; 16 | List awsExtendedStatistics; 17 | List awsDimensions; 18 | Map> awsDimensionSelect; 19 | Map> awsDimensionSelectRegex; 20 | CloudWatchCollector.AWSTagSelect awsTagSelect; 21 | String help; 22 | boolean cloudwatchTimestamp; 23 | boolean useGetMetricData; 24 | Duration listMetricsCacheTtl; 25 | boolean warnOnEmptyListDimensions; 26 | 27 | @Override 28 | public boolean equals(Object o) { 29 | if (this == o) return true; 30 | if (o == null || getClass() != o.getClass()) return false; 31 | 32 | MetricRule that = (MetricRule) o; 33 | 34 | if (periodSeconds != that.periodSeconds) return false; 35 | if (rangeSeconds != that.rangeSeconds) return false; 36 | if (delaySeconds != that.delaySeconds) return false; 37 | if (cloudwatchTimestamp != that.cloudwatchTimestamp) return false; 38 | if (useGetMetricData != that.useGetMetricData) return false; 39 | if (!Objects.equals(awsNamespace, that.awsNamespace)) return false; 40 | if (!Objects.equals(awsMetricName, that.awsMetricName)) return false; 41 | if (!Objects.equals(awsStatistics, that.awsStatistics)) return false; 42 | if (!Objects.equals(awsExtendedStatistics, that.awsExtendedStatistics)) return false; 43 | if (!Objects.equals(awsDimensions, that.awsDimensions)) return false; 44 | if (!Objects.equals(awsDimensionSelect, that.awsDimensionSelect)) return false; 45 | if (!Objects.equals(awsDimensionSelectRegex, that.awsDimensionSelectRegex)) return false; 46 | if (!Objects.equals(awsTagSelect, that.awsTagSelect)) return false; 47 | if (!Objects.equals(help, that.help)) return false; 48 | return Objects.equals(listMetricsCacheTtl, that.listMetricsCacheTtl); 49 | } 50 | 51 | @Override 52 | public int hashCode() { 53 | int result = awsNamespace != null ? awsNamespace.hashCode() : 0; 54 | result = 31 * result + (awsMetricName != null ? awsMetricName.hashCode() : 0); 55 | result = 31 * result + periodSeconds; 56 | result = 31 * result + rangeSeconds; 57 | result = 31 * result + delaySeconds; 58 | result = 31 * result + (awsStatistics != null ? awsStatistics.hashCode() : 0); 59 | result = 31 * result + (awsExtendedStatistics != null ? awsExtendedStatistics.hashCode() : 0); 60 | result = 31 * result + (awsDimensions != null ? awsDimensions.hashCode() : 0); 61 | result = 31 * result + (awsDimensionSelect != null ? awsDimensionSelect.hashCode() : 0); 62 | result = 63 | 31 * result + (awsDimensionSelectRegex != null ? awsDimensionSelectRegex.hashCode() : 0); 64 | result = 31 * result + (awsTagSelect != null ? awsTagSelect.hashCode() : 0); 65 | result = 31 * result + (help != null ? help.hashCode() : 0); 66 | result = 31 * result + (cloudwatchTimestamp ? 1 : 0); 67 | result = 31 * result + (useGetMetricData ? 1 : 0); 68 | result = 31 * result + (listMetricsCacheTtl != null ? listMetricsCacheTtl.hashCode() : 0); 69 | return result; 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /src/main/java/io/prometheus/cloudwatch/ReloadSignalHandler.java: -------------------------------------------------------------------------------- 1 | package io.prometheus.cloudwatch; 2 | 3 | import java.util.logging.Level; 4 | import java.util.logging.Logger; 5 | import sun.misc.Signal; 6 | import sun.misc.SignalHandler; 7 | 8 | class ReloadSignalHandler { 9 | private static final Logger LOGGER = Logger.getLogger(CloudWatchCollector.class.getName()); 10 | 11 | protected static void start(final CloudWatchCollector collector) { 12 | Signal.handle( 13 | new Signal("HUP"), 14 | new SignalHandler() { 15 | public void handle(Signal signal) { 16 | try { 17 | collector.reloadConfig(); 18 | } catch (Exception e) { 19 | LOGGER.log(Level.WARNING, "Configuration reload failed", e); 20 | } 21 | } 22 | }); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/main/java/io/prometheus/cloudwatch/WebServer.java: -------------------------------------------------------------------------------- 1 | package io.prometheus.cloudwatch; 2 | 3 | import io.prometheus.client.hotspot.DefaultExports; 4 | import io.prometheus.client.servlet.jakarta.exporter.MetricsServlet; 5 | import java.io.FileReader; 6 | import java.util.EnumSet; 7 | import org.eclipse.jetty.http.HttpMethod; 8 | import org.eclipse.jetty.server.HttpConfiguration; 9 | import org.eclipse.jetty.server.HttpConnectionFactory; 10 | import org.eclipse.jetty.server.Server; 11 | import org.eclipse.jetty.server.ServerConnector; 12 | import org.eclipse.jetty.servlet.ServletContextHandler; 13 | import org.eclipse.jetty.servlet.ServletHolder; 14 | 15 | public class WebServer { 16 | 17 | public static String configFilePath; 18 | 19 | public static void main(String[] args) throws Exception { 20 | if (args.length < 2) { 21 | System.err.println("Usage: WebServer "); 22 | System.exit(1); 23 | } 24 | 25 | configFilePath = args[1]; 26 | CloudWatchCollector collector = null; 27 | new BuildInfoCollector().register(); 28 | try (FileReader reader = new FileReader(configFilePath); ) { 29 | collector = new CloudWatchCollector(reader).register(); 30 | } 31 | DefaultExports.initialize(); 32 | 33 | ReloadSignalHandler.start(collector); 34 | 35 | int port = Integer.parseInt(args[0]); 36 | Server server = new Server(); 37 | HttpConfiguration httpConfig = new HttpConfiguration(); 38 | httpConfig.addCustomizer(new DisallowHttpMethods(EnumSet.of(HttpMethod.TRACE))); 39 | ServerConnector connector = new ServerConnector(server, new HttpConnectionFactory(httpConfig)); 40 | connector.setPort(port); 41 | server.addConnector(connector); 42 | 43 | ServletContextHandler context = new ServletContextHandler(); 44 | context.setContextPath("/"); 45 | server.setHandler(context); 46 | context.addServlet(new ServletHolder(new MetricsServlet()), "/metrics"); 47 | context.addServlet(new ServletHolder(new DynamicReloadServlet(collector)), "/-/reload"); 48 | context.addServlet(new ServletHolder(new HealthServlet()), "/-/healthy"); 49 | context.addServlet(new ServletHolder(new HealthServlet()), "/-/ready"); 50 | context.addServlet(new ServletHolder(new HomePageServlet()), "/"); 51 | server.start(); 52 | server.join(); 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /src/main/resources/.properties: -------------------------------------------------------------------------------- 1 | ReleaseDate=${project.releaseDate} 2 | BuildVersion=${project.version} 3 | -------------------------------------------------------------------------------- /src/test/java/io/prometheus/cloudwatch/CachingDimensionExpiryTest.java: -------------------------------------------------------------------------------- 1 | package io.prometheus.cloudwatch; 2 | 3 | import static org.junit.Assert.assertEquals; 4 | 5 | import io.prometheus.cloudwatch.CachingDimensionSource.DimensionCacheKey; 6 | import io.prometheus.cloudwatch.CachingDimensionSource.DimensionExpiry; 7 | import java.time.Duration; 8 | import java.time.Instant; 9 | import java.util.Collections; 10 | import java.util.List; 11 | import org.junit.Test; 12 | 13 | public class CachingDimensionExpiryTest { 14 | 15 | private final DimensionSource.DimensionData emptyData = 16 | new DimensionSource.DimensionData(Collections.emptyList()); 17 | 18 | @Test 19 | public void expireAfterCreateUsesDefaultWithEmptyOverrides() { 20 | Duration defaultExpiry = Duration.ofSeconds(35); 21 | List expiryOverrides = Collections.emptyList(); 22 | DimensionExpiry sut = new DimensionExpiry(defaultExpiry, expiryOverrides); 23 | 24 | long afterCreate = 25 | sut.expireAfterCreate( 26 | createDimensionCacheKey("AWS/Redshift", "WriteIOPS", 0), 27 | emptyData, 28 | Instant.now().toEpochMilli()); 29 | 30 | assertEquals(35, Duration.ofNanos(afterCreate).toSeconds()); 31 | } 32 | 33 | @Test 34 | public void expireAfterCreateUsesMetricLevelOverride() { 35 | Duration defaultExpiry = Duration.ofSeconds(35); 36 | List expiryOverrides = List.of(createMetricRule("AWS/S3", "BucketSizeBytes", 100)); 37 | DimensionExpiry sut = new DimensionExpiry(defaultExpiry, expiryOverrides); 38 | 39 | long afterCreate = 40 | sut.expireAfterCreate( 41 | createDimensionCacheKey("AWS/S3", "BucketSizeBytes", 100), 42 | emptyData, 43 | Instant.now().toEpochMilli()); 44 | 45 | assertEquals(100, Duration.ofNanos(afterCreate).toSeconds()); 46 | } 47 | 48 | @Test 49 | public void expireAfterCreateUsesDefaultIfNoMatchedOverride() { 50 | Duration defaultExpiry = Duration.ofSeconds(35); 51 | List expiryOverrides = List.of(createMetricRule("AWS/S3", "BucketSizeBytes", 100)); 52 | DimensionExpiry sut = new DimensionExpiry(defaultExpiry, expiryOverrides); 53 | 54 | long afterCreate = 55 | sut.expireAfterCreate( 56 | createDimensionCacheKey("AWS/Redshift", "WriteIOPS", 120), 57 | emptyData, 58 | Instant.now().toEpochMilli()); 59 | 60 | assertEquals(35, Duration.ofNanos(afterCreate).toSeconds()); 61 | } 62 | 63 | @Test 64 | public void expireAfterUpdateUsesCurrentDuration() { 65 | Duration defaultExpiry = Duration.ofSeconds(35); 66 | List expiryOverrides = Collections.emptyList(); 67 | DimensionExpiry sut = new DimensionExpiry(defaultExpiry, expiryOverrides); 68 | 69 | long afterUpdate = 70 | sut.expireAfterUpdate( 71 | createDimensionCacheKey("AWS/Redshift", "WriteIOPS", 120), 72 | emptyData, 73 | Instant.now().toEpochMilli(), 74 | 10_000_000); 75 | 76 | assertEquals(10_000_000, afterUpdate); 77 | } 78 | 79 | @Test 80 | public void expireAfterReadUsesCurrentDuration() { 81 | Duration defaultExpiry = Duration.ofSeconds(35); 82 | List expiryOverrides = Collections.emptyList(); 83 | DimensionExpiry sut = new DimensionExpiry(defaultExpiry, expiryOverrides); 84 | 85 | long afterRead = 86 | sut.expireAfterRead( 87 | createDimensionCacheKey("AWS/Redshift", "WriteIOPS", 100), 88 | emptyData, 89 | Instant.now().toEpochMilli(), 90 | 20_000_000); 91 | assertEquals(20_000_000, afterRead); 92 | } 93 | 94 | private DimensionCacheKey createDimensionCacheKey( 95 | String namespace, String name, int ttlInSeconds) { 96 | return new DimensionCacheKey( 97 | createMetricRule(namespace, name, ttlInSeconds), Collections.emptyList()); 98 | } 99 | 100 | private MetricRule createMetricRule(String namespace, String name, int ttlInSeconds) { 101 | MetricRule metricRule = new MetricRule(); 102 | metricRule.awsNamespace = namespace; 103 | metricRule.awsMetricName = name; 104 | metricRule.listMetricsCacheTtl = Duration.ofSeconds(ttlInSeconds); 105 | return metricRule; 106 | } 107 | } 108 | -------------------------------------------------------------------------------- /src/test/java/io/prometheus/cloudwatch/CachingDimensionSourceTest.java: -------------------------------------------------------------------------------- 1 | package io.prometheus.cloudwatch; 2 | 3 | import static io.prometheus.cloudwatch.DimensionSource.DimensionData; 4 | import static org.junit.Assert.assertEquals; 5 | 6 | import io.prometheus.cloudwatch.CachingDimensionSource.DimensionCacheConfig; 7 | import java.time.Duration; 8 | import java.util.Collections; 9 | import java.util.List; 10 | import org.junit.Test; 11 | import software.amazon.awssdk.services.cloudwatch.model.Dimension; 12 | 13 | public class CachingDimensionSourceTest { 14 | 15 | @Test 16 | public void cachedFromDelegate() { 17 | DimensionCacheConfig config = new DimensionCacheConfig(Duration.ofSeconds(60)); 18 | FakeDimensionSource source = new FakeDimensionSource(); 19 | DimensionSource sut = new CachingDimensionSource(source, config); 20 | 21 | sut.getDimensions(createMetricRule("AWS/Redshift", "WriteIOPS"), Collections.emptyList()); 22 | sut.getDimensions(createMetricRule("AWS/Redshift", "WriteIOPS"), Collections.emptyList()); 23 | DimensionData expected = 24 | sut.getDimensions(createMetricRule("AWS/Redshift", "WriteIOPS"), Collections.emptyList()); 25 | 26 | Dimension dimension = Dimension.builder().name("AWS/Redshift").value("WriteIOPS").build(); 27 | assertEquals(1, source.called); 28 | assertEquals(dimension, expected.getDimensions().get(0).get(0)); 29 | } 30 | 31 | private MetricRule createMetricRule(String namespace, String name) { 32 | MetricRule metricRule = new MetricRule(); 33 | metricRule.awsNamespace = namespace; 34 | metricRule.awsMetricName = name; 35 | return metricRule; 36 | } 37 | 38 | static class FakeDimensionSource implements DimensionSource { 39 | int called = 0; 40 | 41 | @Override 42 | public DimensionData getDimensions(MetricRule rule, List tagBasedResourceIds) { 43 | called++; 44 | return new DimensionData( 45 | List.of(List.of(Dimension.builder().name("AWS/Redshift").value("WriteIOPS").build()))); 46 | } 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /src/test/java/io/prometheus/cloudwatch/GetMetricDataGetterTest.java: -------------------------------------------------------------------------------- 1 | package io.prometheus.cloudwatch; 2 | 3 | import static org.junit.Assert.assertTrue; 4 | 5 | import java.util.Collections; 6 | import java.util.List; 7 | import org.junit.Test; 8 | 9 | public class GetMetricDataGetterTest { 10 | @Test 11 | public void testPartition() { 12 | List originalList = List.copyOf(Collections.nCopies(28, 0)); 13 | List> partitions = GetMetricDataDataGetter.partitionByMaxSize(originalList, 40); 14 | for (List p : partitions) { 15 | assertTrue("partition must be smaller than 40", p.size() <= 40); 16 | assertTrue("partition should not be empty", !p.isEmpty()); 17 | } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/test/java/io/prometheus/cloudwatch/RequestsMatchers.java: -------------------------------------------------------------------------------- 1 | package io.prometheus.cloudwatch; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | import java.util.stream.Collectors; 6 | import org.hamcrest.BaseMatcher; 7 | import org.hamcrest.Description; 8 | import org.hamcrest.Matcher; 9 | import org.hamcrest.Matchers; 10 | import software.amazon.awssdk.services.cloudwatch.model.Dimension; 11 | import software.amazon.awssdk.services.cloudwatch.model.DimensionFilter; 12 | import software.amazon.awssdk.services.cloudwatch.model.GetMetricDataRequest; 13 | import software.amazon.awssdk.services.cloudwatch.model.GetMetricStatisticsRequest; 14 | import software.amazon.awssdk.services.cloudwatch.model.ListMetricsRequest; 15 | import software.amazon.awssdk.services.cloudwatch.model.Metric; 16 | import software.amazon.awssdk.services.cloudwatch.model.MetricDataQuery; 17 | import software.amazon.awssdk.services.cloudwatch.model.MetricStat; 18 | import software.amazon.awssdk.services.resourcegroupstaggingapi.model.GetResourcesRequest; 19 | import software.amazon.awssdk.services.resourcegroupstaggingapi.model.TagFilter; 20 | 21 | public class RequestsMatchers { 22 | 23 | static class ListMetricsRequestMatcher extends BaseMatcher { 24 | String namespace; 25 | String metricName; 26 | String nextToken; 27 | String recentlyActive; 28 | List dimensions = new ArrayList(); 29 | 30 | public ListMetricsRequestMatcher Namespace(String namespace) { 31 | this.namespace = namespace; 32 | return this; 33 | } 34 | 35 | public ListMetricsRequestMatcher MetricName(String metricName) { 36 | this.metricName = metricName; 37 | return this; 38 | } 39 | 40 | public ListMetricsRequestMatcher NextToken(String nextToken) { 41 | this.nextToken = nextToken; 42 | return this; 43 | } 44 | 45 | public ListMetricsRequestMatcher Dimensions(String... dimensions) { 46 | this.dimensions = new ArrayList(); 47 | for (int i = 0; i < dimensions.length; i++) { 48 | this.dimensions.add(DimensionFilter.builder().name(dimensions[i]).build()); 49 | } 50 | return this; 51 | } 52 | 53 | public ListMetricsRequestMatcher RecentlyActive(String recentlyActive) { 54 | this.recentlyActive = recentlyActive; 55 | return this; 56 | } 57 | 58 | public boolean matches(Object o) { 59 | ListMetricsRequest request = (ListMetricsRequest) o; 60 | if (request == null) return false; 61 | if (namespace != null && !namespace.equals(request.namespace())) { 62 | return false; 63 | } 64 | if (metricName != null && !metricName.equals(request.metricName())) { 65 | return false; 66 | } 67 | if (nextToken == null ^ request.nextToken() == null) { 68 | return false; 69 | } 70 | if (nextToken != null && !nextToken.equals(request.nextToken())) { 71 | return false; 72 | } 73 | if (!dimensions.equals(request.dimensions())) { 74 | return false; 75 | } 76 | if (recentlyActive != null && !recentlyActive.equals(request.recentlyActive())) { 77 | return false; 78 | } 79 | return true; 80 | } 81 | 82 | public void describeTo(Description description) { 83 | description.appendText("list metrics request"); 84 | } 85 | } 86 | 87 | static class GetMetricStatisticsRequestMatcher extends BaseMatcher { 88 | String namespace; 89 | String metricName; 90 | List dimensions = new ArrayList(); 91 | Integer period; 92 | 93 | public GetMetricStatisticsRequestMatcher Namespace(String namespace) { 94 | this.namespace = namespace; 95 | return this; 96 | } 97 | 98 | public GetMetricStatisticsRequestMatcher MetricName(String metricName) { 99 | this.metricName = metricName; 100 | return this; 101 | } 102 | 103 | public GetMetricStatisticsRequestMatcher Dimension(String name, String value) { 104 | dimensions.add(Dimension.builder().name(name).value(value).build()); 105 | return this; 106 | } 107 | 108 | public GetMetricStatisticsRequestMatcher Period(int period) { 109 | this.period = period; 110 | return this; 111 | } 112 | 113 | public boolean matches(Object o) { 114 | GetMetricStatisticsRequest request = (GetMetricStatisticsRequest) o; 115 | if (request == null) return false; 116 | if (namespace != null && !namespace.equals(request.namespace())) { 117 | return false; 118 | } 119 | if (metricName != null && !metricName.equals(request.metricName())) { 120 | return false; 121 | } 122 | if (!dimensions.equals(request.dimensions())) { 123 | return false; 124 | } 125 | if (period != null && !period.equals(request.period())) { 126 | return false; 127 | } 128 | return true; 129 | } 130 | 131 | public void describeTo(Description description) { 132 | description.appendText("get metrics statistics request"); 133 | } 134 | } 135 | 136 | static class GetResourcesRequestMatcher extends BaseMatcher { 137 | String paginationToken = ""; 138 | List resourceTypeFilters = new ArrayList(); 139 | List tagFilters = new ArrayList(); 140 | 141 | public GetResourcesRequestMatcher PaginationToken(String paginationToken) { 142 | this.paginationToken = paginationToken; 143 | return this; 144 | } 145 | 146 | public GetResourcesRequestMatcher ResourceTypeFilter(String resourceTypeFilter) { 147 | resourceTypeFilters.add(resourceTypeFilter); 148 | return this; 149 | } 150 | 151 | public GetResourcesRequestMatcher TagFilter(String key, List values) { 152 | tagFilters.add(TagFilter.builder().key(key).values(values).build()); 153 | return this; 154 | } 155 | 156 | public boolean matches(Object o) { 157 | GetResourcesRequest request = (GetResourcesRequest) o; 158 | if (request == null) return false; 159 | if (paginationToken == "" ^ request.paginationToken() == "") { 160 | return false; 161 | } 162 | if (paginationToken != "" && !paginationToken.equals(request.paginationToken())) { 163 | return false; 164 | } 165 | if (!resourceTypeFilters.equals(request.resourceTypeFilters())) { 166 | return false; 167 | } 168 | if (!tagFilters.equals(request.tagFilters())) { 169 | return false; 170 | } 171 | return true; 172 | } 173 | 174 | public void describeTo(Description description) { 175 | description.appendText("get resources request"); 176 | } 177 | } 178 | 179 | static class MetricMatcher extends BaseMatcher { 180 | String namespace; 181 | String metricName; 182 | List dimensions = new ArrayList(); 183 | 184 | public MetricMatcher Namespace(String namespace) { 185 | this.namespace = namespace; 186 | return this; 187 | } 188 | 189 | public MetricMatcher MetricName(String metricName) { 190 | this.metricName = metricName; 191 | return this; 192 | } 193 | 194 | public MetricMatcher Dimension(String name, String value) { 195 | dimensions.add(Dimension.builder().name(name).value(value).build()); 196 | return this; 197 | } 198 | 199 | @Override 200 | public boolean matches(Object o) { 201 | Metric metric = (Metric) o; 202 | if (metric == null) return false; 203 | if (namespace != null && !namespace.equals(metric.namespace())) { 204 | return false; 205 | } 206 | if (metricName != null && !metricName.equals(metric.metricName())) { 207 | return false; 208 | } 209 | if (!dimensions.equals(metric.dimensions())) { 210 | return false; 211 | } 212 | return true; 213 | } 214 | 215 | @Override 216 | public void describeTo(Description description) { 217 | description.appendText("Metric"); 218 | List properties = new ArrayList<>(); 219 | if (namespace != null) { 220 | properties.add(String.format("namespace=%s", namespace)); 221 | } 222 | if (metricName != null) { 223 | properties.add(String.format("metricName=%s", metricName)); 224 | } 225 | String dimentions = 226 | dimensions.stream() 227 | .map((d) -> d.name() + ":" + d.value()) 228 | .collect(Collectors.joining(", ")); 229 | properties.add(String.format("dimentions=[%s]", dimentions)); 230 | description.appendValueList("(", ",", ")", properties); 231 | } 232 | } 233 | 234 | static class MetricStatMatcher extends BaseMatcher { 235 | MetricMatcher metricMatcher; 236 | String stat; 237 | Integer period; 238 | 239 | public MetricStatMatcher metric(MetricMatcher metricMatcher) { 240 | this.metricMatcher = metricMatcher; 241 | return this; 242 | } 243 | 244 | public MetricStatMatcher Period(int period) { 245 | this.period = period; 246 | return this; 247 | } 248 | 249 | public MetricStatMatcher Stat(String stat) { 250 | this.stat = stat; 251 | return this; 252 | } 253 | 254 | @Override 255 | public boolean matches(Object o) { 256 | MetricStat metricStat = (MetricStat) o; 257 | if (metricStat == null) return false; 258 | if (period != null && !period.equals(metricStat.period())) { 259 | return false; 260 | } 261 | if (metricMatcher != null && !metricMatcher.matches(metricStat.metric())) { 262 | return false; 263 | } 264 | if (stat != null && !stat.equals(metricStat.stat())) { 265 | return false; 266 | } 267 | return true; 268 | } 269 | 270 | @Override 271 | public void describeTo(Description description) { 272 | description.appendText("A metric stat"); 273 | if (stat != null) { 274 | description.appendText(String.format(" with stat %s", stat)); 275 | } 276 | if (period != null) { 277 | description.appendText(String.format(" with period %s", period)); 278 | } 279 | if (metricMatcher != null) { 280 | description.appendText(" with metric "); 281 | metricMatcher.describeTo(description); 282 | } 283 | } 284 | } 285 | 286 | static class MetricDataQueryMatcher extends BaseMatcher { 287 | String label; 288 | MetricStatMatcher metricStat; 289 | 290 | public MetricDataQueryMatcher Label(String label) { 291 | this.label = label; 292 | return this; 293 | } 294 | 295 | public MetricDataQueryMatcher MetricStat(MetricStatMatcher metricStat) { 296 | this.metricStat = metricStat; 297 | return this; 298 | } 299 | 300 | @Override 301 | public boolean matches(Object o) { 302 | MetricDataQuery query = (MetricDataQuery) o; 303 | if (query == null) return false; 304 | if (label != null && !label.equals(query.label())) { 305 | return false; 306 | } 307 | if (metricStat != null && !metricStat.matches(query.metricStat())) { 308 | return false; 309 | } 310 | return true; 311 | } 312 | 313 | @Override 314 | public void describeTo(Description description) { 315 | description.appendText("metric data query"); 316 | if (label != null) { 317 | description.appendText(String.format(" with label '%s'", label)); 318 | } 319 | if (metricStat != null) { 320 | description.appendText(" with stat: "); 321 | metricStat.describeTo(description); 322 | } 323 | } 324 | } 325 | 326 | static class GetMetricDataRequestMatcher extends BaseMatcher { 327 | List queries = new ArrayList<>(); 328 | 329 | public GetMetricDataRequestMatcher Query(MetricDataQueryMatcher query) { 330 | this.queries.add(query); 331 | return this; 332 | } 333 | 334 | private Matcher> queriesMatcher() { 335 | return Matchers.hasItems(queries.stream().toArray(MetricDataQueryMatcher[]::new)); 336 | } 337 | 338 | @Override 339 | public boolean matches(Object o) { 340 | GetMetricDataRequest request = (GetMetricDataRequest) o; 341 | if (request == null) { 342 | return false; 343 | } 344 | if (!queries.isEmpty() && !queriesMatcher().matches(request.metricDataQueries())) { 345 | return false; 346 | } 347 | ; 348 | return true; 349 | } 350 | 351 | @Override 352 | public void describeTo(Description description) { 353 | description.appendText("a GetMetricDataRequest"); 354 | if (!queries.isEmpty()) { 355 | description.appendText("with queries:\n"); 356 | for (MetricDataQueryMatcher qmatcher : queries) { 357 | description.appendText("\t- "); 358 | qmatcher.describeTo(description); 359 | description.appendText("\n"); 360 | } 361 | } 362 | } 363 | } 364 | } 365 | --------------------------------------------------------------------------------