Skip to content

Google Cloud Monitoring

Monitor your Google Cloud project — Compute Engine VMs, Cloud SQL instances, HTTP(S) load balancers, Pub/Sub subscriptions, and Cloud Storage buckets — through Cloud Monitoring, with curated dashboards and alerts you import in one step.

Cloud Monitoring (the metrics half of Google Cloud Observability, formerly Stackdriver) is a polled API rather than a scrape endpoint, but no adapter is needed: the LeanSignal agent gateway is an OpenTelemetry Collector distribution and bundles the googlecloudmonitoring receiver, which reads the time series you name with a read-only service account. The gateway keeps full fidelity locally and forwards only the demanded subset to your central dataplane — so polling broadly stays cheap, and importing a demand is what decides which Google Cloud series are stored centrally.

The panels and alerts cover the five services most projects run on — Compute Engine, Cloud SQL, Cloud Load Balancing, Pub/Sub, and Cloud Storage — with the thresholds Google Cloud operators actually page on: server state, disk headroom, 5xx ratios, backend latency, and subscription backlog age.

  • A LeanSignal agent gateway deployed and connected — one per cluster or environment. If you haven’t deployed it yet, follow Install the agent (source: LeanSignal/leansignal-agent). It should show as Connected under Agents in the LeanSignal app.
  • Network reachability to the gateway’s OTLP port4317 (gRPC) or 4318 (HTTP). See Agent configuration.
  • A read-only Google Cloud identity — a service account with the Monitoring Viewer (roles/monitoring.viewer) role on each project you poll, reachable through Application Default Credentials — and an OpenTelemetry Collector running the googlecloudmonitoring receiver, which the LeanSignal agent gateway already bundles. Both configured in Setup.
  • Editor or admin role in the LeanSignal app (importing a demand creates dashboards and alert rules).

Two pieces: a read-only Google Cloud identity, and a collector running the googlecloudmonitoring receiver that polls Cloud Monitoring and forwards OTLP to the gateway.

1. Google Cloud — a read-only identity. Create a service account with the Monitoring Viewer role on every project you poll:

Terminal window
PROJECT=my-project-id
gcloud iam service-accounts create leansignal-monitor \
--project "$PROJECT" --display-name "LeanSignal metric reader"
gcloud projects add-iam-policy-binding "$PROJECT" \
--member "serviceAccount:leansignal-monitor@$PROJECT.iam.gserviceaccount.com" \
--role roles/monitoring.viewer
# Only if the collector runs outside Google Cloud:
gcloud iam service-accounts keys create /etc/leansignal-agent/gcp-key.json \
--iam-account "leansignal-monitor@$PROJECT.iam.gserviceaccount.com"

The receiver authenticates with Application Default Credentials. On GKE use Workload Identity, on a VM use the attached service account — nothing else to configure. Off Google Cloud, point GOOGLE_APPLICATION_CREDENTIALS at the key file above (for a systemd install, add it to /etc/leansignal-agent/agent.env).

2. Collector — poll Cloud Monitoring, forward OTLP to the gateway (not a SaaS endpoint). metrics_list is the whole poll surface: one entry per metric type, and the dashboards chart exactly these.

receivers:
# One receiver per project — add googlecloudmonitoring/<other-project> blocks
# and list them all in the pipeline below.
googlecloudmonitoring:
project_id: my-project-id
collection_interval: 300s # minimum 60s; each poll is one API call per metric
metrics_list:
# Compute Engine
- metric_name: "compute.googleapis.com/instance/cpu/utilization"
- metric_name: "compute.googleapis.com/instance/cpu/reserved_cores"
- metric_name: "compute.googleapis.com/instance/network/received_bytes_count"
- metric_name: "compute.googleapis.com/instance/network/sent_bytes_count"
- metric_name: "compute.googleapis.com/instance/network/received_packets_count"
- metric_name: "compute.googleapis.com/instance/network/sent_packets_count"
- metric_name: "compute.googleapis.com/instance/disk/read_bytes_count"
- metric_name: "compute.googleapis.com/instance/disk/write_bytes_count"
- metric_name: "compute.googleapis.com/instance/disk/read_ops_count"
- metric_name: "compute.googleapis.com/instance/disk/write_ops_count"
# Cloud SQL
- metric_name: "cloudsql.googleapis.com/database/up"
- metric_name: "cloudsql.googleapis.com/database/cpu/utilization"
- metric_name: "cloudsql.googleapis.com/database/memory/utilization"
- metric_name: "cloudsql.googleapis.com/database/disk/utilization"
- metric_name: "cloudsql.googleapis.com/database/disk/bytes_used"
- metric_name: "cloudsql.googleapis.com/database/disk/quota"
- metric_name: "cloudsql.googleapis.com/database/network/connections"
- metric_name: "cloudsql.googleapis.com/database/replication/replica_lag"
# Cloud Load Balancing
- metric_name: "loadbalancing.googleapis.com/https/request_count"
- metric_name: "loadbalancing.googleapis.com/https/backend_latencies"
# Pub/Sub
- metric_name: "pubsub.googleapis.com/subscription/num_undelivered_messages"
- metric_name: "pubsub.googleapis.com/subscription/oldest_unacked_message_age"
- metric_name: "pubsub.googleapis.com/subscription/sent_message_count"
- metric_name: "pubsub.googleapis.com/subscription/ack_message_count"
- metric_name: "pubsub.googleapis.com/subscription/dead_letter_message_count"
- metric_name: "pubsub.googleapis.com/subscription/expired_ack_deadlines_count"
# Cloud Storage
- metric_name: "storage.googleapis.com/storage/total_bytes"
- metric_name: "storage.googleapis.com/api/request_count"
processors:
# Required — Google Cloud's *_count metrics are delta temporality, which a
# Prometheus store cannot hold. Accumulates them into cumulative series.
deltatocumulative: {}
# Required — see "Google Cloud units" below. Keeps metric names as the GCP
# metric type, with dots and slashes as underscores.
transform/gcp_units:
error_mode: ignore
metric_statements:
- set(metric.unit, "") where IsMatch(metric.name, "googleapis")
batch: {}
exporters:
otlp:
endpoint: leansignal-agent:4317 # per-cluster gateway (use :4318 for HTTP)
tls:
insecure: true # in-cluster plaintext; provide ca_file for TLS
service:
pipelines:
metrics:
receivers: [googlecloudmonitoring]
processors: [deltatocumulative, transform/gcp_units, batch]
exporters: [otlp]

