Cloud Monitoring Metrics

Why This Topic Matters

Metrics answer the questions that logs cannot answer quickly at scale: Is backlog rising, is CPU saturating, are errors sustained or spiky, and did the problem affect one instance or the whole fleet? In data engineering, these are the signals that tell you when a scheduled batch is late, when a consumer is falling behind, when retries are amplifying load, and when costs or retention are creeping upward.

This archived project already proves the split between Logging and Monitoring:

  • Logging has active audit logs, default buckets, and verification writes.
  • Monitoring has active metric APIs, running Compute Engine instances, no dashboards, no alerting policies, no uptime configs, and no configured notification channels.

That is a normal platform baseline. The raw telemetry exists. The operational question is how to interpret it and which pieces are still missing.

Conceptual Model

Metrics become useful only after you read them with the right schema and aggregation semantics. The diagram below shows the signal path that matters operationally.


flowchart LR
    A["GCP services<br>Compute, Logging, Pub/Sub, BigQuery"] --> B["Metric descriptor"]
    A --> C["Raw time series"]
    C --> D["Alignment<br>mean, max, sum"]
    D --> E["Reduction<br>fleet, zone, project"]
    E --> F["Dashboards"]
    E --> G["Alerting policies"]
    G --> H["Notification channels"]
    C --> I["Incident investigation"]
    I --> J["Cloud Logging queries"]

Cloud Monitoring | archived project summary

The archived project already had metric-producing resources, but almost no Monitoring control objects.

ObjectArchived state in removed projectOperational meaning
Compute instancesstoxx-airflow, stoxx-vmNative VM metrics are available
Dashboards[]No saved visual views yet
Alerting policies[]No active Monitoring threshold policies yet
Uptime configs[]No active uptime checks or synthetic monitors yet
Notification channels[]Policies cannot notify anyone yet
Notification channel descriptor typesemail, pagerduty, pubsub, slack, sms, webhook_*, othersSupported delivery types exist even though no instances are configured

Important conceptual note not safely executed here

The archived project did not contain dashboards, alerting policies, uptime configs, synthetic monitors, or configured notification channels. Creating those objects would have mutated the live environment and could have paged people, generated cost, or created false confidence. This note therefore separates:

  • historically captured inventory and query workflows
  • production guidance for alert and monitor design that was important but not safe to instantiate here

PowerShell / Linux

This section covers the current gcloud command surface that exists in the installed SDK.

PowerShell / Linux | gcloud monitoring | verify the current CLI surface

Older guides often show stable commands like gcloud monitoring metrics-descriptors list and gcloud monitoring time-series list. Those commands are not present on the stable surface in this environment, so the first operational step is to verify the CLI that is actually installed.

Inspect the stable Monitoring command groups

Before copying metric-descriptor or time-series commands from older notes. It is typically triggered by A runbook assumes that stable gcloud monitoring exposes direct metric query subcommands. Read-only. This command checks the installed SDK surface. Confirm which stable Monitoring command groups actually exist.

Ask the stable CLI which Monitoring groups it currently exposes.

gcloud monitoring --help
NAME
    gcloud monitoring - manage Cloud Monitoring dashboards
 
GROUPS
    GROUP is one of the following:
 
     dashboards
        Manage Cloud Monitoring dashboards.
 
     policies
        Manage Cloud Monitoring alerting policies.
 
     snoozes
        Manage Cloud Monitoring snoozes.
 
     uptime
        Manage Cloud Monitoring uptime checks and synthetic monitors.

This is the most important live correction in the chapter. Stable gcloud monitoring in this environment is a control-plane CLI for dashboards, policies, snoozes, and uptime. It is not the current stable interface for listing metric descriptors or raw time series.

Inspect the existing Monitoring inventory

Before building alerts or dashboards on top of assumed existing objects. It is typically triggered by you need to know whether the project already has alerting and visualization state. Read-only. Show whether dashboards, policies, uptime checks, and notification channels already exist.

FieldTypeMeaning
result arrayarrayInventory returned by the CLI
[]empty arrayNo configured objects of that type exist in the project

List dashboards in the archived project.

gcloud monitoring dashboards list --format=json
[]

List alerting policies in the archived project.

gcloud monitoring policies list --format=json
[]

List uptime checks and synthetic monitors in the archived project.

gcloud monitoring uptime list-configs --format=json
[]

