Amazon CloudWatch
Plugin: go.d.plugin Module: cloudwatch
Overview
Monitor AWS infrastructure through Amazon CloudWatch. The collector discovers your AWS resources and turns their CloudWatch metrics into Netdata charts, one chart instance per resource, for a curated set of AWS services and with minimal configuration.
Out of the box it covers:
| Area | Services |
|---|---|
| Compute and containers | Amazon EC2, AWS Lambda, Amazon ECS, Amazon EKS (Kubernetes control plane), AWS Auto Scaling |
| Databases and analytics | Amazon RDS, Amazon DynamoDB, Amazon ElastiCache, Amazon DocumentDB, Amazon Redshift, Amazon OpenSearch Service |
| Storage | Amazon S3, Amazon EBS, Amazon EFS |
| Networking and content delivery | Classic (ELB), Application (ALB), and Network (NLB) load balancers, NAT Gateway, AWS PrivateLink endpoints and endpoint services, Amazon CloudFront, AWS Site-to-Site VPN |
| Messaging, streaming, and events | Amazon SQS, Amazon SNS, Amazon Kinesis Data Streams, Amazon Data Firehose, Amazon MSK, Amazon EventBridge |
| Application services and AI | Amazon API Gateway, AWS Step Functions, Amazon Bedrock |
| Cost | AWS Billing estimated month-to-date charges (opt-in) |
- Every resource becomes a chart instance labeled with its AWS account, region, and identifying dimensions (for
example the EC2
instance_id). - Several AWS accounts can be monitored from one job by assuming roles.
- Resources can be selected and labeled by their AWS tags.
- Four collector-activity charts show the AWS API work the job performs, so its cost stays visible.
Coverage is defined by profiles: one YAML file per service and level of detail, 34 enabled by default and 13 opt-in. A service can be added or a chart changed without a code change; see the AWS CloudWatch profile format.
This collector reads runtime metrics. The AWS EC2 Compute instances integration (EC2 inventory and capacity) and the AWS Quota integration (AWS Service Quotas) use different AWS data sources and complement it.
The collector runs on the Netdata Agent and reads CloudWatch through the AWS API. It installs nothing in AWS and writes nothing there.
- Authentication: each named credential source uses the AWS SDK default chain (environment variables, shared
config and credentials files, instance profile, EKS IRSA) or static access keys, optionally assuming one IAM
role per target. The AWS account behind a target is resolved once with
sts:GetCallerIdentity. - Discovery: every
discovery.refresh_everyseconds (default 300) the collector lists the metrics of each selected service withcloudwatch:ListMetrics, once per target, region, and CloudWatch namespace, and matches them against the profile's dimensions to find the resources. Resource tag filters and labels are resolved withtag:GetResources(Resource Groups Tagging API). - Collection: every
update_everyseconds (default 60) it reads the newest complete datapoint of every selected metric and statistic withcloudwatch:GetMetricData, batched, and only for series whose CloudWatch period has moved on since the last read. Between reads the last value is repeated at no AWS cost.
Terms used on this page and in the options:
| Term | Meaning |
|---|---|
| Profile | A YAML file that maps one CloudWatch namespace and one dimension set to charts. Stock profiles ship with Netdata; user profiles extend or override them. |
| Grain | The exact dimension set a profile matches, such as one PrivateLink endpoint versus one endpoint per subnet. |
| Target | A named AWS identity to monitor: a credential source, used directly or through one assumed role. |
| Rule | An ordered configuration entry selecting targets, regions, profiles, and optionally exact metrics. The first rule that selects a series owns it. |
| Series | One metric and statistic for one resource: the unit the collector's limits count. |
This collector is supported on all platforms.
This collector supports collecting metrics from multiple instances of this integration, including remote instances.
| Permission | Needed when |
|---|---|
cloudwatch:GetMetricData | Always, for every target. |
cloudwatch:ListMetrics | Any selected profile has an identifying dimension and therefore needs discovery. An all-constant profile such as billing_total is queried directly and does not need it. |
sts:AssumeRole | A target sets assume_role; grant it on the credential source's identity for that role ARN. |
tag:GetResources | Resource tag filters (rule_defaults.filters.resource_tags, rules[].filters.resource_tags) or resource tag labels (labels.resource_tags) are configured. |
The collector also calls sts:GetCallerIdentity for account attribution, but AWS does not require an explicit
permission grant for that operation.
The collector only reads; it never writes to CloudWatch or changes a resource.
Default Behavior
Auto-Detection
No job runs until you write one: a job needs at least one credential source, one target, and one rule. There is no service discovery for this collector.
With a minimal rule (targets and regions only) the collector collects every default-enabled profile, 34 of
them minus any your regions do not support (CloudFront exists only in us-east-1), with each profile's
default metrics and statistics, and discovers the resources itself every
discovery.refresh_every seconds (default 300). A chart appears once a resource reports data. Opt-in profiles
and opt-in metrics are collected only when a rule names them.
Limits
- The collection interval is at least 60 seconds. The CloudWatch period of a series (1 minute to 24 hours)
decides how often it has new data; a shorter
update_everydoes not make AWS publish more often. limits.max_instances(default 1000): more distinct resources than this, after tag filtering, rejects the query plan instead of collecting a subset; the log names the bound. Raise it deliberately or narrow the rules.limits.max_discovery_groups(default 64, at most 100): more unique target, region, and namespace combinations than this stops the job at start; split the collection across jobs.- The whole plan, evaluated as if every series were due at once, is refused above 20,000 series, 600,000
datapoints, or 40
GetMetricDatarequests, and a rule set is refused above 16,384 candidate or 4,096 compiled target, profile, and region combinations. Only very broad rules reach these bounds. - A job holds at most 64 credential sources, 64 targets, and 256 rules; each rule list (targets, regions, profiles, metrics) holds at most 256 entries; a tag filter holds at most 50 keys with 20 values each.
- Query timing per series:
periodfrom 1 minute to 24 hours in whole minutes;lookbackat least one period and at most 1,440 periods;publication_delay + lookback + periodat most 14 days. - A discovery refresh that exceeds its internal bounds or the shared
timeoutis discarded as a whole: the previously discovered resources stay, and discovery retries afterdiscovery.refresh_every. Recurring warnings of this kind are logged at most once per hour.
Performance Impact
The impact on the Agent host is negligible. The cost is on your AWS bill.
GetMetricData is billed per metric requested, about $0.01 per 1,000 in most regions; check
CloudWatch pricing for yours. Up to five statistics of one
metric in one request count as one metric requested, and the collector keeps them together as long as they
share the same query timing. ListMetrics
discovery is within the AWS free tier for most accounts and inexpensive beyond it. Broad rules across many
regions and services cost real money; read this section before enabling a wide selection.
What drives the cost
| Driver | Effect |
|---|---|
| Resources | Every discovered resource adds its profile's metrics. Tag filters and limits.max_instances bound it. |
| Metrics and statistics | Each selected metric and statistic of each resource is one series. Most default profiles select one statistic per metric, a few select two or three; up to five statistics of one metric stay one metric request when they share the same query timing, and giving one statistic its own period or lookback splits the request and bills separately. |
| Request frequency | A series is read once per CloudWatch period, and at most once per update_every. A 1-minute period read every minute costs five times a 5-minute period. |
| Lookback | A longer window requests more datapoints per read and can turn off the 3-hour recently-active discovery filter, which makes ListMetrics scans larger. |
| Retries | A read that fails transiently is retried after update_every, then with a doubling delay up to one period. Retries are billed. |
Estimating before you run
metric requests per day = resources × metrics requested per resource × 86,400 / max(period, update_every) in seconds
Sum it over the groups of series that share a period. For example, one series at a 10-minute period read on every collection is 86,400 / 600 = 144 metric requests per day; 200 such series are 28,800 per day, about $0.29 per day at $0.01 per 1,000.
Watching the cost while running
Four collector-activity charts count the work as it happens: CloudWatch SDK Invocations (ListMetrics and
GetMetricData calls, including failed calls and every result page), GetMetricData Calculated Metric Requests
(the billable unit, per account and region), GetMetricData Profile Metric Request Estimates (the same split
per profile for ranking; estimates are computed per profile and do not add up to the total), and
GetMetricData Query Items (submitted queries, for plan tuning). They count only ListMetrics and
GetMetricData, not STS or tag lookups, and they are inputs for cost visibility, not an invoice.
Reducing the cost
| Option | Effect |
|---|---|
rules[].profiles, rules[].metrics, rules[].regions, rules[].targets | Collect only the services, metrics, regions, and accounts you need. |
rule_defaults.filters.resource_tags, rules[].filters.resource_tags | Collect only tagged resources. |
rule_defaults.query.period with update_every | Read less often. A 5-minute period with update_every: 300 cuts a 1-minute selection by five. |
discovery.refresh_every | Scan for new resources less often. |
discovery.recently_active_only (default on) | Keep ListMetrics scans to resources active in the last 3 hours where the query horizon allows it. |
The opt-in Billing profiles use a 10-minute period, so each selected Billing series costs 144 metric requests per day before retries; their cardinality grows with services and linked accounts, so select only the grains you need.
Setup
You can configure the cloudwatch collector in two ways:
| Method | Best for | How to |
|---|---|---|
| UI | Fast setup without editing files | Go to Nodes → Configure this node → Collectors → Jobs, search for cloudwatch, then click + to add a job. |
| File | If you prefer configuring via file, or need to automate deployments (e.g., with Ansible) | Edit go.d/cloudwatch.conf and add a job. |
UI configuration requires paid Netdata Cloud plan.
Prerequisites
Create an AWS IAM identity with CloudWatch read access
The collector authenticates as an IAM user or role that can read CloudWatch. Attach this policy to it:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"cloudwatch:ListMetrics",
"cloudwatch:GetMetricData"
],
"Resource": "*"
}
]
}
cloudwatch:ListMetricsandcloudwatch:GetMetricDatado not support resource-level permissions, so"Resource": "*"is already the least privilege for these read actions (AWS reference).- Add
tag:GetResources(also"Resource": "*") when you use resource tag filters or labels. - Add
sts:AssumeRoleon each role ARN a target assumes, and let the role's trust policy allow this identity. - A job that selects only the
billing_totalprofile can omitcloudwatch:ListMetrics.
Verify as that identity: aws cloudwatch list-metrics --namespace AWS/EC2 --region <region> --max-items 1
should return without an access error.
Enable Billing metrics before selecting a Billing profile
The four Billing profiles are opt-in and collect nothing until AWS publishes estimated-charge metrics for your account.
- In the AWS Billing console open Billing preferences and enable Receive CloudWatch Billing Alerts (AWS documentation). For consolidated billing, do it in the management (payer) account.
- Wait about 15 minutes for the first data. AWS then publishes new estimates several times a day.
Enabling the preference needs the root user or an IAM principal allowed to view billing; the collector
identity needs only the read policy above. AWS states that once enabled, Billing metric collection cannot
be turned off; if the management (payer) account changes, enable it again in the new account. AWS
publishes Billing metrics only in us-east-1, in USD, and not for APN accounts.
Add or override a profile (optional)
Stock profiles live under /usr/lib/netdata/conf.d/go.d/cloudwatch.profiles/default/. To add a service or
change a chart, put a profile under /etc/netdata/go.d/cloudwatch.profiles/; a file with the same basename
as a stock profile overrides it. Profiles are read once at startup, so restart Netdata after changing one.
Format and rules: AWS CloudWatch profile format.
Configuration
Options
All options are set per job. update_every and autodetection_retry can also be set globally for the collector.
Config options
| Group | Option | Description | Default | Required |
|---|---|---|---|---|
| Collection | update_every | Data collection interval, in seconds, at least 60. All CloudWatch series are collected on this interval; a shorter metric period does not make Netdata query more often. | 60 | no |
| autodetection_retry | How often to retry the initial connection when the job fails to start, in seconds. Zero disables retries. | 0 | no | |
| timeout | Timeout in seconds for AWS API calls; a whole discovery refresh and a whole resource-tag lookup each share one timeout. | 30 | no | |
| Credentials | credentials | Named credential sources that targets reference. Each uses the AWS SDK default chain or explicit static credentials. | yes | |
| credentials[].name | Name that targets use to reference this credential source. | yes | ||
| credentials[].type | How this source obtains AWS credentials: the SDK default chain or explicit static credentials. | yes | ||
| credentials[].type_static | Explicit AWS credentials, used only when the type is static. Prefer secret references over plaintext values. | no | ||
| credentials[].type_static.access_key_id | AWS access key ID. Use a secret reference such as ${env:AWS_ACCESS_KEY_ID}. | no | ||
| credentials[].type_static.secret_access_key | AWS secret access key. Use a secret reference instead of a plaintext value. | no | ||
| credentials[].type_static.session_token | AWS session token, only for temporary credentials. Use a secret reference. | no | ||
| Targets | targets | Named AWS identities to monitor. A target uses one credential source directly or assumes one role with it. | yes | |
| targets[].name | Name that collection rules use to reference this target. | yes | ||
| targets[].credentials | Name of a credential source defined on the Credentials tab. | yes | ||
| targets[].assume_role.role_arn | ARN of the IAM role to assume with the target's credential source. | no | ||
| targets[].assume_role.external_id | External ID the role's trust policy expects, if it requires one. This is not a password or access key. | no | ||
| Rules | rules | Ordered collection rules. Each selects targets, profiles, regions, and optional metric overrides and resource filters; the first matching rule owns a series. | yes | |
| rules[].name | Unique rule name, shown in logs and diagnostics. | yes | ||
| rules[].targets | Names of the targets this rule collects from, in order. Order breaks ties when rules overlap. | yes | ||
| rules[].profiles.defaults | Start from every default-enabled profile before applying the include and exclude lists. | yes | no | |
| rules[].profiles.include | Profile basenames to add. With defaults off, only this list is collected, including profiles disabled by default. | no | ||
| rules[].profiles.exclude | Profile basenames to remove from the selection. A profile cannot be both included and excluded. | no | ||
| rules[].metrics | Per-profile metric overrides. Leave empty to collect each selected profile's default-enabled metrics. | no | ||
| rules[].metrics[].profile | Profile basename to override. It must be selected by this rule's profiles and may appear in one metrics group only. | yes | ||
| rules[].metrics[].defaults | Keep the profile's default-enabled metrics and add the included ones. Turn off for an exact-only selection. | yes | no | |
| rules[].metrics[].statistics | Statistics for included metrics that do not list their own. Leave empty to use the profile's statistics. | no | ||
| Rules / Query Policy | rules[].metrics[].query | Query timing for the series this group includes explicitly. Fields left empty inherit from the rule. | no | |
| rules[].metrics[].query.period | CloudWatch aggregation period for these series, from 1m to 24h in whole minutes. | no | ||
| rules[].metrics[].query.lookback | Window searched for the newest datapoint. At least one period, a whole multiple of it, and at most 1,440 periods. | no | ||
| rules[].metrics[].query.publication_delay | How long to wait after a period closes before querying it. A scheduling policy, not an AWS guarantee. | no | ||
| Rules | rules[].metrics[].include | Exact, case-sensitive CloudWatch metric names this group adds. A name may repeat only with disjoint statistics. | yes | |
| rules[].metrics[].include[].name | Exact, case-sensitive CloudWatch MetricName exported by the profile. | yes | ||
| rules[].metrics[].include[].statistics | Statistics for this metric, replacing the group list. Leave empty to inherit. | no | ||
| Rules / Query Policy | rules[].metrics[].include[].query | Query timing for this metric's series, overriding the group's. Fields left empty inherit. | no | |
| rules[].metrics[].include[].query.period | CloudWatch aggregation period for these series, from 1m to 24h in whole minutes. | no | ||
| rules[].metrics[].include[].query.lookback | Window searched for the newest datapoint. At least one period, a whole multiple of it, and at most 1,440 periods. | no | ||
| rules[].metrics[].include[].query.publication_delay | How long to wait after a period closes before querying it. A scheduling policy, not an AWS guarantee. | no | ||
| Rules | rules[].regions | AWS region codes this rule collects from. Profiles that support fewer regions are restricted automatically. | yes | |
| Rules / Query Policy | rule_defaults.query | Query timing inherited by every rule, field by field. Fields left empty fall back to profile or built-in values. | no | |
| rule_defaults.query.period | Default CloudWatch aggregation period, from 1m to 24h in whole minutes. Rules, groups, and metrics may override it. | no | ||
| rule_defaults.query.lookback | Default window searched for the newest datapoint. At least one period, a whole multiple of it, and at most 1,440 periods. | no | ||
| rule_defaults.query.publication_delay | Default wait after a period closes before querying it. A scheduling policy, not an AWS guarantee. | no | ||
| rules[].query | Query timing overrides for this rule. Fields left empty inherit the rule defaults; group and metric values take precedence. | no | ||
| rules[].query.period | CloudWatch aggregation period for these series, from 1m to 24h in whole minutes. | no | ||
| rules[].query.lookback | Window searched for the newest datapoint. At least one period, a whole multiple of it, and at most 1,440 periods. | no | ||
| rules[].query.publication_delay | How long to wait after a period closes before querying it. A scheduling policy, not an AWS guarantee. | no | ||
| Rules / Resource Filters | rule_defaults.filters.resource_tags | Resource tag filters inherited by rules that define none. A resource must match every key, with any listed value per key. | no | |
| rule_defaults.filters.resource_tags[].key | Exact, case-sensitive AWS tag key. A filter list supports at most 50 keys. | yes | ||
| rule_defaults.filters.resource_tags[].values | Accepted values for this key, 1 to 20, exact and case-sensitive. Any of them matches. | yes | ||
| rules[].filters.resource_tags | Resource tag filters replacing the job defaults for this rule. Leave unset to inherit, or set an empty list to disable filtering. | no | ||
| rules[].filters.resource_tags[].key | Exact, case-sensitive AWS tag key. A filter list supports at most 50 keys. | yes | ||
| rules[].filters.resource_tags[].values | Accepted values for this key, 1 to 20, exact and case-sensitive. Any of them matches. | yes | ||
| Resource Labels | labels.resource_tags | AWS resource tags copied to charts as labels. Presentation only; they never select resources. | no | |
| labels.resource_tags[].key | Exact, case-sensitive AWS tag key to copy. | yes | ||
| labels.resource_tags[].label | Netdata label key to use. Leave empty to derive it from the AWS key (Name becomes name). | no | ||
| Limits | limits.max_instances | Maximum distinct resource instances that emit metrics. Exceeding it rejects the plan instead of collecting a subset. | 1000 | no |
| limits.max_discovery_groups | Maximum target, region, and namespace combinations discovered per job, 1 to 100. Split larger collection across jobs. | 64 | no | |
| Discovery | discovery.refresh_every | How often to rediscover matching metrics and resources, in seconds, at least 60. | 300 | no |
| discovery.recently_active_only | Restrict discovery to metrics active in the last three hours where possible, which keeps scans smaller and cheaper. | yes | no | |
| Virtual Node | vnode | Associates this job with a Virtual Node. | no |
credentials
Up to 64 credential sources. Several targets can share one source.
credentials[].name
Names are lowercase, start with a letter, use only letters, digits, _, and -, and are at most 64 characters. Target and rule names follow the same format.
credentials[].type
| Type | Behavior | Use when |
|---|---|---|
default | AWS SDK default credential chain: environment variables, shared config and credentials files, EC2 instance profile, or EKS IRSA | Netdata runs inside AWS or the host already has an AWS identity |
static | Explicit access key ID and secret access key, plus an optional session token, in type_static | Keys are provisioned externally; reference them as ${env:NAME} rather than writing them in the file |
credentials[].type_static
Required when the type is static and not allowed otherwise. Inside it, access_key_id and
secret_access_key are required; session_token only for temporary credentials.
targets
Up to 64 targets. Targets stay distinct even when they resolve to the same AWS account. Every target must be
selected by at least one rule and every credential source used by at least one target; an unused entry
stops the job with target "<name>" is not referenced by any rule.
targets[].assume_role.external_id
The role owner supplies the value; see AWS guidance for third-party access.
rules
Up to 256 rules. Explicit metric selections expand to at most 256 metric/statistic pairs per rule.
rules[].profiles.include
PrivateLink detail choices are privatelink_endpoint_subnet, privatelink_service_az, privatelink_service_load_balancer, privatelink_service_az_load_balancer, and privatelink_service_vpc_endpoint. Billing choices are billing_total, billing_service, billing_linked_account, and billing_linked_account_service.
A profile that supports fewer regions than the rule (CloudFront and the Billing profiles exist only in
us-east-1) is skipped silently when selected by defaults, but stops the job when named here with only
unsupported regions.
rules[].metrics[].statistics
Spell statistics as AWS does, case-insensitively: Average, Minimum, Maximum, Sum, SampleCount, or a
percentile such as p90 or p99.9. The profile-file spelling sample_count is not accepted in a job.
rules[].metrics[].include[].statistics
Same spelling as the group list: Average, Minimum, Maximum, Sum, SampleCount, or p<N>. Each
statistic must be one the profile declares for that metric.
rules[].regions
Use canonical lowercase region codes. CloudFront and the Billing profiles support only us-east-1.
rule_defaults.query
The resolved publication_delay + lookback + period horizon cannot exceed 14 days.
rule_defaults.query.period
The period that wins for a series (metric item, then group, then rule, then this default, then the profile's metric-level query, then the profile's query) is also the one used to normalize rate metrics to per-second values.
rule_defaults.query.publication_delay
Leaving it unset falls through to the profile value and then the built-in 10m fallback. Setting it overrides profile-specific delays for every inheriting rule, including the stock S3 storage profile's conservative 24h; AWS documents only that S3 storage metrics are reported once per day, so use a shorter default only after verifying each workload's publication timing.
rule_defaults.filters.resource_tags
The Resource Groups Tagging API performs the lookup and requires the tag:GetResources permission.
labels.resource_tags
Tag values may contain personal data, so expose only keys intended for Netdata. Requires the tag:GetResources permission.
limits.max_instances
Overflow rejects the refreshed plan; collection never truncates to the first N instances. In the
configuration file 0 selects the default; the form does not accept 0.
limits.max_discovery_groups
Compatible rules and profiles share groups. One refresh can admit at most 100 groups that reach ListMetrics.
In the configuration file 0 selects the default; the form does not accept 0.
discovery.refresh_every
Also the lifetime of resolved resource tags. In the configuration file 0 selects the default; the form
does not accept 0.
discovery.recently_active_only
Profiles sharing one target, region, and namespace share one scan; the filter applies only while every participating series has publication_delay + lookback + period of three hours or less.
via UI
Configure the cloudwatch collector from the Netdata web interface:
- Go to Nodes.
- Select the node where you want the cloudwatch data-collection job to run and click the ⚙ (Configure this node). That node will run the data collection.
- The Collectors → Jobs view opens by default.
- In the Search box, type cloudwatch (or scroll the list) to locate the cloudwatch collector.
- Click the + next to the cloudwatch collector to add a new job.
- Fill in the job fields, then click Test to verify the configuration and Submit to save.
- Test runs the job with the provided settings and shows whether data can be collected.
- If it fails, an error message appears with details (for example, connection refused, timeout, or command execution errors), so you can adjust and retest.
via File
The configuration file name for this integration is go.d/cloudwatch.conf.
The file format is YAML. Generally, the structure is:
update_every: 1
autodetection_retry: 0
jobs:
- name: some_name1
- name: some_name2
You can edit the configuration file using the edit-config script from the
Netdata config directory.
cd /etc/netdata 2>/dev/null || cd /opt/netdata/etc/netdata
sudo ./edit-config go.d/cloudwatch.conf
Examples
Default credentials, single region
The minimal job. The Agent host already has an AWS identity (environment, shared config, instance profile, or IRSA), and every default-enabled profile is collected in one region.
Config
jobs:
- name: default_credentials
credentials:
- name: sdk_default
type: default
targets:
- name: base
credentials: sdk_default
rules:
- name: base-defaults
targets: [base]
regions: [us-east-1]
Static access keys
The Agent host has no AWS identity of its own. Use an access key pair from your AWS administrator, referenced from the environment rather than written in the file.
Config
jobs:
- name: static_keys
credentials:
- name: keys
type: static
type_static:
access_key_id: ${env:AWS_ACCESS_KEY_ID}
secret_access_key: ${env:AWS_SECRET_ACCESS_KEY}
targets:
- name: base
credentials: keys
rules:
- name: base-defaults
targets: [base]
regions: [us-east-1, eu-west-1]
Monitor several AWS accounts by assuming roles
One credential source assumes a different IAM role in each account you monitor. Each role needs the read policy from Prerequisites and a trust policy that allows this identity, with an external ID when the role owner requires one.
Config
jobs:
- name: cross_account
credentials:
- name: sdk_default
type: default
targets:
- name: production
credentials: sdk_default
assume_role:
role_arn: "arn:aws:iam::111111111111:role/netdata-cloudwatch-readonly"
external_id: ${env:AWS_EXTERNAL_ID}
- name: staging
credentials: sdk_default
assume_role:
role_arn: "arn:aws:iam::222222222222:role/netdata-cloudwatch-readonly"
rules:
- name: both-defaults
targets: [production, staging]
regions: [us-east-1, eu-west-1]
Collect a metric a profile leaves off by default
The EC2 profile declares CPU credit balance for burstable instances but does not collect it by default. Naming it adds it to the default EC2 metrics with the profile's statistic.
Config
jobs:
- name: ec2_with_cpu_credits
credentials:
- name: sdk_default
type: default
targets:
- name: base
credentials: sdk_default
rules:
- name: ec2
targets: [base]
profiles:
defaults: false
include: [ec2]
metrics:
- profile: ec2
include:
- name: CPUCreditBalance
regions: [us-east-1]
Read one metric at two resolutions
Lambda Duration as a five-minute average and as a one-minute p90. Each statistic is its own series with its own timing; the same metric and statistic cannot be listed twice.
Config
jobs:
- name: lambda_split_policy
credentials:
- name: sdk_default
type: default
targets:
- name: base
credentials: sdk_default
rules:
- name: lambda-duration
targets: [base]
profiles:
defaults: false
include: [lambda]
metrics:
- profile: lambda
defaults: false
query:
period: 5m
lookback: 30m
publication_delay: 10m
include:
- name: Duration
statistics: [Average]
- name: Duration
statistics: [p90]
query:
period: 1m
lookback: 5m
publication_delay: 5m
regions: [us-east-1]
Lower resolution to reduce cost
Everything at five-minute resolution with discovery every 15 minutes, for accounts where cost matters more than freshness. The daily S3 storage profile is excluded because a five-minute period with a fifteen-minute lookback can never find its once-a-day datapoint.
Config
jobs:
- name: low_resolution
update_every: 300
credentials:
- name: sdk_default
type: default
targets:
- name: base
credentials: sdk_default
rule_defaults:
query:
period: 5m
lookback: 15m
rules:
- name: five-minute-defaults
targets: [base]
profiles:
exclude: [s3]
regions: [us-east-1]
discovery:
refresh_every: 900
AWS Billing estimated charges
Month-to-date estimated charges, in total and split by service and linked account. Enable Billing metrics first (Prerequisites); they exist only in us-east-1 and have no resource tags, so any inherited tag filter is disabled for this rule.
Config
jobs:
- name: billing_estimated_charges
credentials:
- name: sdk_default
type: default
targets:
- name: billing
credentials: sdk_default
rules:
- name: billing-grains
targets: [billing]
profiles:
defaults: false
include:
- billing_total
- billing_service
- billing_linked_account
- billing_linked_account_service
regions: [us-east-1]
filters:
# Billing is not an RGTA resource. This explicitly
# disables any inherited resource-tag filter.
resource_tags: []
AWS PrivateLink endpoints with split timing
PrivateLink endpoints tagged environment=production, with per-minute connection metrics and six-hour byte totals for the same endpoints.
Config
jobs:
- name: privatelink_endpoints
credentials:
- name: sdk_default
type: default
targets:
- name: base
credentials: sdk_default
rule_defaults:
filters:
resource_tags:
- key: environment
values: [production]
rules:
- name: endpoint-split-timing
targets: [base]
profiles:
defaults: false
include: [privatelink_endpoint]
metrics:
- profile: privatelink_endpoint
defaults: false
query:
period: 1m
lookback: 5m
publication_delay: 5m
include:
- name: ActiveConnections
statistics: [Average]
- name: BytesProcessed
statistics: [Average]
- name: NewConnections
statistics: [Average]
- name: BytesProcessed
statistics: [Sum]
query:
period: 6h
lookback: 6h
publication_delay: 5m
regions: [us-east-1]
labels:
resource_tags:
- key: Name
AWS PrivateLink endpoints by subnet
The per-subnet detail grain for PrivateLink endpoints tagged environment=production. One endpoint produces one chart instance per subnet, and the subnet charts inherit the endpoint's tags.
Config
jobs:
- name: privatelink_endpoint_subnets
credentials:
- name: sdk_default
type: default
targets:
- name: base
credentials: sdk_default
rule_defaults:
filters:
resource_tags:
- key: environment
values: [production]
rules:
- name: endpoint-subnets
targets: [base]
profiles:
defaults: false
include: [privatelink_endpoint_subnet]
regions: [us-east-1]
labels:
resource_tags:
- key: Name
AWS PrivateLink services with split timing
The provider side of PrivateLink, for services tagged environment=production. Per-minute traffic, a five-minute connected-endpoint count, and six-hour byte totals.
Config
jobs:
- name: privatelink_services
credentials:
- name: sdk_default
type: default
targets:
- name: base
credentials: sdk_default
rule_defaults:
filters:
resource_tags:
- key: environment
values: [production]
rules:
- name: service-split-timing
targets: [base]
profiles:
defaults: false
include: [privatelink_service]
metrics:
- profile: privatelink_service
defaults: false
query:
period: 1m
lookback: 5m
publication_delay: 5m
include:
- name: ActiveConnections
statistics: [Average]
- name: BytesProcessed
statistics: [Average]
- name: NewConnections
statistics: [Average]
- name: RstPacketsSent
statistics: [Average]
- name: EndpointsCount
statistics: [Average]
query:
period: 5m
lookback: 5m
publication_delay: 5m
- name: BytesProcessed
statistics: [Sum]
query:
period: 6h
lookback: 6h
publication_delay: 5m
regions: [us-east-1]
labels:
resource_tags:
- key: Name
Everything, including opt-in profiles
Every default profile plus every opt-in grain in one region. Read the cardinality and cost notes under Metrics and Performance Impact before using this on a large account.
Config
jobs:
- name: defaults_and_opt_in
credentials:
- name: sdk_default
type: default
targets:
- name: base
credentials: sdk_default
rules:
- name: expanded-services
targets: [base]
profiles:
defaults: true
include:
- alb_target
- dynamodb_operation
- s3_requests
- ebs_stalled_io
- privatelink_endpoint_subnet
- privatelink_service_az
- privatelink_service_load_balancer
- privatelink_service_az_load_balancer
- privatelink_service_vpc_endpoint
- billing_total
- billing_service
- billing_linked_account
- billing_linked_account_service
regions: [us-east-1]
Filter resources by tag and add tag labels
Only resources tagged managed-by=platform, with the Name and owner tags shown as chart labels. Profiles Netdata ships no resource-tag association for (CloudFront, API Gateway, ElastiCache, MSK, Auto Scaling, Bedrock, the ALB and NLB target-health grains) cannot be tag-filtered and are skipped by a filtered rule; collect them from a second rule that disables the inherited filter, as the CloudFront rule does.
Config
jobs:
- name: tagged_resources
credentials:
- name: sdk_default
type: default
targets:
- name: base
credentials: sdk_default
rule_defaults:
filters:
resource_tags:
- key: managed-by
values: [platform]
rules:
- name: filtered-defaults
targets: [base]
regions: [us-east-1]
- name: unfiltered-cloudfront
targets: [base]
profiles:
defaults: false
include: [cloudfront]
regions: [us-east-1]
filters:
resource_tags: []
labels:
resource_tags:
- key: Name
- key: owner
label: resource_owner
Present AWS metrics on a virtual node
Show the AWS charts as their own Netdata node instead of on the host running the collector. The virtual node must already exist in the Agent's vnodes configuration.
Config
jobs:
- name: aws_production
vnode: aws-production
credentials:
- name: sdk_default
type: default
targets:
- name: base
credentials: sdk_default
rules:
- name: base-defaults
targets: [base]
regions: [us-east-1]
Alerts
The following alerts are available:
| Alert name | On metric | Description |
|---|---|---|
| aws_cloudwatch_ec2_status_check_failed | cloudwatch.ec2.status_check_failed | EC2 instance ${label:instance_id} in ${label:region} has failed AWS status checks. |
| aws_cloudwatch_ec2_attached_ebs_status_check_failed | cloudwatch.ec2.status_check_failed | EC2 instance ${label:instance_id} in ${label:region} has an attached EBS volume failing AWS status checks. |
| aws_cloudwatch_alb_target_group_unhealthy_hosts | cloudwatch.alb_target_health.unhealthy_hosts | ALB target group ${label:target_group} on load balancer ${label:load_balancer} in ${label:region} has sustained unhealthy registered targets. |
| aws_cloudwatch_nlb_target_group_unhealthy_hosts | cloudwatch.nlb_target_health.unhealthy_hosts | NLB target group ${label:target_group} on load balancer ${label:load_balancer} in ${label:region} has sustained unhealthy registered targets. |
| aws_cloudwatch_ebs_stalled_io_check_failed | cloudwatch.ebs_stalled_io.stalled_io_check | EBS volume ${label:volume_id} in ${label:region} has failed AWS stalled I/O checks. |
| aws_cloudwatch_nat_gateway_port_allocation_errors | cloudwatch.nat_gateway.errors | NAT Gateway ${label:nat_gateway_id} in ${label:region} is reporting source-port allocation failures. |
| aws_cloudwatch_efs_io_limit_reached | cloudwatch.efs.io_limit | EFS file system ${label:file_system_id} in ${label:region} is at its AWS PercentIOLimit threshold. |
| aws_cloudwatch_efs_burst_credits_exhausted | cloudwatch.efs.burst_credit | EFS file system ${label:file_system_id} in ${label:region} has exhausted burst credits. |
| aws_cloudwatch_ecs_cpu_utilization | cloudwatch.ecs.utilization | ECS service ${label:service_name} in cluster ${label:cluster_name} (${label:region}) has sustained CPU utilization above the AWS recommended alarm threshold. |
| aws_cloudwatch_ecs_memory_utilization | cloudwatch.ecs.utilization | ECS service ${label:service_name} in cluster ${label:cluster_name} (${label:region}) has sustained memory utilization above the AWS recommended alarm threshold. |
| aws_cloudwatch_ecs_ebs_filesystem_utilization | cloudwatch.ecs.ebs_filesystem_utilization | ECS service ${label:service_name} in cluster ${label:cluster_name} (${label:region}) has sustained EBS filesystem utilization above the AWS recommended alarm threshold. |
| aws_cloudwatch_opensearch_cluster_status_red | cloudwatch.opensearch.cluster_status | OpenSearch domain ${label:domain_name} in ${label:region} is reporting red cluster status. |
| aws_cloudwatch_opensearch_cluster_status_yellow | cloudwatch.opensearch.cluster_status | OpenSearch domain ${label:domain_name} in ${label:region} is reporting yellow cluster status. |
| aws_cloudwatch_opensearch_index_writes_blocked | cloudwatch.opensearch.index_writes_blocked | OpenSearch domain ${label:domain_name} in ${label:region} is blocking index write requests. |
| aws_cloudwatch_opensearch_jvm_memory_pressure | cloudwatch.opensearch.jvm_memory_pressure | OpenSearch domain ${label:domain_name} in ${label:region} has sustained JVM memory pressure above the AWS recommended alarm threshold. |
| aws_cloudwatch_opensearch_cpu_utilization | cloudwatch.opensearch.cpu | OpenSearch domain ${label:domain_name} in ${label:region} has sustained maximum CPU utilization above the AWS recommended alarm threshold. |
| aws_cloudwatch_opensearch_automated_snapshot_failure | cloudwatch.opensearch.automated_snapshot_failure | OpenSearch domain ${label:domain_name} in ${label:region} has a failed automated snapshot. |
| aws_cloudwatch_opensearch_old_gen_jvm_memory_pressure | cloudwatch.opensearch.old_gen_jvm_memory_pressure | OpenSearch domain ${label:domain_name} in ${label:region} has sustained old-generation JVM memory pressure above the AWS recommended alarm threshold. |
| aws_cloudwatch_elasticache_engine_cpu_utilization | cloudwatch.elasticache.cpu | ElastiCache node ${label:cache_cluster_id}/${label:cache_node_id} in ${label:region} has sustained engine CPU utilization above the AWS recommended alarm threshold. |
| aws_cloudwatch_msk_active_controller_missing | cloudwatch.msk_cluster.active_controllers | MSK cluster ${label:cluster_name} in ${label:region} has had no active controller for a sustained period. |
| aws_cloudwatch_msk_multiple_active_controllers | cloudwatch.msk_cluster.active_controllers | MSK cluster ${label:cluster_name} in ${label:region} has had more than one active controller for a sustained period. |
| aws_cloudwatch_msk_offline_partitions | cloudwatch.msk_cluster.offline_partitions | MSK cluster ${label:cluster_name} in ${label:region} has had offline partitions for a sustained period. |
| aws_cloudwatch_msk_cpu_utilization | cloudwatch.msk.cpu | MSK broker ${label:broker_id} in cluster ${label:cluster_name} (${label:region}) has sustained CpuUser plus CpuSystem above the AWS best-practice threshold. |
| aws_cloudwatch_msk_data_logs_disk_used | cloudwatch.msk.disk_used | MSK broker ${label:broker_id} in cluster ${label:cluster_name} (${label:region}) has sustained data-log disk utilization above the AWS best-practice threshold. |
| aws_cloudwatch_msk_heap_memory_after_gc | cloudwatch.msk.heap_memory_after_gc | MSK broker ${label:broker_id} in cluster ${label:cluster_name} (${label:region}) has sustained heap memory after GC above the AWS best-practice threshold. |
| aws_cloudwatch_msk_under_replicated_partitions | cloudwatch.msk.partitions | MSK broker ${label:broker_id} in cluster ${label:cluster_name} (${label:region}) has had under-replicated partitions for a sustained period. This can happen during planned MSK rolling maintenance, but outside expected maintenance it means replicas are not fully caught up. |
| aws_cloudwatch_msk_under_min_isr_partitions | cloudwatch.msk.under_min_isr | MSK broker ${label:broker_id} in cluster ${label:cluster_name} (${label:region}) has had partitions below the configured minimum in-sync replica count for a sustained period. |
| aws_cloudwatch_rds_replica_lag | cloudwatch.rds.replica_lag | RDS instance ${label:db_instance_identifier} in ${label:region} has sustained replica lag above the AWS recommended alarm threshold. |
| aws_cloudwatch_rds_maximum_used_transaction_ids | cloudwatch.rds.maximum_used_transaction_ids | RDS instance ${label:db_instance_identifier} in ${label:region} is above the AWS recommended transaction ID alarm threshold. |
| aws_cloudwatch_rds_ebs_byte_balance | cloudwatch.rds.ebs_balance | RDS instance ${label:db_instance_identifier} in ${label:region} has sustained EBS byte balance below the AWS recommended alarm threshold. |
| aws_cloudwatch_rds_ebs_io_balance | cloudwatch.rds.ebs_balance | RDS instance ${label:db_instance_identifier} in ${label:region} has sustained EBS I/O balance below the AWS recommended alarm threshold. |
| aws_cloudwatch_vpn_tunnel_down | cloudwatch.vpn.tunnel_state | Site-to-Site VPN ${label:vpn_id} in ${label:region} has one or more tunnels down. |
| aws_cloudwatch_sns_invalid_notification_attributes | cloudwatch.sns.invalid_notifications | SNS topic ${label:topic_name} in ${label:region} has sustained notifications filtered out because of invalid attributes. |
| aws_cloudwatch_sns_invalid_notification_body | cloudwatch.sns.invalid_notifications | SNS topic ${label:topic_name} in ${label:region} has sustained notifications filtered out because of invalid message bodies. |
| aws_cloudwatch_sns_notifications_redriven_to_dlq | cloudwatch.sns.dlq_redrive | SNS topic ${label:topic_name} in ${label:region} has sustained notifications moved to a dead-letter queue. |
| aws_cloudwatch_sns_notifications_failed_to_redrive_to_dlq | cloudwatch.sns.dlq_redrive | SNS topic ${label:topic_name} in ${label:region} has sustained notifications that could not be moved to a dead-letter queue. |
Metrics
Metrics grouped by scope.
The scope defines the instance that the metric belongs to. An instance is uniquely identified by a set of labels.
Charts come from the selected profiles. Each stock profile is linked below and is the authoritative list of its metrics, statistics, dimensions, and charts; to see exactly what one job collects, open the Metrics tab of its dashboard.
Every chart instance is one AWS resource, identified by account_id, region, and the profile's identifying
dimensions (for example EC2 instance_id, or S3 bucket_name and storage_type). A dimension that is the same
for every resource of a profile (CloudFront's Region=Global) is matched but not shown as a label. Tags selected
with labels.resource_tags are added as labels that are not part of the chart identity, so a changed tag changes
the label, not the chart. Charts land on the job's vnode when one is set, otherwise on the node running the
collector; AWS resources never become separate Netdata nodes. CloudWatch publishes with a delay, so allow a few
minutes for the first datapoints.
The four collector-activity charts in the scopes below are fixed and present in every job. They count the collector's own AWS API work for cost visibility (see Performance Impact).
Default profiles, collected by any rule that does not restrict profiles:
| Profile | Metric prefix | Description |
|---|---|---|
| Amazon EC2 | cloudwatch.ec2.* | CPU utilization, network traffic, disk operations, status-check failures, attached-EBS status-check failures |
| Amazon RDS | cloudwatch.rds.* | CPU utilization, database connections, freeable memory, swap usage, free storage space, disk queue depth, disk and network throughput, IOPS, latency, replica lag, PostgreSQL transaction ID usage, EBS credit balance |
| Classic Load Balancer (ELB) | cloudwatch.elb.* | request count, backend and load-balancer response codes, backend connection errors, latency, host count, spillover count |
| Application Load Balancer (ALB) | cloudwatch.alb.* | request count, target and load-balancer response codes, connection rate, active connections, processed traffic, target response time, consumed LCUs |
| ALB Target Health | cloudwatch.alb_target_health.* | per-target-group unhealthy host count |
| Network Load Balancer (NLB) | cloudwatch.nlb.* | active and new flow counts, processed bytes and packets, consumed LCUs, TCP resets |
| NLB Target Health | cloudwatch.nlb_target_health.* | per-target-group unhealthy host count |
| Amazon S3 | cloudwatch.s3.* | bucket size, number of objects (daily storage metrics) |
| AWS Lambda | cloudwatch.lambda.* | invocations, errors and throttles, duration |
| Amazon SQS | cloudwatch.sqs.* | message throughput, empty receives, queue depth, maximum age of oldest message, sent message size |
| Amazon DynamoDB | cloudwatch.dynamodb.* | consumed and provisioned capacity, throttle events |
| Amazon API Gateway | cloudwatch.api_gateway.* | requests, errors, latency |
| AWS Step Functions | cloudwatch.step_functions.* | executions, throttled events, execution time |
| NAT Gateway | cloudwatch.nat_gateway.* | traffic, active connections, connection rate, errors, idle timeouts |
| AWS PrivateLink endpoints | cloudwatch.privatelink_endpoint.* | endpoint-level active and new connections, processed bytes, dropped packets, and received reset packets |
| AWS PrivateLink endpoint services | cloudwatch.privatelink_service.* | provider-side active and new connections, connected endpoints, processed bytes, and sent reset packets |
| Amazon Kinesis Data Streams | cloudwatch.kinesis.* | data throughput, records, GetRecords iterator age, operation latency, throughput exceeded, PutRecords rejected |
| Amazon Data Firehose | cloudwatch.firehose.* | records, throughput, put requests, throttled records, S3 delivery freshness and success |
| Amazon SNS | cloudwatch.sns.* | messages published, notifications, invalid notification filters, DLQ redrive, published message size |
| Amazon EBS | cloudwatch.ebs.* | volume throughput, IOPS, queue length, idle time, burst balance |
| Amazon EFS | cloudwatch.efs.* | I/O throughput, metered vs permitted throughput, percent I/O limit, burst credit balance, client connections |
| Amazon ECS | cloudwatch.ecs.* | service utilization, EBS filesystem utilization, live task count |
| Amazon ElastiCache | cloudwatch.elasticache.* | CPU utilization, memory, database memory usage, current and new connections, cache hits and misses, evictions, network traffic |
| Amazon OpenSearch Service | cloudwatch.opensearch.* | cluster status, index writes blocked, automated snapshot failures, nodes, CPU utilization, JVM memory pressure, old-gen JVM memory pressure, free storage space, search and indexing rate, search and indexing latency |
| Amazon DocumentDB | cloudwatch.docdb.* | CPU utilization, freeable memory, connections, buffer cache hit ratio, disk IOPS, latency, throughput, replica lag, cursors timed out |
| Amazon Redshift | cloudwatch.redshift.* | health, CPU utilization, disk space used, database connections, disk IOPS, throughput, network throughput |
| Amazon MSK | cloudwatch.msk.* | broker throughput, messages in, CPU, disk used, memory, heap memory after GC, partitions, under-min-ISR partitions, connections |
| Amazon MSK Cluster | cloudwatch.msk_cluster.* | active controllers and offline partitions |
| Amazon CloudFront | cloudwatch.cloudfront.* | requests, downloaded and uploaded traffic, total/4xx/5xx error rates (us-east-1 only) |
| AWS Auto Scaling | cloudwatch.auto_scaling.* | group sizing (min/max/desired/total) and instances by state (in-service, pending, standby, terminating) |
| Amazon Bedrock | cloudwatch.bedrock.* | invocations, invocation errors, token throughput, invocation and time-to-first-token latency |
| Amazon EventBridge | cloudwatch.eventbridge.* | target invocations, rule activity (matched events, triggered rules), ingestion-to-invocation latency |
| AWS Site-to-Site VPN | cloudwatch.vpn.* | tunnel traffic (in/out) and tunnel state (fraction of tunnels up) |
| Amazon EKS | cloudwatch.eks.* | control-plane health: API server request rate, errors, p99 latency, and in-flight requests; etcd database size; scheduler pending pods and scheduling attempts |
Opt-in profiles, collected when a rule names them in profiles.include:
| Profile | Metric prefix | Description |
|---|---|---|
| ALB Target Groups | cloudwatch.alb_target.* | per-target-group host count, requests per target, response time, response codes, connection errors |
| DynamoDB Operations | cloudwatch.dynamodb_operation.* | per-operation successful request latency, system errors, throttled requests, returned items |
| EBS Stalled I/O | cloudwatch.ebs_stalled_io.* | per-volume stalled I/O health check; the EBS stalled I/O alert fires only when a rule opts into this profile |
| S3 Request Metrics | cloudwatch.s3_requests.* | requests, request errors, request latency, request data transfer; needs per-bucket request metrics enabled in AWS |
| AWS PrivateLink endpoints by subnet | cloudwatch.privatelink_endpoint_subnet.* | the endpoint metrics split by subnet_id; one endpoint can produce several chart instances, which inherit the endpoint's tags |
| AWS PrivateLink services by Availability Zone | cloudwatch.privatelink_service_az.* | provider-side traffic split by availability_zone and service_id |
| AWS PrivateLink services by load balancer | cloudwatch.privatelink_service_load_balancer.* | provider-side traffic split by load_balancer_arn and service_id |
| AWS PrivateLink services by Availability Zone and load balancer | cloudwatch.privatelink_service_az_load_balancer.* | provider-side traffic split by availability_zone, load_balancer_arn, and service_id |
| AWS PrivateLink services by VPC endpoint | cloudwatch.privatelink_service_vpc_endpoint.* | provider-side traffic split by service_id and consumer vpc_endpoint_id; tags come from the parent endpoint service, never from the consumer endpoint |
| AWS Billing total | cloudwatch.billing_total.* | latest worldwide estimated month-to-date charge |
| AWS Billing by service | cloudwatch.billing_service.* | estimated charges by service_name |
| AWS Billing by linked account | cloudwatch.billing_linked_account.* | estimated charges by linked_account_id, when the payer account publishes this grain |
| AWS Billing by linked account and service | cloudwatch.billing_linked_account_service.* | estimated charges by linked_account_id and service_name, when available |
S3 Request Metrics are billed by AWS at custom-metric rates once enabled on a bucket. The PrivateLink detail grains multiply chart instances by subnets, Availability Zones, load balancers, and consumer endpoints. The Billing service and linked-account grains grow with the payer's services and accounts. Select only the grains you need.
A stock profile can also declare opt-in metrics (disabled: true on the metric); enable one through
rules[].metrics[].include without copying the profile. Billing charts show the latest published month-to-date
estimate in USD for the whole account; region=us-east-1 is where AWS publishes them, not where the charge
occurred, and around the UTC month boundary the previous month's value stays until AWS publishes the new one.
Per AWS account, region, and operation
Collector-issued CloudWatch SDK work attributed to one resolved AWS account, region, and SDK operation.
Labels:
| Label | Description |
|---|---|
| account_id | Resolved AWS account ID. |
| region | AWS region where the collector attempted the SDK invocation. |
| operation | Collector-issued CloudWatch SDK operation (list_metrics or get_metric_data). |
Metrics:
| Metric | Description | Dimensions | Unit |
|---|---|---|---|
| cloudwatch.collector_sdk_invocations | CloudWatch SDK Invocations | invocations | invocations |
Per AWS account and region
Calculated CloudWatch metric requests attributed to one resolved AWS account and region.
Labels:
| Label | Description |
|---|---|
| account_id | Resolved AWS account ID. |
| region | AWS region where the collector submitted the metric requests. |
Metrics:
| Metric | Description | Dimensions | Unit |
|---|---|---|---|
| cloudwatch.collector_get_metric_data_calculated_metric_requests | GetMetricData Calculated Metric Requests | calculated_metric_requests | metric requests |
Per AWS account, region, and profile
CloudWatch metric-data request estimates and query items attributed to their source profile for cost ranking and collection-plan tuning.
Labels:
| Label | Description |
|---|---|
| account_id | Resolved AWS account ID. |
| region | AWS region where the collector submitted the requests. |
| profile | CloudWatch profile that produced the submitted query items. |
Metrics:
| Metric | Description | Dimensions | Unit |
|---|---|---|---|
| cloudwatch.collector_get_metric_data_profile_metric_request_estimates | GetMetricData Profile Metric Request Estimates | estimated_metric_requests | metric requests |
| cloudwatch.collector_get_metric_data_query_items | GetMetricData Query Items | query_items | query items |
Troubleshooting
Diagnostics
Debug Mode
Important: Debug mode is not supported for data collection jobs created via the UI using the Dyncfg feature.
To troubleshoot issues with the cloudwatch collector, run the go.d.plugin with the debug option enabled. The output
should give you clues as to why the collector isn't working.
-
Navigate to the
plugins.ddirectory, usually at/usr/libexec/netdata/plugins.d/. If that's not the case on your system, opennetdata.confand look for thepluginssetting under[directories].cd /usr/libexec/netdata/plugins.d/ -
Switch to the
netdatauser.sudo -u netdata -s -
Run the
go.d.pluginto debug the collector:./go.d.plugin -d -m cloudwatchTo debug a specific job:
./go.d.plugin -d -m cloudwatch -j jobName
Getting Logs
If you're encountering problems with the cloudwatch collector, follow these steps to retrieve logs and identify potential issues:
- Run the command specific to your system (systemd, non-systemd, or Docker container).
- Examine the output for any warnings or error messages that might indicate issues. These messages should provide clues about the root cause of the problem.
System with systemd
Use the following command to view logs generated since the last Netdata service restart:
journalctl _SYSTEMD_INVOCATION_ID="$(systemctl show --value --property=InvocationID netdata)" --namespace=netdata --grep cloudwatch
System without systemd
Locate the collector log file, typically at /var/log/netdata/collector.log, and use grep to filter for collector's name:
grep cloudwatch /var/log/netdata/collector.log
Note: This method shows logs from all restarts. Focus on the latest entries for troubleshooting current issues.
Docker Container
If your Netdata runs in a Docker container named "netdata" (replace if different), use this command:
docker logs netdata 2>&1 | grep cloudwatch
Known Errors
AWS request failed (code=AccessDeniedException, status=403, request_id=...)
When
Logged as part of a CloudWatch <operation> failed for N target/region operation(s) warning, where the
operation is account resolution, discovery, GetMetricData, query client creation, or
resource tag lookup. The codes AccessDenied, NotAuthorized, and Forbidden mean the same.
Cause
The IAM identity behind the named target is not allowed the AWS action that operation uses:
cloudwatch:ListMetrics for discovery, cloudwatch:GetMetricData for reads, tag:GetResources for tag
lookups, or sts:AssumeRole when the target assumes a role. The collector never prints the AWS message
itself, only the code, HTTP status, and request id.
Fix
Attach the policy from Prerequisites to that identity, adding tag:GetResources if the job uses tag
filters or labels. For a target with assume_role, allow sts:AssumeRole on the role ARN for the source
identity and let the role's trust policy accept it. The next discovery refresh or collection cycle retries
automatically.
AWS request failed (code=ExpiredToken, status=403, request_id=...)
When
Also ExpiredTokenException, InvalidClientTokenId, UnrecognizedClientException, or
SignatureDoesNotMatch.
Cause
The credential source is expired, revoked, mistyped, or belongs to a different AWS partition than the regions it is used for.
Fix
Renew or correct the credentials. For a static source, check the access_key_id and secret_access_key
values and, for temporary keys, the session_token; prefer ${env:NAME} references so a rotated key is
picked up without editing the file. For the default source, check what the AWS SDK finds on the Agent
host (aws sts get-caller-identity as the netdata user).
AWS request failed
When
The message carries no code= and no status=.
Cause
The request never reached AWS or got no AWS answer: DNS resolution, an outbound firewall or proxy, or TLS interception on the Agent host. Provider-side detail is deliberately not logged.
Fix
From the Agent host, as the netdata user, run aws sts get-caller-identity --region <region> and
aws cloudwatch list-metrics --region <region> --max-items 1; the AWS CLI shows the underlying network or
TLS error. Allow outbound HTTPS to the CloudWatch, STS, and Tagging endpoints of every selected region, or
configure the proxy through the standard HTTPS_PROXY environment of the Netdata service.
AWS request timed out
Cause
An AWS call exceeded timeout (default 30 seconds). A whole discovery refresh and a whole resource tag
lookup share one timeout; each GetMetricData and STS call has its own.
Fix
Raise timeout, or make the work smaller: fewer regions and profiles per rule, resource tag filters,
or split the job. A timed-out discovery refresh is discarded and retried after discovery.refresh_every;
a timed-out read is retried on the next collection.
AWS request failed (code=Throttling, status=400, request_id=...)
When
Also ThrottlingException or RequestLimitExceeded.
Cause
The account exceeded the CloudWatch API request rate. The AWS SDK already attempts each call up to five times with a short backoff before this is logged, so the job is well above the rate.
Fix
Reduce request volume: a longer period in rule_defaults.query, a longer update_every, fewer metrics
or regions, or split targets across jobs that do not run at the same second. Retried reads are billed.
no AWS target could be resolved (N failed); last failure for target "<name>" region "<region>": ...
Cause
sts:GetCallerIdentity failed for every target, so the job has no AWS account to attribute metrics to.
The trailing text is one of the AWS request ... messages above and names the actual reason.
Fix
Fix the credentials or network problem named in the trailing message. Targets that fail while others succeed are retried every cycle without failing the job; only total failure stops collection.
target "<name>" is not referenced by any rule
When
Also credential "<name>" is not referenced by any target. The job does not start.
Cause
Every target must be selected by at least one rule and every credential source used by at least one target; an unused entry is treated as a configuration mistake rather than ignored.
Fix
Reference the entry from a rule (or target), or remove it.
'credentials' must contain at least one entry
When
Together with 'targets' must contain at least one entry and 'rules' must contain at least one entry
when the job has no configuration at all.
Cause
The job is missing one of the three required blocks. Nothing is collected by default.
Fix
Add at least one credential source, one target that references it, and one rule with targets and
regions; see the first example under Setup.
rules[N].name "<name>" must match "^[a-z][a-z0-9_-]{0,63}$"
When
The same for credentials[N].name and targets[N].name.
Cause
Names are lowercase, start with a letter, use only letters, digits, _ and -, and are at most 64
characters. Duplicate names produce duplicate rule name "<name>" (or target, credential).
Fix
Rename the entry and update the places that reference it (targets[].credentials, rules[].targets).
rules[N].regions[M] "US-EAST-1" is not canonical; use "us-east-1"
When
Also rules[N].regions[M] "<value>" is not a valid AWS region.
Cause
Regions must be the lowercase AWS region code such as us-east-1 or eu-west-1.
Fix
Correct the region code.
target "<name>" spans multiple AWS partitions across regions [...]
When
Also target "<name>" role partition "aws" does not match selected region partition "aws-us-gov".
Cause
All regions collected for one target must belong to one AWS partition (standard aws, GovCloud
aws-us-gov, China aws-cn), and an assumed role's ARN must belong to the same partition.
Fix
Give each partition its own target (and rule), or split the job per partition, and use a role ARN of the matching partition.
rules[N] explicitly includes profile "cloudfront", but none of regions [...] are supported
Cause
Some profiles exist only in us-east-1 (CloudFront and the four Billing profiles). When such a profile is
selected by defaults it is silently skipped for other regions; when it is named in profiles.include or in
a rules[].metrics[] group with only unsupported regions the job refuses to start.
Fix
Add us-east-1 to the rule's regions, or collect that profile from a separate rule limited to
us-east-1.
rules[N].profiles.include references unknown profile "<name>"
Cause
No loaded profile has that basename: a typo, or a user profile that was added after the plugin started. Profiles are read once at startup.
Fix
Use the basename of a file under /usr/lib/netdata/conf.d/go.d/cloudwatch.profiles/default/ or
/etc/netdata/go.d/cloudwatch.profiles/; after adding a profile, restart Netdata.
rules[N].metrics[M].include[K].name references unknown MetricName "<name>" in profile "<profile>"
When
Also ... "<statistic>" is not exported for MetricName "<name>" in profile "<profile>".
Cause
An explicit metric selection must name a metric the profile declares, spelled exactly as AWS does
(CPUUtilization, not cpu_utilization), with a statistic the profile declares for it.
Fix
Open the profile file and copy the metric_name and statistics from its metrics list.
rules[N].metrics[M].statistics[K] is not valid (use Average|Minimum|Maximum|Sum|SampleCount|p<N>)
Cause
In job configuration statistics use the AWS spelling, case-insensitively: Average, Minimum,
Maximum, Sum, SampleCount, or a percentile such as p90 or p99.9. The message does not echo the
value that failed; the common case is the profile-file spelling sample_count, which a job does not
accept.
Fix
Write SampleCount.
rules[N] derives N discovery groups (unique target, region, namespace combinations); exceeds limits.max_discovery_groups=64; ...
Cause
Every unique combination of target, region, and CloudWatch namespace is one ListMetrics discovery
group. Many targets times many regions times many services exceeds the safeguard, which defaults to 64
and cannot exceed 100.
Fix
Check that the rule does not select more targets, regions, or profiles than intended. For intentional
scale, raise limits.max_discovery_groups up to 100; beyond that, split the collection across jobs (for
example one job per target or per region group).
CloudWatch query plan contains more than limits.max_instances=1000 final instances
Cause
After discovery and tag filtering the job would collect more resources than limits.max_instances. The
collector refuses the plan rather than collecting a subset, so no metrics are collected until it fits.
Fix
Narrow the selection (rules[].regions, rules[].profiles, resource tag filters) or raise
limits.max_instances deliberately, knowing that every resource adds to the AWS bill.
CloudWatch query plan would exceed maximum 20000 queries
When
Also CloudWatch query plan requires more than 600000 datapoints per all-due pass or
... more than 40 GetMetricData batches per all-due pass.
Cause
The whole plan, evaluated as if every series were due at once, is larger than the collector will query safely. Only very broad rules across many regions, services, and resources reach these bounds.
Fix
Narrow regions, profiles, or metrics, use resource tag filters, or split the collection across jobs.
CloudWatch discovery refresh was discarded atomically: ...
When
Also CloudWatch discovery stage timed out, or a
CloudWatch discovery failed for N target/region operation(s) warning. Logged at most once per hour.
Cause
A discovery refresh exceeded timeout or one of its internal size bounds. The previous set of
resources stays in use and discovery retries after discovery.refresh_every; on a job's first refresh
only profiles with constant dimensions (billing_total) can collect until discovery succeeds.
Fix
Raise timeout, narrow the rule's regions and profiles, or split the job. If the failure names a
specific target and region, check that identity's cloudwatch:ListMetrics permission.
CloudWatch GetMetricData returned Forbidden for N metric result(s): ...; verify each target identity is allowed cloudwatch:GetMetricData
Cause
AWS accepted the request but refused some of the metrics in it, which happens when a target's identity
lacks cloudwatch:GetMetricData or a policy condition excludes the namespace.
Fix
Grant cloudwatch:GetMetricData without namespace conditions to the identity of the target named in the
message.
CloudWatch GetMetricData left N metric result(s) unresolved: ...; retained values are replayed and retries use per-query exponential backoff
Cause
AWS returned PartialData or InternalError for some metrics, or a result did not come back. The
collector keeps showing the last value it has and retries with a doubling delay up to one period.
Fix
Nothing, unless it persists across many collections; then check the AWS Health Dashboard for the
region and reduce the request volume (fewer metrics, longer period).
all due CloudWatch queries failed transiently and no retained observations are available
Cause
Every read due in this collection failed and the job has no earlier values to repeat, so the collection cycle fails. On a new job this usually means AWS is unreachable or throttling; on a running job it follows a long outage.
Fix
Look for the AWS request ... warning logged just before it and follow its entry above.
CloudWatch discovered N instances; this scales GetMetricData cost — narrow collection rules if this is unexpected
Cause
Discovery found 1,000 or more resources. Collection is not truncated; the warning exists because every resource multiplies the AWS bill.
Fix
If the count is expected, ignore it. Otherwise narrow regions, profiles, or add resource tag filters,
and read the Performance Impact section.
CloudWatch collection plan: rule "<name>" has N metric selection(s) shadowed by earlier rules; example: ...
When
Also
CloudWatch collection rules shadowed N duplicate exported series; earliest matching rule/target order owns each series.
Cause
Two rules select the same series for the same target and region. The earlier rule (and, within it, the earlier target) owns the series; the later selection is ignored, including its query timing.
Fix
Make the rules disjoint (different profiles, regions, or targets), or move the selection you want to win into the earlier rule.
CloudWatch collection plan: rule "<name>" skips default profiles unsupported in its regions: ...
Cause
A default-enabled profile that exists only in us-east-1 (CloudFront, Billing) was selected by defaults
for a rule whose regions do not include it. It is skipped there; no error.
Fix
Nothing, or add a rule for us-east-1 if you want that service.
CloudWatch tags (profile "<profile>"): skipped tag "<tag>": label "<label>" collides with a dimension label (rename it)
Cause
A tag selected in labels.resource_tags would become a label that the profile already uses for a
dimension (or one of the reserved account_id and region labels). The tag is not attached.
Fix
Set labels.resource_tags[].label to another name for that key.
load CloudWatch profiles: validate profile "<name>": ...
When
Also unmarshal profile "<name>": ... (invalid YAML) or normalize profile "<name>": .... Every
CloudWatch job on the Agent fails, not only the one that uses the profile.
Cause
A profile under /etc/netdata/go.d/cloudwatch.profiles/ does not parse or breaks a profile rule; the
trailing text names the field. Profiles are loaded once for the whole plugin, so one bad file stops all
jobs.
Fix
Fix or remove the file following the profile format and restart Netdata.
rules[N] explicitly includes profile "<name>" with resource tag filtering, but it has no safe tag association: profile is not registered
When
The non-fatal sibling for profiles selected by defaults is
CloudWatch collection plan: rule "<name>" skips default profiles without a safe resource-tag association: ....
Cause
Resource tag filters need a mapping from the profile's CloudWatch dimensions to a taggable AWS resource, and Netdata ships none for this profile (CloudFront and the Billing profiles, among others). A profile named explicitly under a tag filter cannot be filtered, so the job refuses to start; a default-selected one is skipped with a warning.
Fix
Give that profile its own rule with filters: {resource_tags: []} to collect it unfiltered, or drop it from
the filtered rule.
credentials[N].type_static is required
When
Also credentials[N].type_static is not allowed when credentials[N].type is "default",
credentials[N].type "<value>" is invalid: expected one of "default", "static",
credentials[N].type_static.access_key_id is required, or ... must not contain surrounding whitespace.
Cause
The credential block does not match its type: static needs type_static with access_key_id and
secret_access_key; default takes no type_static; values must not be padded with spaces.
Fix
Shape the block as the two examples under Setup show (type: default alone, or type: static with
type_static).
rules[N].profiles.include must not be empty when defaults is false
When
Also rules[N].profiles selects no profiles (exclusions removed everything) or
rules[N] compiles to no collection scopes (every selected profile was filtered away by regions or tag
associations).
Cause
The rule ends up selecting nothing. Narrowing with defaults: false, exclude, region-restricted
profiles, or tag filters went one step too far.
Fix
Name at least one profile in include, remove the exclusion that empties the set, or add a region the
selected profiles support.
targets[N].assume_role.role_arn is invalid: expected an IAM role ARN
When
Also ... is invalid: invalid ARN syntax.
Cause
The value is not a role ARN of the form arn:<partition>:iam::<12-digit-account>:role/<name>.
Fix
Copy the role ARN from the IAM console; it must name the iam service, have no region, a 12-digit
account id, and a role/ resource.
candidate collection scopes exceed maximum 16384
When
Also compiled collection scopes exceed maximum 4096.
Cause
Targets times profiles times regions, before or after filtering, is larger than the collector will compile. Only rules that combine many targets, all profiles, and many regions reach this.
Fix
Split the collection across jobs, for example one job per target or per region group.
CloudWatch resource tag filtering reserved N exported series from lower-priority rules while membership was unknown
When
Preceded by
CloudWatch resource tag lookup failed for N target/region operation(s): ... (retaining fail-closed membership and last-known labels).
Cause
The tag lookup (tag:GetResources) failed, so the collector does not know which resources match the
filter. It keeps the last known membership and labels, and resources whose membership is unknown stay
uncollected rather than being collected unfiltered.
Fix
Follow the AWS request ... message inside the lookup failure (usually a missing tag:GetResources
permission or a timeout on a large tagged estate; raise timeout for the latter). Collection resumes on
the next successful lookup.
No charts appear although the job runs without errors
Cause
CloudWatch has nothing for the selection yet. Typical reasons: the resources are idle (several services,
such as EventBridge and Bedrock, publish a metric only when its value is non-zero); the metric is not
enabled on the AWS side (Auto Scaling group metrics need enable-metrics-collection; EKS control-plane
metrics exist only for Kubernetes 1.28 or later; S3 request metrics need per-bucket request-metrics
configuration; Billing needs the preference from Prerequisites); or the first datapoint has not been
published yet, which takes a few minutes and up to a day for the daily S3 storage metrics.
Fix
Confirm in the AWS CloudWatch console that the resource publishes the metric in that region, enable the
AWS-side feature if needed, and give a new job a few minutes. If the console shows data but Netdata does
not, read the Diagnostics output for one of the AWS request ... messages above.
Charts have gaps or show a stale value
Cause
CloudWatch publishes each period late and irregularly; the collector reads a series only when a new
period is complete and repeats the newest value in between. A gap means no datapoint existed within the
lookback window; a value that seems old is the newest one AWS has, and during an AWS outage the last
good value stays until a read succeeds.
Fix
Keep period at or above the metric's real publication cadence (a shorter period cannot make AWS publish
more often). If a workload publishes later than the profile expects, raise publication_delay at the
rule or metric level; if datapoints are sparse, widen lookback (a whole multiple of the period). Do not
lower rule_defaults.query.publication_delay below a profile's own value unless you have verified the
publication timing; the S3 storage profile uses one day for a reason.
A user profile does not take effect
Cause
Profiles are read once when the plugin starts and cached for its lifetime, so a file added or edited
under /etc/netdata/go.d/cloudwatch.profiles/ is not seen by a running plugin. A user profile whose chart
id collides with another profile's is loaded but the colliding chart is dropped, with a warning logged
under the cloudwatch/cwprofiles component rather than the job.
Fix
Restart Netdata after changing profiles. Give every chart in a user profile an id that no other loaded profile uses.
A service I use has no profile
Cause
Coverage is defined by the profiles shipped with Netdata, one per service and grain. A missing service means nobody has authored its profile yet; no code change is needed to add one.
Fix
Open a feature request and attach the service's CloudWatch metric schema, captured with this read-only command, which prints only metric and dimension names (no resource ids, ARNs, or values):
aws cloudwatch list-metrics --namespace "AWS/<Service>" --region <your-region> --output json \
| jq -c '[.Metrics[] | {metric: .MetricName, dimensions: ([.Dimensions[].Name] | sort)}] | unique'
Replace AWS/<Service> with the namespace (for example AWS/AmazonMQ) and <your-region> with a region
where the service runs. Or author the profile yourself following the
profile format.
The AWS bill is higher than expected
Cause
Cost scales with resources, selected metrics and statistics, request frequency, and lookback; see the drivers table under Performance Impact. The most common causes are a 1-minute period on many resources, opt-in detail grains (PrivateLink, DynamoDB operations, Billing by linked account and service), and broad rules that select every default profile in many regions.
Fix
Read the GetMetricData Profile Metric Request Estimates chart to see which profiles drive the requests,
then narrow rules[].profiles, rules[].metrics, and rules[].regions, add resource tag filters, or
raise rule_defaults.query.period together with update_every.
Do you have any feedback for this page? If so, you can open a new issue on our netdata/learn repository.