CloudWatch metrics: identity, retention, publishing, EMF and metric math
How CloudWatch metrics work for someone reading or publishing them — a metric is namespace + name + exact dimensions, retention by resolution (3 hours to 15 months), PutMetricData limits and visibility delays, the Embedded Metric Format for logging metrics from Lambda, metric math functions and their missing-data rules, and what each AWS/Lambda metric does and doesn't count.
markdownreferencev4QT04-VGV8stage: referencetrust: officialservice: cloudwatchinterface: anyCloudWatch metric dimensions identitymetric retention 15 monthshigh resolution 1 secondPutMetricData limitsmetric not showing ListMetrics 15 minutescustom metric namespace AWS reservedEmbedded Metric FormatEMF _aws CloudWatchMetricsEMF metrics missingmetric math syntaxFILLIFMETRICS()RATEANOMALY_DETECTION_BANDSEARCHdivision by zero metric mathLambda metricsErrors includes timeoutsThrottlesIteratorAgeConcurrentExecutionsClaimedAccountConcurrencyAsyncEventsDroppedpercentiles
A metric is its namespace, its name and its exact set of dimensions. Errors with FunctionName=a and Errors with FunctionName=a, Resource=a:prod are two different metrics. CloudWatch doesn't add custom metrics up across dimensions for you, so query with exactly the dimensions you published.
Basics
- Regional. A metric exists only in the Region it was published to.
- Can't be deleted. A metric expires after 15 months without new data.
- Retention by resolution (rolled up as it ages):
| Period | Kept |
|---|---|
| Under 60 s (1-second, high-resolution custom metrics) | 3 hours |
| 60 s | 15 days |
| 300 s | 63 days |
| 3600 s | 455 days (15 months) |
- Periods are 1, 5, 10, 30 or multiples of 60 seconds. The default is 60, and sub-minute periods only work on custom metrics stored at 1-second resolution.
- Statistics: Sum, Average, Minimum, Maximum, SampleCount, percentiles (
p99, up to ten decimals) and trimmed mean. - Percentiles need raw values, none of them negative.
- Statistic sets give percentiles only in narrow cases (for example, SampleCount 1).
- Units: default
None. Points with different units are aggregated separately, so publish one unit consistently.
Publishing (PutMetricData)
| Limit | Value |
|---|---|
| Request | 1 MB (gzip accepted), up to 1,000 metrics |
| Dimensions | Up to 30 per metric |
Values / Counts arrays | Up to 150 values per metric per request |
| Timestamps | Up to 2 weeks in the past, 2 hours in the future |
| Values | Within ±2^360. No NaN or Infinity |
| Namespace | 1–255 characters; don't start with AWS/ |
Visibility delays:
- A new metric can take up to 15 minutes to appear in
ListMetrics(and so in the console's metric browser). - Data timestamped 3–24 hours ago can take up to 2 hours to become queryable; data older than 24 hours, 48 hours or more.
StorageResolution: 1makes a high-resolution metric.
Errors: InvalidParameterValue, InvalidParameterCombination, MissingParameter (400) and InternalServiceError (500). The SDK names them …Exception; see reference/cloudwatch/errors.md.
Embedded Metric Format (metrics from log lines)
Write each log event as one JSON object that follows the specification, and CloudWatch extracts the metrics from it. AWS names three ways to send the events: the open-source EMF client libraries, the CloudWatch agent, or PutLogEvents. Because there's no PutMetricData call, the cloudwatch:PutMetricData permission shouldn't be needed (the hub's reading). From Lambda, the common approach is to write the object to stdout, as below. That path isn't described on the fetched pages (UNVERIFIED), so confirm the metric appears before you rely on it:
export function emitMetric(name: string, value: number, dims: Record<string, string>) {
console.log(JSON.stringify({
_aws: {
Timestamp: Date.now(), // milliseconds
CloudWatchMetrics: [{
Namespace: "orders",
Dimensions: [Object.keys(dims)], // array of dimension sets
Metrics: [{ Name: name, Unit: "Milliseconds", StorageResolution: 60 }],
}],
},
...dims, // dimension values: top level
[name]: value, // metric value: top level
}));
}
emitMetric("checkoutLatency", 142, { service: "checkout", stage: "prod" });
Rules:
- The whole log event must be the JSON object, with nothing before or after it.
- Dimension keys and metric values must be top-level members, not nested.
- Values are numbers or arrays of up to 100 numbers.
- Up to 100 metric definitions per event and 30 keys per dimension set. Each dimension set becomes its own metric. Event size up to 1 MB. Timestamps from 14 days past to 2 hours future.
When EMF metrics don't appear:
- Look in the
AWS/Logsnamespace, which counts extraction failures. - A bad namespace or name drops that metric; a bad dimension drops that dimension set.
- An out-of-range value, an array over 100, or more than 100 definitions drops the whole event's metrics.
- Delivery is at-least-once, so occasional duplicates are normal.
How Lambda's Text and JSON log formats interact with the "nothing before or after" rule isn't on the fetched pages. If metrics are missing, check the AWS/Logs failure counts first.
Metric math
- IDs start with a lowercase letter (
m1,errors). Functions are uppercase. The result must be a time series, so scalar functions go inside a bigger expression (m1 - AVG(m1)). - Functions:
METRICS()andMETRICS("err")(by ID substring);SUM,AVG,MIN,MAX,STDDEV;FILL(m, 0 | REPEAT | LINEAR),IF(cond, a, b);RATE,DIFF,DIFF_TIME,PERIOD;ANOMALY_DETECTION_BAND(m, n)(default 2 standard deviations);SEARCH(...),INSIGHT_RULE_METRIC,SERVICE_QUOTA.- Missing data: treated as 0 in arithmetic and comparisons. A division by zero drops that point.
- Limits:
- 500 metrics and expressions per graph;
- no alarms on
SEARCH; - anomaly detection on math can't use
METRICS,SEARCH, more than 10 inputs, mixed periods, periods over an hour or high-resolution metrics.
AWS/Lambda metrics: what they count
| Metric | Statistic | Counts | Doesn't count |
|---|---|---|---|
Invocations | Sum | Every invocation, including those that errored (= billed requests) | Throttled requests, other invocation errors |
Errors | Sum | Function errors: thrown exceptions, timeouts, runtime and configuration errors. Timestamped at invoke time | Throttles |
Throttles | Sum | Requests refused with TooManyRequestsException | — |
Duration | Avg, Max, pNN | Time in your handler | Cold-start init time |
ConcurrentExecutions | Max | Instances processing events | — |
ClaimedAccountConcurrency | Max | Regional concurrency not available on demand (unreserved in use + reserved + provisioned) | — |
IteratorAge | Max | Age (ms) of the last record in a batch: DynamoDB, Kinesis, DocumentDB | — |
OffsetLag | Max | Kafka / MSK consumer lag | — |
AsyncEventAge / AsyncEventsDropped | Max / Sum | Queue time of async events / events dropped after max age or retries | — |
DeadLetterErrors, DestinationDeliveryFailures | Sum | Failed sends to a DLQ or destination (FIFO SQS and SNS destinations aren't supported) | — |
Error rate = Errors / Invocations (alarm recipe: guides/cloudwatch/create-alarms.md).