List configured notification channels in the archived project.

gcloud alpha monitoring channels list --format=json
[]

The archived project had raw telemetry but no configured Monitoring control objects. That means alerts were not yet firing, dashboards were not yet persisted, and notification delivery was not configured.

FlagSyntaxDescription
--format--format=jsonChooses machine-readable inventory output
--project--project=bq-wh-nbOverrides the target project when needed

PowerShell / Linux | gcloud monitoring | inspect notification and uptime surfaces

Notification channels and uptime checks are where Monitoring becomes operator-visible. Even when the project has no configured instances, it is still useful to inspect the supported channel types and the public probe source ranges.

List supported notification channel descriptor types

Before designing alert delivery. It is typically triggered by you need to know whether email, Pub/Sub, PagerDuty, Slack, SMS, or webhook delivery is supported. Read-only. Uses the beta descriptor surface because that is what exists in this SDK. Show the channel families that can be instantiated in the project.

List the supported notification channel descriptor types.

gcloud beta monitoring channel-descriptors list --format="value(type)"
campfire
email
google_chat
hipchat
pagerduty
pubsub
slack
sms
webhook_basicauth
webhook_tokenauth

This output tells you what kinds of channels can exist. It does not mean any channel of that type is already configured.

Current product note: channel descriptors versus channels

Descriptor support only tells you which channel families the API can create. Actual notification channels are separate resources, and channel instances carry operational state such as verificationStatus, enablement, and delivery-specific configuration.

Inspect the Pub/Sub channel descriptor

Before choosing Pub/Sub as a notification fan-out target. It is typically triggered by you need to know which labels the descriptor requires. Read-only. Show that a channel descriptor is a schema, not a configured channel instance.

FieldTypeMeaning
displayNamestringHuman-facing name of the descriptor type
typestringChannel type identifier
labelsarrayRequired configuration fields for channel creation

Describe the built-in Pub/Sub notification channel descriptor.

gcloud beta monitoring channel-descriptors describe pubsub --format=json
{
  "description": "A channel that publishes notifications to Cloud Pub/Sub topics.",
  "displayName": "Cloud Pub/Sub",
  "labels": [
    {
      "description": "The PubSub topic.",
      "key": "topic"
    }
  ],
  "launchStage": "GA",
  "name": "projects/bq-wh-nb/notificationChannelDescriptors/pubsub",
  "type": "pubsub"
}

The important operational point is that descriptors define the required configuration shape. A descriptor is not a live channel and does not deliver anything on its own.

List uptime probe source IPs

Before firewalling an endpoint that an uptime check or synthetic monitor must reach. It is typically triggered by the networking team needs the source ranges for Monitoring probes. Read-only. Show where uptime checks can originate from.

ColumnMeaning
REGIONBroad probe region grouping
LOCATIONHuman-friendly probe location
IP_ADDRESSSource IP that can send probe traffic

List a representative slice of uptime check source addresses.

gcloud monitoring uptime list-ips --limit=6 --format="table(region,location,ipAddress)"
REGION  LOCATION  IP_ADDRESS
USA     Oregon    35.197.117.125
USA     Oregon    35.203.157.42
USA     Oregon    35.199.157.7
USA     Oregon    35.233.206.171
USA     Oregon    35.197.32.224
USA     Oregon    35.233.167.246

This command is useful even when there are no configured uptime checks yet because firewall and allowlist work often happens before the monitor object is created.

Current product note: uptime checks are not full browser journeys

Uptime checks are still useful for reachability, latency, and allowlist planning, but they are not equivalent to scripted browser execution. When the requirement is multi-step journey validation or browser-level behavior, treat synthetic monitoring as a separate capability rather than as a synonym for basic uptime checks.

FlagSyntaxDescription
--format--format=json or table(...)Renders descriptor or IP output in a human-usable form
--limit--limit=6Restricts how many probe addresses are displayed

PowerShell

Stable gcloud monitoring in this environment does not expose direct metric-descriptor or time-series list commands. The live fallback below uses the Monitoring v3 API with an access token printed by gcloud.

PowerShell | Monitoring API | read metric descriptors

Read the descriptor before you read the data. The descriptor tells you how many labels exist, which resource model to expect, whether the metric is GAUGE or DELTA, what the unit means, and how quickly the data should arrive.

