cloud-metrics blueprint to collect managed database and cache metrics from AWS CloudWatch, GCP Cloud
Monitoring, or Azure Monitor. Ryvn’s Postgres and Cache modules declare their resources for collection; custom
Terraform modules can use the same cloud_metrics output.
Leave the metric selection unset to collect the defaults. Customize it when you need other
metrics within a supported family. Collected series keep the exporter’s native names,
units, and statistics. View supported cards on the installation’s Metrics tab or query the series in
Grafana.
How it works
Collection is opt-in for each environment:- Install
ryvn.app/cloud-metrics. The blueprint creates a dedicated collector, a read-only cloud identity, and their config. It runs separately from the platform metrics collector. Install and remove it explicitly; datastore installations do not install it automatically. - Declare the resources. Ryvn’s Postgres and Cache modules already emit
cloud_metricsand tag resources with the environment ID. Custom Terraform modules must implement the same contract. - Choose the metrics. Use the defaults or set the blueprint’s
collectioninput. Ryvn renders an allowlist of the declared resources and selected metrics into the collector config. - Check delivery. After the identity and collector deploy, allow a few minutes for samples to arrive. Check the installation’s Metrics tab and the environment’s Grafana; an applied config alone does not prove delivery.
Every collected series carries
environment and installation labels, plus cloud_target (the module-chosen
declaration name) and cloud_resource_id with the provider identifier the module declared (the ARN on AWS, the projects/... path on
GCP, the ARM id on Azure), so group-shaped resources (a multi-node cache) chart per member.Choose what to collect
Supported families
A family is a supported cloud service or resource type, not an individual metric. Use the exact key below under your environment’s provider key. Ryvn resolves each target’s family from itscloud_resource_id; the
collection input selects metrics for that family across the environment, not for an individual installation.
An omitted family uses its defaults, but only declared, admitted targets are collected. The selection does not
discover or opt in undeclared resources.
Default metrics
These are the default selections whencollection is unset or {}. A provider may not emit every selected metric
for every resource, tier, or topology; for example, a cache without replicas may have no replication-lag series.
Selected metrics are not a list of guaranteed Metrics-tab cards: see Per-cloud availability.
Customize collection
Set the map-valuedcollection input on the environment’s cloud-metrics blueprint installation. Its shape is
provider → family → metrics, using only the environment’s own provider. In
BlueprintInstallation YAML, it is an entry in spec.inputs.
Keep the defaults and add a metric
This AWS example keeps all six RDS defaults and addsDatabaseConnections with Maximum. Replace production
with your environment name. When updating an existing blueprint installation, use its existing installation name.
statistics: [Average, Maximum]; do not repeat the metric name.
GCP and Azure input values
The following examples are values of thecollection input, not complete installation manifests. Place the
chosen map under value in the example above, replacing the aws map.
- GCP
- Azure
Keep all five Cloud SQL defaults and add disk read operations. Memorystore retains its defaults.The added metric is available in Grafana; it does not populate the built-in IOPS card, whose query currently
supports AWS and Azure only.
Find metrics outside the defaults
Follow the resource links in Supported families to the provider’s metric reference. Check that the metric is emitted for your resource and supports the statistic or aggregation you select. A new metric within a supported family needs no Ryvn platform release, subject to these limits:- AWS: use exact CloudWatch metric names and
statistics:Average,Sum,Minimum,Maximum, orSampleCount. - GCP: use objects containing only
name, set to the full, exact metric type within the family’s domain:cloudsql.googleapis.com/orredis.googleapis.com/. Scalar strings and additional fields are rejected. Do not use prefixes or wildcards. - Azure: use exact Azure Monitor metric names and
aggregations:Average,Total,Minimum,Maximum, orCount. Customdimensionsselections are rejected because the exporter cannot bound the number of dimension value combinations. Metrics requiring a custom dimension split, such asShardMemoryUsedBytes, need exporter support before they can be selected. Managed Redis’s built-inInstanceIdsplit is already configured.
Replacement, reset, and limits
Writing
collection replaces the whole map; it does not merge with the previous value. Include every existing
override or disabled family you want to retain. For example, omitting an existing elasticache.metrics: []
override re-enables ElastiCache defaults. An update that omits the collection input leaves it unchanged; writing
{} explicitly resets it to defaults.
Changing the selection updates the generated collector config, not the datastore’s Terraform resources.
Pending apply remains set until the collector reconciles the change.
Selections allow up to 64 metrics per family and must fit the provider’s estimated collection budget. The
estimate counts targets × metrics × statistics/aggregations, weighted by supported dimension sets; GCP counts
metric types without statistics. It is not a hard cap on provider API calls or cost: discovered nodes, shards,
and dimension values can increase query work. Scrape limits bound retained samples, not the provider work already
performed.
The module contract
Two things mark a datastore resource for collection — a tag and an output. The tag key’s spelling depends on the cloud, because GCP and Azure disallow/ in tag keys:
The tag’s value is always the environment’s Ryvn ID. Only on AWS is the tag the scrape gate — the collector
requests metric data only for tagged resources. GCP and Azure gate by enumeration instead: the rendered config
lists the declared resource ids verbatim (GCP
extra_filters; an Azure Resource Graph id in~ filter), and the
tag is a bookkeeping convention there.
In the module:
ryvn describe environment prints the environment’s ID for manual tagging.
schemais1— the contract version.targetsmaps a stable, module-chosen name to each provider object. The name travels onto the collected series as acloud_targetlabel — keep it short and stable (it must match[a-zA-Z0-9][a-zA-Z0-9_-]{0,62}).cloud_resource_idis the provider-native identifier — the full ARN on AWS, the Terraform resource path on GCP (projects/<project>/instances/<name>for Cloud SQL,projects/<project>/locations/<location>/instances/<name>for Memorystore), and the full ARM id on Azure (/subscriptions/<sub>/resourceGroups/<rg>/providers/Microsoft.DBforPostgreSQL/flexibleServers/<name>orMicrosoft.Cache/redis). The identifier alone carries the service, resource kind, region, and cloud account; Ryvn resolves the metric family and dimensions from it, so the module never spells a Ryvn-side type or region. For cluster-shaped resources declare every member and the group as separate named targets (for ElastiCache, each cluster ARN plus the replication-group ARN).selectionis optional provider-specific context for targets whose identifier is not self-describing (e.g. a project-level quota object); datastore identifiers never need it.
Permissions: what Ryvn reads in the account
Each cloud grants the dedicated collector a read-only metrics identity through the blueprint’s<provider>-identity child, so the exact grant shows up in that installation’s plan and removing the blueprint
removes the binding with it — the platform collector’s identity is never widened for cloud metrics:
- AWS — an IAM role granting
cloudwatch:GetMetricData,cloudwatch:GetMetricStatistics,cloudwatch:ListMetrics, andtag:GetResources, provisioned by theaws-cloud-metrics-identitychild. To audit actual reads, enable CloudTrail data-event logging for CloudWatch in the account:GetMetricDataandGetMetricStatisticsare data events, so they do not appear in a management-events-only trail. - GCP — the collector’s Kubernetes ServiceAccount is itself the Workload Identity principal;
roles/monitoring.vieweris granted on exactly the projects the environment’s targets point into (the union the hub renders as the blueprint’smonitoredIdsinput). - Azure — a user-assigned managed identity with Monitoring Reader on the subscriptions the environment’s
targets point into (the same
monitoredIdsseam), bound to the collector’s ServiceAccount by a federated credential.
-
The tag (AWS) confines metric-data requests:
GetMetricDatais issued only for resources the tag admitted. It does not confine enumeration —ListMetricsandtag:GetResourcesstill run across the account in the granted regions, because discovery works by listing candidates and matching the tag. On GCP and Azure the metrics queries themselves enumerate the declared ids (per-projectextra_filters; a Resource Graphid in~filter), so undeclared ids are never requested at all. - The rendered allowlist and its 50-target cap bound which resources’ telemetry is forwarded to the metrics store — they are scoping rules on emitted series, not on provider API reads.
- Forwarding is default-deny on resource identity: only samples carrying a current admitted resource claim reach the store — exporter self-metrics and anything unrelated never join the cloud-data stream.
Per-cloud availability
Each cloud’s metrics API covers a slightly different surface; a card for a metric a cloud doesn’t emit shows unavailable rather than zero:- GCP — Cloud SQL does publish per-disk read/write ops DELTA metrics
(
database/disk/read_ops_count/write_ops_count), but they’re left out of the recommended defaults, and the built-in IOPS card’s query only unions the AWS and Azure arms today — selecting the GCP ops metrics makes thestackdriver_series available to query but the card itself stays empty. Memorystore CPU reports the main thread’s per-window utilization rather than an all-core average (that is the thread Redis bottlenecks on), and Memorystore has no network-throughput metrics, so cache network cards show unavailable. - Azure — two cache families are supported side by side: legacy Azure Cache for Redis
(
microsoft.cache/redis) and Azure Managed Redis (microsoft.cache/redisenterprise, keyed by the ARM cluster resource id). Azure Cache doesn’t publish a replication-lag metric — Managed Redis exposesgeoReplicationHealthy(0/1 health, not a lag), so the replication-lag card shows unavailable on Azure rather than a misleading lag series. Managed Redis shards report under the per-shardInstanceIddimension, so cache cards sum across shards for a cluster total;cacheRead/cacheWriteremain inbound/outbound respectively (bytes read from / written to the cache). Managed Redis counts (cachehits,cachemisses,evictedkeys,expiredkeys) arrive already per-second — the collector reads them as Average series and the cards take them as-is, unlike legacyTotalcounts which the cards divide by the scrape window. TheInstanceIdsplit is requested with a wildcard (InstanceId eq '*'): the exporter may expand it into more query work than the declared collection estimate — an accepted residual of the stock Azure Monitor exporter, documented rather than capped. - GCP and Azure — free-space panels need no extra plumbing: Cloud SQL composes its own
bytes_used/disk/quotapair and Azure emitsstorage_freedirectly.
Collection status
Status is a stored field —cloudMetrics on the installation’s metrics response (MetricsResponse) — so the web
UI, the CLI, and direct API callers all read the same value. The Metrics tab shows a status line for installations
that emit cloud_metrics, and ryvn get cloud-metrics [NAME] -e ENVIRONMENT prints the same status for one
installation or a whole environment:
Alongside the status code, the same surface carries two pieces of collection state:
- Pending apply — when the rendered collector config differs from what the blueprint install currently
carries, the status shows
pending apply(CLI) and the Metrics tab notes it. Acollectionchange, a new declaration, or a resource removal all render a new config; the flag clears once the collector’s reconcile applies it. It is informational, not an error — the collector keeps serving the previously applied selection in the meantime. - Family selection — each resolved family reports
enabledordisabled. Disabled means the family is present in declarations but thecollectionselection turned it off (metrics: []); the CLI shows the disabled family names next to the status.
limit_reached in the detail, and the installation’s other targets still collect. Admission is deterministic for
a given input but membership is not stable across renders: a new emitter can change which later targets fit under
the cap.
Two more rules shape admission: a cloud object associates with one installation — if two installations declare
the same cloud_resource_id, the earlier declaration wins and the other installation’s id_conflict detail names
the loser targets — and within one output, two names resolving to the same cloud object admit only the first
declaration’s name (the alias is recorded as a duplicate, never double-scraped).
Where the metrics live
Collected series are written to the environment’s own metrics store alongside its other observability data — they are not replicated into a hub-level store. Two consequences:- You query them through that environment’s Grafana (or any client pointed at its store); there is no cross-environment rollup of cloud metrics.
- An environment without the observability stack produces no queryable series — the collector has nowhere to write.
Because the hub never queries the destination, installation status stays
unverifiedwhether or not series actually land; check the environment’s Grafana to confirm delivery.
Dashboards and queries
Series keep the provider exporter’s native names —aws_rds_cpuutilization_average on AWS,
stackdriver_cloudsql_database_cloudsql_googleapis_com_database_cpu_utilization on GCP,
azure_microsoft_dbforpostgresql_flexibleservers_cpu_percent_average_percent on Azure — with native units,
statistic suffixes, and counter semantics preserved. Ryvn adds
only attribution labels (environment, installation, cloud_target, cloud_resource_id); it never renames or
re-units provider metrics, and never dual-publishes old normalized aliases.
The built-in Metrics-tab cards query the native metric names for each family’s recommended selection. Because
collection can replace or disable that selection:
- A card whose prerequisite metric isn’t in your selection shows empty/unavailable rather than silently widening the collector or fabricating zeroes.
- Custom metrics you add don’t automatically acquire cards — Grafana and direct queries are the advanced path, and they work for any native name the collector forwarded.
orders-db (native CloudWatch name, native bytes unit):