Logs are the first place you look when anything breaks, and routing them correctly controls cost and retention.
Cloud Logging collects logs from Google Cloud services automatically (Cloud Run, GKE, load balancers, audit logs) and from VMs via the Ops Agent. Explore them in Logs Explorer or with gcloud logging read.
Every entry has a resource.type (cloud_run_revision, gce_instance, k8s_container...), a severity, a timestamp, a logName and a payload: textPayload or structured jsonPayload. The Logging query language filters on these: AND, OR, NOT, comparison operators, : for "contains" and =~ for regular expressions.
Write structured logs: on Cloud Run, Cloud Run functions and GKE, a single-line JSON object on stdout is parsed into jsonPayload, and special fields like severity and message are understood.
print(json.dumps({"severity": "ERROR", "message": "payment failed", "order_id": 42}))Now you can query jsonPayload.order_id=42 instead of grepping text.
The Log Router sends every entry through sinks. By default _Required (audit logs, 400 days, free) and _Default (everything else, 30 days) log buckets receive them. Add sinks to export to BigQuery, Cloud Storage, Pub/Sub or other buckets, and exclusion filters to drop noisy logs. Ingestion beyond the free allowance is billed per GiB, so excluding debug noise saves real money.
Log-based metrics turn matching entries into Monitoring metrics you can alert on.
Example
# Errors from one Cloud Run service in the last 6 hours
gcloud logging read '
resource.type="cloud_run_revision"
AND resource.labels.service_name="orders-api"
AND severity>=ERROR' --freshness=6h --limit=20 \
--format="table(timestamp,severity,jsonPayload.message)"
# Structured field search and regex
gcloud logging read 'jsonPayload.order_id=42 OR textPayload=~"timeout after [0-9]+s"' --limit=5
# Count 5xx responses as a metric you can alert on
gcloud logging metrics create orders_5xx \
--description="5xx from orders-api" \
--log-filter='resource.type="cloud_run_revision" AND resource.labels.service_name="orders-api" AND httpRequest.status>=500'Remember
- Filter on resource.type, severity and payload fields
- Log one-line JSON to stdout to get structured jsonPayload
- Sinks route logs; exclusions cut ingestion cost
- _Required keeps audit logs 400 days, _Default 30 days
Watch out for
- Logging multi-line text or stack traces as many entries, which breaks searching and error grouping.