Inspect logging billing metric descriptors

Before charting or alerting on Logging-related ingestion or retention signals. It is typically triggered by you need to know which logging metrics already exist natively in Monitoring. PowerShell-only in this note because the workflow uses Invoke-RestMethod. Read-only. Show the descriptor schema for built-in Logging billing metrics.

FieldMeaning
typeCanonical metric type identifier
metricKindWhether the series is GAUGE or DELTA
valueTypeData type of each point
unitUnit string used by Monitoring
labelsMetric labels that create additional time-series dimensions
samplePeriodExpected sampling cadence
ingestDelayTypical delay before points are queryable

Query Logging metric descriptors through the Monitoring v3 API and keep only the fields needed for interpretation.

$token = gcloud auth print-access-token
$headers = @{ Authorization = "Bearer $token" }
$filter = [uri]::EscapeDataString('metric.type = starts_with("logging.googleapis.com/")')
$uri = "https://monitoring.googleapis.com/v3/projects/bq-wh-nb/metricDescriptors?filter=$filter&pageSize=5"
$resp = Invoke-RestMethod -Headers $headers -Uri $uri -Method Get
$resp.metricDescriptors |
  Select-Object type,metricKind,valueType,unit,@{Name='labels';Expression={@($_.labels.key)}},@{Name='samplePeriod';Expression={$_.metadata.samplePeriod}},@{Name='ingestDelay';Expression={$_.metadata.ingestDelay}} |
  ConvertTo-Json -Depth 10
[
  {
    "type": "logging.googleapis.com/billing/bytes_ingested",
    "metricKind": "DELTA",
    "valueType": "INT64",
    "unit": "By",
    "labels": "resource_type",
    "samplePeriod": "60s",
    "ingestDelay": "300s"
  },
  {
    "type": "logging.googleapis.com/billing/bytes_stored",
    "metricKind": "GAUGE",
    "valueType": "INT64",
    "unit": "By",
    "labels": [
      "data_type",
      "log_bucket_location",
      "log_bucket_id"
    ],
    "samplePeriod": "60s",
    "ingestDelay": "300s"
  },
  {
    "type": "logging.googleapis.com/billing/log_bucket_bytes_ingested",
    "metricKind": "DELTA",
    "valueType": "INT64",
    "unit": "By",
    "labels": [
      "log_source",
      "resource_type",
      "log_bucket_location",
      "log_bucket_id"
    ],
    "samplePeriod": "60s",
    "ingestDelay": "300s"
  },
  {
    "type": "logging.googleapis.com/billing/log_bucket_monthly_bytes_ingested",
    "metricKind": "GAUGE",
    "valueType": "INT64",
    "unit": "By",
    "labels": [
      "log_source",
      "resource_type",
      "log_bucket_location",
      "log_bucket_id"
    ],
    "samplePeriod": "1800s",
    "ingestDelay": "6000s"
  },
  {
    "type": "logging.googleapis.com/billing/monthly_bytes_ingested",
    "metricKind": "GAUGE",
    "valueType": "INT64",
    "unit": "By",
    "labels": "resource_type",
    "samplePeriod": "1800s",
    "ingestDelay": "6000s"
  }
]

This output is the bridge back to the Logging note. Cloud Logging already emits Monitoring-native billing metrics, so not every logging question requires a custom log-based metric. Notice how retention-focused metrics are GAUGE, while ingestion metrics are DELTA.

Inspect Compute Engine CPU descriptors

Before querying VM performance or alerting on CPU saturation. It is typically triggered by you need to know which CPU metrics exist and how to interpret their units. Read-only. Show that metric descriptors carry the schema needed to interpret utilization, usage time, and reserved cores correctly.

Query Compute Engine CPU descriptors through the Monitoring v3 API.

$token = gcloud auth print-access-token
$headers = @{ Authorization = "Bearer $token" }
$filter = [uri]::EscapeDataString('metric.type = starts_with("compute.googleapis.com/instance/cpu/")')
$uri = "https://monitoring.googleapis.com/v3/projects/bq-wh-nb/metricDescriptors?filter=$filter&pageSize=5"
$resp = Invoke-RestMethod -Headers $headers -Uri $uri -Method Get
$resp.metricDescriptors |
  Select-Object type,metricKind,valueType,unit,@{Name='samplePeriod';Expression={$_.metadata.samplePeriod}},@{Name='ingestDelay';Expression={$_.metadata.ingestDelay}},@{Name='monitoredResourceTypes';Expression={$_.monitoredResourceTypes -join ','}} |
  ConvertTo-Json -Depth 5
