Google Cloud has a signal the other clouds do not, and most teams under-use it. Error Reporting groups exceptions by stack trace and tells you which release each group first appeared in — which is deploy correlation, already computed, for free. On any other platform you assemble that yourself from logs and deploy timestamps, and the result is the assumed causal link we keep having to cap confidence on.
Getting alerts in
Cloud Monitoring's alerting policies post a webhook with an incident object.
Simple shape, two things to know about it.
| Field | Becomes | Note |
|---|---|---|
incident_id | external id | Stable across open and close, which is what makes the resolve match reliably. |
policy_name | alert name | So name your policies as you would name alerts. "Orders API error rate" beats "Policy 4". |
resource.labels | labels | Where service_name, cluster_name, location live. This is what match rules bind to. |
state / ended_at | resolved | closed, or any non-null ended_at. |
started_at | started | Epoch seconds, not a string — a parser that assumes ISO-8601 silently loses the timestamp. |
Severity is usually absent
Cloud Monitoring only carries a severity when the policy explicitly sets one, and most do not. Unset defaults to warning here. If you route by severity, set it on your policies — otherwise every GCP alert arrives at the same level and your routing does nothing.
Error Reporting, and why it is the interesting one
Compare what each signal can establish about "did the release cause this?"
two things in one window.
Confidence capped at 0.75."] end subgraph E["From Error Reporting"] E1["Group abc123: 4,201 events,
first seen 02:11"] --> E2["affectedServices:
orders-api v2.4.1 only"] E2 --> E3["Established
this signature does not exist
in the previous version."] end style L3 fill:#fff4e2,stroke:#f4a03a style E3 fill:#e8f8f4,stroke:#22c1a4,stroke-width:2px
That is the same lift a change-management system gives you, obtained from the runtime instead
of from a process. The gcp.errors step returns grouped exceptions with counts,
affected user counts, first- and last-seen times and the service versions each group
appears in — and "first seen 02:11, present only in v2.4.1" is not a correlation, it
is an observation about which build the signature exists in.
The three read steps
| Step | What it answers |
|---|---|
gcp.metrics | A Cloud Monitoring time series by filter, with an aligner. The GCP equivalent of a range query. |
gcp.logs | Cloud Logging entries matching a filter, newest first. Severity, timestamp and payload. |
gcp.errors | Error Reporting groups. Put this early — it frequently answers the incident before the log step runs. |
A Cloud Run runbook that uses all three, in the order that makes the fourth step's job easiest:
1 gcp.metrics metric.type="run.googleapis.com/request_count" resource.labels.service_name="{{service_name}}" → request_rate 2 gcp.errors service="{{service_name}}", window 60m → error_groups 3 gcp.logs severity>=ERROR resource.type="cloud_run_revision" → error_logs 4 ai.classify context_vars: request_rate, error_groups, error_logs 5 ai.verify conclusion_var: classification
Authentication, three ways
In order of preference, and the first two need no secret at all:
- The metadata server. Running on GCE, GKE or Cloud Run, the workload's own service account is used. Nothing to configure, nothing to rotate.
- An explicit token via
GCP_ACCESS_TOKEN, for short-lived or federated setups. - A service-account key at
GOOGLE_APPLICATION_CREDENTIALS, signed into a JWT and exchanged for an access token — the standard OAuth 2.0 JWT bearer flow, done directly rather than throughgoogle-auth.
Roles needed, all read-only: roles/monitoring.viewer,
roles/logging.viewer, roles/errorreporting.viewer.
One thing we could test live, and did
GCP publishes its incident feed publicly, so the cloud.health step for GCP
is the one part of this connector verified against the real thing rather than against
documentation. It answers, correctly, "GCP reports nothing open. Whatever this is,
it is ours." Everything else here is built to the published APIs and tested through
the product, but not against a live project.
Getting it wired
- A notification channel of type webhook pointed at
/api/webhooks/gcp?token=…, attached to the alerting policies you want triaged. - Name the policies properly and set a severity on each. Both become the thing your match rules bind to.
- Set
GCP_PROJECT(or let it come from the service-account key), and grant the three viewer roles. - Put
gcp.errorsbeforegcp.logsin your first runbook. It is the step most likely to make the rest unnecessary.
Next in this series
InsightResolve on Oracle Cloud — Notifications, request signing, and a status feed that turns out not to be a status page at all.