Skip to content

AWS CloudWatch metrics in Osuite

Osuite ingests Amazon CloudWatch metrics through the OpenTelemetry Collector. The awscloudwatch receiver polls the CloudWatch GetMetricData API on an interval, converts each series to OTLP, and forwards it through the otlp/osuite exporter, where it correlates with the rest of your telemetry.

The receiver runs anywhere the Collector runs — an EC2 instance, a container, or a Kubernetes pod — and pulls metrics for the AWS account and region it is configured against. One Collector can cover many namespaces.

There are two collector-based paths for CloudWatch metrics:

  • Pull with the awscloudwatch receiver (documented below) — the Collector calls GetMetricData on a schedule. Simplest to run: no inbound endpoint, no extra AWS resources. CloudWatch charges per metric API request.
  • Push with CloudWatch Metric Streams — a metric stream delivers metrics through Amazon Data Firehose to the Collector’s awsfirehosereceiver (encoding: cwmetrics). Lower latency and no polling cost, but the Collector must expose a public HTTPS endpoint on port 443 for Firehose to reach, and you provision a stream plus a Firehose delivery stream. Prefer this at high metric volume where API-request cost or freshness matters.

This page covers the pull path.

  • An OpenTelemetry Collector from the Contrib distribution (otelcol-contrib) that includes the awscloudwatch receiver.
  • Your Osuite ingest endpoint and token.
  • AWS credentials available to the Collector through the standard AWS SDK chain: environment variables (AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY), a shared credentials file, or an instance/role identity (IMDS on EC2, IRSA on EKS).
  • An IAM policy granting the Collector read access to CloudWatch metrics:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"cloudwatch:GetMetricData",
"cloudwatch:ListMetrics"
],
"Resource": "*"
}
]
}

GetMetricData reads the data points; ListMetrics is required only if you use auto-discovery instead of explicit queries.

This configuration polls two explicit metrics and forwards them to Osuite. Set region to the AWS region whose metrics you want.

receivers:
awscloudwatch:
region: us-east-1
metrics:
collection_interval: 5m
period: 300s
delay: 10m
queries:
- namespace: AWS/EC2
metric_name: CPUUtilization
stats:
- Average
- namespace: AWS/RDS
metric_name: FreeStorageSpace
stats:
- Average
processors:
batch:
exporters:
otlp/osuite:
endpoint: ingest.<region>.osuite.io:443
tls:
insecure: false
headers:
x-osuite-ingest-token: <your-ingest-token>
service:
pipelines:
metrics:
receivers: [awscloudwatch]
processors: [batch]
exporters: [otlp/osuite]

To collect metrics for a single resource, add its CloudWatch dimensions to a query:

queries:
- namespace: AWS/EC2
metric_name: CPUUtilization
dimensions:
InstanceId: i-1234567890abcdef0
stats:
- Average

To collect a whole namespace without listing every metric, use auto-discovery instead of queries (the two are mutually exclusive):

metrics:
collection_interval: 5m
period: 300s
delay: 10m
discovery:
filters:
namespace: AWS/EC2
limit: 200

Start the Collector and confirm it logs no GetMetricData authorization or throttling errors. Then check Osuite.

What you should see

CloudWatch metrics appear in Dashboards → Explore metrics within a few minutes, named amazonaws.com/AWS/EC2/CPUUtilization and similar. Filter by the resource attribute cloud.provider = aws to isolate them.

Metric names follow the CloudWatch Metric Streams OpenTelemetry 1.0.0 format: amazonaws.com/{Namespace}/{MetricName}, with CloudWatch casing preserved. Each data point carries the Namespace, MetricName, and Dimensions attributes; resource attributes include cloud.provider = aws and cloud.region.

Whatever you query is collected. Common namespaces:

NamespaceCovers
AWS/EC2Instance CPU, network, disk, status checks
AWS/RDSDatabase CPU, connections, free storage, IOPS
AWS/LambdaInvocations, errors, duration, throttles, concurrency
AWS/ApplicationELBRequest count, target response time, HTTP 5xx
AWS/S3Bucket size, object count, request metrics
AWS/DynamoDBConsumed capacity, throttled requests, latency
AWS/SQSQueue depth, message age, sent/received counts

By default (no stats), the receiver fetches Sum, SampleCount, Minimum, and Maximum and emits a Summary data point. Listing explicit stats emits a Gauge per statistic, tagged with a stat attribute, and costs fewer API sub-queries.

Empty or partial data usually means the query window is wrong or a metric has no data points for the requested statistic. Increase delay if points are missing, confirm the namespace/metric_name/dimensions match exactly what CloudWatch reports, and watch for ThrottlingException in the Collector logs — widen collection_interval or split queries across Collectors if you hit CloudWatch API limits.

No data in Osuite after a few minutes? Work through these checks.

  • Endpoint — confirm the exporter targets exactly ingest.<region>.osuite.io:443 for your region, over TLS.
  • Token — confirm the ingest header carries a valid <your-ingest-token> and has not been rotated.
  • Pipeline — confirm the signal you expect (traces, logs, or metrics) is wired into an active pipeline with the otlp/osuite exporter attached.
  • Export errors — check the application or Collector logs for OTLP export failures (auth, DNS, TLS, connection refused).
  • Network — confirm the host has outbound access to the ingest endpoint on port 443.
  • Timing — allow up to a minute for the first data to appear before assuming a failure.

Still stuck? Ask the Investigation Agent or contact support.

  • Dashboards — build views over your CloudWatch metrics.
  • Alerts — alert on CloudWatch thresholds with PromQL.