[
  {
    "type": "compute.googleapis.com/instance/cpu/guest_visible_vcpus",
    "metricKind": "GAUGE",
    "valueType": "DOUBLE",
    "unit": "1",
    "samplePeriod": "60s",
    "ingestDelay": "240s",
    "monitoredResourceTypes": "gce_instance"
  },
  {
    "type": "compute.googleapis.com/instance/cpu/reserved_cores",
    "metricKind": "GAUGE",
    "valueType": "DOUBLE",
    "unit": "1",
    "samplePeriod": "60s",
    "ingestDelay": "240s",
    "monitoredResourceTypes": "gce_instance"
  },
  {
    "type": "compute.googleapis.com/instance/cpu/scheduler_wait_time",
    "metricKind": "DELTA",
    "valueType": "DOUBLE",
    "unit": "s{idle}",
    "samplePeriod": "60s",
    "ingestDelay": "240s",
    "monitoredResourceTypes": "gce_instance"
  },
  {
    "type": "compute.googleapis.com/instance/cpu/usage_time",
    "metricKind": "DELTA",
    "valueType": "DOUBLE",
    "unit": "s{CPU}",
    "samplePeriod": "60s",
    "ingestDelay": "240s",
    "monitoredResourceTypes": "gce_instance"
  },
  {
    "type": "compute.googleapis.com/instance/cpu/utilization",
    "metricKind": "GAUGE",
    "valueType": "DOUBLE",
    "unit": "10^2.%",
    "samplePeriod": "60s",
    "ingestDelay": "240s",
    "monitoredResourceTypes": "gce_instance"
  }
]

The unit field matters. compute.googleapis.com/instance/cpu/utilization is a GAUGE with unit 10^2.%, which means the raw point value is a fraction rendered as percent. A value of 0.517... is about 51.7%, not 0.517%.

PowerShell | Monitoring API | read raw and aggregated time series

Raw time series tell you what one labeled source did. Aggregated time series tell you what a fleet or slice did after explicit alignment and reduction rules were applied. Both views are useful, but they answer different questions.

Read raw CPU utilization for one VM

During host-level triage or right-sizing review. It is typically triggered by you need to know whether one VM is actually saturated or idle. Read-only. Show an unaggregated VM metric with its resource labels and recent points.

FieldMeaning
metric.typeMetric being queried
metric.labels.instance_nameHuman-friendly VM name
resource.labels.instance_idStable instance identifier used by Monitoring
resource.labels.zoneZone of the VM
points[].intervalTime window for each metric point
points[].value.doubleValueObserved CPU utilization fraction

Query raw CPU utilization points for one VM in the archived project.

$token = gcloud auth print-access-token
$headers = @{ Authorization = "Bearer $token" }
$start = [uri]::EscapeDataString((Get-Date).ToUniversalTime().AddHours(-6).ToString('o'))
$end = [uri]::EscapeDataString((Get-Date).ToUniversalTime().ToString('o'))
$filter = [uri]::EscapeDataString('metric.type = "compute.googleapis.com/instance/cpu/utilization"')
$uri = "https://monitoring.googleapis.com/v3/projects/bq-wh-nb/timeSeries?filter=$filter&interval.startTime=$start&interval.endTime=$end&view=FULL&pageSize=3"
(Invoke-RestMethod -Headers $headers -Uri $uri -Method Get) | ConvertTo-Json -Depth 100
{
  "timeSeries": [
    {
      "metric": {
        "labels": {
          "instance_name": "stoxx-airflow"
        },
        "type": "compute.googleapis.com/instance/cpu/utilization"
      },
      "resource": {
        "type": "gce_instance",
        "labels": {
          "project_id": "bq-wh-nb",
          "zone": "europe-west1-b",
          "instance_id": "3833904033025838281"
        }
      },
      "metricKind": "GAUGE",
      "valueType": "DOUBLE",
      "points": [
        {
          "interval": {
            "startTime": "2026-04-13T13:44:00Z",
            "endTime": "2026-04-13T13:44:00Z"
          },
          "value": {
            "doubleValue": 0.26974677127151203
          }
        },
        {
          "interval": {
            "startTime": "2026-04-13T13:43:00Z",
            "endTime": "2026-04-13T13:43:00Z"
          },
          "value": {
            "doubleValue": 0.11170530053671257
          }
        },
        {
          "interval": {
            "startTime": "2026-04-13T13:42:00Z",
            "endTime": "2026-04-13T13:42:00Z"
          },
          "value": {
            "doubleValue": 0.01081406960042619
          }
        }
      ]
    }
  ],
  "nextPageToken": "CMG1x8-vgZ-glQES7wEiHQoQCgYIqOXzzgYSBgio5fPOBhIJGQD7KdqvJYY_KgxnY2VfaW5zdGFuY2UyvwFqFwoHcHJvamVjdBoMMzQ4NTU3MDkyNTE0aiEKB3NlcnZpY2UaFmNvbXB1dGUuZ29vZ2xlYXBpcy5jb21qGQoNcmVzb3VyY2VfdHlwZRoIaW5zdGFuY2VqGgoIbG9jYXRpb24aDmV1cm9wZS13ZXN0MS1iaiIKC3Jlc291cmNlX2lkGhMzODMzOTA0MDMzMDI1ODM4MjgxciYKFW1ldHJpYzovaW5zdGFuY2VfbmFtZRoNc3RveHgtYWlyZmxvdw",
  "unit": "10^2.%"
}