Running this on the gateway itself instead? Add the googlecloudmonitoring receiver and both processors to its own config, then add them to its metrics/all pipeline — the otlp exporter and the separate service block above are only for a standalone collector.

To confirm metrics are arriving, look for the compute_googleapis_com_* family in the LeanSignal app under Metrics with the source set to Available, or on the gateway host:

Terminal window
curl -s http://127.0.0.1:8428/api/v1/label/__name__/values | grep -o '[a-z]*_googleapis_com_[a-z_]*' | sort -u | head

Cloud Logging reaches the gateway through Pub/Sub, the export path Google itself is built around: create a log sink that routes the logs you want to a Pub/Sub topic, give the collector a subscription on it, and point the gateway’s bundled googlecloudpubsub receiver at that subscription — the streams then behave like any other logs.

Terminal window
gcloud logging sinks create leansignal-logs \
pubsub.googleapis.com/projects/my-project-id/topics/leansignal-logs \
--log-filter='resource.type="cloud_run_revision" OR resource.type="gce_instance"'
extensions:
googlecloudlogentry_encoding:
receivers:
googlecloudpubsub:
project: my-project-id
subscription: projects/my-project-id/subscriptions/leansignal-logs
encoding: googlecloudlogentry_encoding # decodes Cloud Logging LogEntry JSON

Grant the sink’s writer identity (printed by gcloud logging sinks create) roles/pubsub.publisher on the topic, and the collector’s service account roles/pubsub.subscriber on the subscription. Then add googlecloudpubsub to a logs pipeline exporting OTLP to the gateway (or to the gateway’s own logs/all pipeline), and list the extension under service.extensions. Keep the sink filter tight — Cloud Logging exports everything the filter matches, and a subscription with no subscriber running retains messages until they expire.

Traces are an application concern, not a Cloud Monitoring one — instrument the workloads running on Google Cloud with the OpenTelemetry SDKs (see the runtime integrations) and point them at the gateway.

Google Cloud Monitoring ships as a ready-made demand in three variants. You don’t copy any JSON — in the LeanSignal app go to Demands, press the ˅ arrow on the Add Demand button (the arrow opens the import menu), choose Import from catalog…, and pick the variant. Each variant below lists the slug that identifies its published bundle. See Integrations for the full import flow.

The variants are nested — Standard is a superset of Essential, Extended a superset of Standard. Pick whichever is closest to what you need and treat it as a starting point: after import everything is a normal, editable copy, so retune thresholds, add or drop panels, and adjust queries for your environment — your edits reshape the demand automatically. Start small and re-import a larger variant later if you outgrow it.

The failure signals. 1 dashboard · 10 panels · 5 alerts — CPU, server state, disk headroom, 5xx responses, and subscription backlog at a glance.

Import this variant from the catalog. Its demand slug:

Demand slug
google-cloud-monitoring-otel-demand-essential

Dashboard — CPU utilization, Network in / out, Server up, CPU utilization, Disk utilization, Requests, 5xx responses, Oldest unacked message age, Undelivered messages, and Bytes stored.

Alerts (5)

AlertSeverityFires when
Load balancer high 5xx ratiowarning5xx > 5% of requests for 10m
Cloud SQL instance downcriticalinstance not serving for 10m
Cloud SQL disk nearly fullcritical> 90% of disk used for 15m
Pub/Sub backlog agingwarningoldest unacked message > 10m old, for 10m
Pub/Sub backlog growingwarning> 1000 undelivered messages for 15m

Review the bundle JSON →

Each variant imports one Google Cloud Monitoring dashboard, its panels grouped into collapsible sections. Every dashboard carries an Instance filter (on the project_id label), so one import covers the whole fleet — view every instance at once, or focus on one. Legends are sortable tables showing last/mean/max per series, so the outlier instance stands out. Dashboards are demand-driven: importing one tells your agents to forward exactly the timeseries its panels query, and nothing else. Panels are ordinary Perses panels — edit queries, add panels, or retune them after import, and your changes reshape the demand automatically.

Thresholds are conservative starting points — tune them to your workload.

Was this page helpful?