This is a raw per-instance series. The points show CPU rising from about 1.1% to 11.2% to 27.0% across consecutive one-minute samples. That is a real workload ramp, not necessarily a problem. The unit field confirms how to convert the fraction into operator-friendly percent.

Read aligned and reduced CPU utilization

During fleet-level health review, threshold design, or noisy-alert cleanup. It is typically triggered by raw per-instance series are too granular for the operational question. Read-only. Show how alignment and reduction change the meaning of the returned point.

Query one aligned and reduced CPU series across the project’s VM set.

$token = gcloud auth print-access-token
$headers = @{ Authorization = "Bearer $token" }
$start = [uri]::EscapeDataString((Get-Date).ToUniversalTime().AddHours(-6).ToString('o'))
$end = [uri]::EscapeDataString((Get-Date).ToUniversalTime().ToString('o'))
$filter = [uri]::EscapeDataString('metric.type = "compute.googleapis.com/instance/cpu/utilization"')
$uri = "https://monitoring.googleapis.com/v3/projects/bq-wh-nb/timeSeries?filter=$filter&interval.startTime=$start&interval.endTime=$end&view=FULL&pageSize=3&aggregation.alignmentPeriod=3600s&aggregation.perSeriesAligner=ALIGN_MEAN&aggregation.crossSeriesReducer=REDUCE_MAX"
(Invoke-RestMethod -Headers $headers -Uri $uri -Method Get) | ConvertTo-Json -Depth 100
{
  "timeSeries": [
    {
      "metric": {
        "type": "compute.googleapis.com/instance/cpu/utilization"
      },
      "resource": {
        "type": "gce_instance",
        "labels": {
          "project_id": "bq-wh-nb"
        }
      },
      "metricKind": "GAUGE",
      "valueType": "DOUBLE",
      "points": [
        {
          "interval": {
            "startTime": "2026-04-13T13:47:08.24961Z",
            "endTime": "2026-04-13T13:47:08.24961Z"
          },
          "value": {
            "doubleValue": 0.1426432415897683
          }
        },
        {
          "interval": {
            "startTime": "2026-04-13T12:47:08.24961Z",
            "endTime": "2026-04-13T12:47:08.24961Z"
          },
          "value": {
            "doubleValue": 0.06123336967894423
          }
        },
        {
          "interval": {
            "startTime": "2026-04-13T11:47:08.24961Z",
            "endTime": "2026-04-13T11:47:08.24961Z"
          },
          "value": {
            "doubleValue": 0.04817410439093394
          }
        }
      ]
    }
  ],
  "nextPageToken": "CJHokZmd95DytAESNyInChoKCwi8r_POBhCQ_oJ3EgsIvK_zzgYQkP6CdxIJGa8Nv7VGqqg_KgxnY2VfaW5zdGFuY2U",
  "unit": "10^2.%"
}

This result is not the same question as the raw series above. ALIGN_MEAN produces an hourly mean for each VM, and REDUCE_MAX then keeps the highest aligned VM across the set for each hour. The latest returned point is about 14.3%, which means the busiest aligned VM in that hour still averaged comfortably below saturation.

Read Logging ingestion as a Monitoring time series

During cost review, retention review, or when log volume itself is the problem. It is typically triggered by you need a numeric signal for logging ingestion rather than reading raw entries. Read-only. Show that Logging already emits Monitoring-native usage series.

Query recent points for the Logging bytes-ingested metric.

$token = gcloud auth print-access-token
$headers = @{ Authorization = "Bearer $token" }
$start = [uri]::EscapeDataString((Get-Date).ToUniversalTime().AddDays(-1).ToString('o'))
$end = [uri]::EscapeDataString((Get-Date).ToUniversalTime().ToString('o'))
$filter = [uri]::EscapeDataString('metric.type = "logging.googleapis.com/billing/bytes_ingested"')
$uri = "https://monitoring.googleapis.com/v3/projects/bq-wh-nb/timeSeries?filter=$filter&interval.startTime=$start&interval.endTime=$end&view=FULL&pageSize=5"
(Invoke-RestMethod -Headers $headers -Uri $uri -Method Get) | ConvertTo-Json -Depth 100
{
  "timeSeries": [
    {
      "metric": {
        "labels": {
          "resource_type": "audited_resource"
        },
        "type": "logging.googleapis.com/billing/bytes_ingested"
      },
      "resource": {
        "type": "global",
        "labels": {
          "project_id": "bq-wh-nb"
        }
      },
      "metricKind": "DELTA",
      "valueType": "INT64",
      "points": [
        {
          "interval": {
            "startTime": "2026-04-13T13:42:00Z",
            "endTime": "2026-04-13T13:43:00Z"
          },
          "value": {
            "int64Value": "25870"
          }
        },
        {
          "interval": {
            "startTime": "2026-04-13T13:41:00Z",
            "endTime": "2026-04-13T13:42:00Z"
          },
          "value": {
            "int64Value": "5680"
          }
        },
        {
          "interval": {
            "startTime": "2026-04-13T13:40:00Z",
            "endTime": "2026-04-13T13:41:00Z"
          },
          "value": {
            "int64Value": "167"
          }
        },
        {
          "interval": {
            "startTime": "2026-04-13T13:36:00Z",
            "endTime": "2026-04-13T13:37:00Z"
          },
          "value": {
            "int64Value": "26126"
          }
        },
        {
          "interval": {
            "startTime": "2026-04-13T13:35:00Z",
            "endTime": "2026-04-13T13:36:00Z"
          },
          "value": {
            "int64Value": "6531"
          }
        }
      ]
    }
  ],
  "nextPageToken": "COejn43bir-CYhKFASIXChAKBgiE4vPOBhIGCMDi884GEgMQgzMqBmdsb2JhbDJiahcKB3Byb2plY3QaDDM0ODU1NzA5MjUxNGoQCgZyZWdpb24aBmdsb2JhbGoLCgRoYXNoGgM0NjZyKAoUbWV0cmljOnJlc291cmNlX3R5cGUaEGF1ZGl0ZWRfcmVzb3VyY2U",
  "unit": "By"
}

This is the cleanest live example of the Logging-Monitoring bridge. The project can already chart bytes ingested into log buckets without creating a custom metric. The current points show bursts tied to audited_resource, which matches the audit-heavy activity observed in the Logging note.

Warnings And Anti-Patterns

These are the mistakes that most often turn Monitoring from a decision tool into a source of false confidence or alert noise.

Do not treat missing data as healthy data

A query that returns nothing can mean the metric does not exist, the filter is wrong, the ingest delay has not elapsed, the resource labels do not match, or the alert evaluation window is too tight.

Check schema and delay before blaming the workload

Read the descriptor first, confirm samplePeriod and ingestDelay, then validate the metric filter and monitored resource labels.

Do not alert directly on noisy raw series

Raw one-minute points often flap because they represent transient spikes, not stable states.

Align and reduce before you page people

Use alignment to smooth to the decision window you actually care about, then reduce only across the resource set that should share one incident.

Do not use unbounded labels in custom or log-based metrics

Labels like full timestamps, UUIDs, or request IDs create time-series explosions, higher cost, and unreadable dashboards.

Keep labels bounded and operational

Good labels are environment, pipeline name, result class, service name, zone, or bounded error family.

Recommendations And Production Rules

These rules translate the archived project findings into a safer operating model for metrics and alerts.

Read the metric descriptor before you design the chart or the alert. metricKind, valueType, unit, samplePeriod, and ingestDelay are not metadata trivia. They determine what the data means and when it is safe to act on it.

Treat alerting as a control system, not as a checkbox. A policy with no channel, no retest window, or no log investigation path is incomplete even if the object exists in Monitoring.

Pair every important alert with the log query that explains it. Metrics surface the anomaly. Logs explain the anomaly. If the team cannot pivot from a chart to a log query quickly, the observability design is unfinished.

Remember that Monitoring API read cost is tied to time series returned rather than only raw API call count, so broad, high-cardinality queries are more expensive than focused reads. The current pricing page also notes that some alerting charges are effective no sooner than May 1, 2026, so review pricing before turning large alert estates into default platform behavior.

Data-Engineering Scenarios

These scenarios show where Monitoring should lead the investigation and where Logging should take over.

Backlog is rising

For consumer lag, start with the native backlog metric for the transport, not with application logs. After the metric proves the backlog is real and sustained, pivot into logs to find whether the cause is authentication failure, downstream slowness, dead-letter churn, or retry amplification.

VM-backed batch worker is slow

Use raw VM CPU and scheduler metrics to determine whether the worker is compute-bound, then read host or application logs to separate saturation from lock waits, network stalls, or external dependency failures.

Logging cost is rising

Do not begin in raw log search. Begin with Monitoring metrics such as logging.googleapis.com/billing/bytes_ingested, then pivot into Logging to determine which resource type or log family is driving the increase.

Alert did not fire

Check the chain in order:

  1. Did the time series exist?
  2. Did the policy exist?
  3. Did the condition align and reduce in the intended way?
  4. Did the channel exist and stay enabled?
  5. Did the incident auto-close or never open because missing data logic masked it?

Troubleshooting And Runbooks

These runbooks focus on metric query failures, silent alerts, and noisy evaluations.

Metrics exist but the query returns nothing

Use this sequence:

  1. Read the descriptor and confirm the metric type exactly.
  2. Confirm the monitored resource type and labels.
  3. Extend the query interval past samplePeriod + ingestDelay.
  4. Remove reduction first, then remove alignment, then widen the label filter.
  5. Only after the read works should you tighten the query again.

Alert did not fire

Because the archived project had no alerting policies, this is an architectural runbook rather than a live object inspection:

  1. Verify the underlying metric exists with raw API reads.
  2. Verify the alert threshold would actually have been crossed after alignment and reduction.
  3. Verify the policy condition window was longer than metric delay and shorter than the incident you care about.
  4. Verify at least one enabled notification channel exists.

Alert fires too often

The usual causes are one of these:

  1. The signal is too raw and should be aligned.
  2. The reducer collapses unlike resources into one noisy incident.
  3. The threshold is too close to normal variance.
  4. The alert is really a log-search problem and should not be a metric alert.

Cloud Run or pipeline logs are fragmented across services

Use Monitoring first to identify the time window and the stressed service, then pivot into Logging with that window, service name, and severity filter. A metric narrows the timeline. A log query explains the sequence.

Quick Reference

Use this table when you know the operational question and need the shortest verified path to the answer.

NeedFastest live workflow
Verify current stable Monitoring CLIgcloud monitoring --help
Check if the project has dashboardsgcloud monitoring dashboards list --format=json
Check if alerts existgcloud monitoring policies list --format=json
Check if uptime checks existgcloud monitoring uptime list-configs --format=json
List supported notification typesgcloud beta monitoring channel-descriptors list --format="value(type)"
Read a descriptor liveMonitoring v3 API metricDescriptors call with gcloud auth print-access-token
Read raw VM points liveMonitoring v3 API timeSeries call with view=FULL
Read aligned fleet points liveAdd aggregation.alignmentPeriod, perSeriesAligner, and crossSeriesReducer
Check logging usage numericallyQuery logging.googleapis.com/billing/bytes_ingested

These notes extend the Monitoring workflow into log investigation and broader observability design.

Cloud Monitoring Metrics References

These official references were used to verify metric kinds, API surfaces, notification channels, uptime behavior, and pricing.