gcp-sandbox.orgOne Google Cloud service and one hands-on lab a day. Independent; not affiliated with Google.
Thursday, October 29, 2026BeginnerObservability

Cloud Logging from Cloud Shell: write a log entry, then find it again with a filter

Every Google Cloud project already has a logbook. Learn where entries go, write a few of your own, search them by severity and JSON field, then delete the practice log so nothing is left behind.

Cloud Logging, in plain words

Cloud Logging is the place where Google Cloud keeps the running diary of your project: messages your apps print, requests that hit a load balancer, and audit records of who changed what. It is on by default, so a brand-new project already collects entries. Each log entry has a timestamp, a severity (from DEBUG up to EMERGENCY), the resource it came from, and a payload that is either plain text (textPayload) or structured JSON (jsonPayload).

Entries do not just land in one pile. A Log Router in every project passes them through sinks. The _Required sink sends key audit logs, such as Admin Activity, to the _Required bucket, which keeps them for 400 days and cannot be changed or deleted. The _Default sink sends almost everything else to the _Default bucket, kept for 30 days by default. You can edit the _Default sink, add exclusion filters to drop noisy entries, or add your own sinks that copy logs to BigQuery, Cloud Storage or Pub/Sub.

To read logs you use the Logs Explorer in the console or gcloud logging read in a terminal. Both speak the same Logging query language: severity>=WARNING, jsonPayload.user="ana", or log_id("my-app"). Writing logs into storage costs $0.50 per GiB after the first 50 GiB per project each month, which includes 30 days of storage, and querying is free, so a small lab like this one costs nothing. Recent news: the September 28, 2026 release notes say the legacy Logging agent has reached end of support (the Ops Agent replaces it) and that only platform services can now write entries to billing accounts.

Reach for it when

  • An app on Cloud Run, GKE or Compute Engine misbehaves and you need to see what it printed in the minutes before the error, filtered to severity>=ERROR.
  • You need to answer who deleted a VM or changed an IAM policy last week, which the Admin Activity audit logs in the _Required bucket already record.
  • You want to send a copy of certain logs to BigQuery for long-term analysis or to Pub/Sub so another system can react to them, using a Log Router sink.

Skip it when

  • You need numbers over time, such as request latency or CPU use, with charts and alerts; that is Cloud Monitoring's job (a log-based metric can bridge the two, but it is billed as a Monitoring custom metric).
  • You want to follow one request as it hops across many services; Cloud Trace shows that path far better than reading log lines side by side.
  • You plan to dump very chatty debug output from busy services forever; past the free 50 GiB per month every GiB is billed, so add exclusion filters or log less first.

The AI angle

Logs and AI meet in two ways. In the Logs Explorer you can select an entry and click Investigate log to have Gemini Cloud Assist summarize it in plain words; it sees only that entry's text, needs Cloud Assist set up first, and Google warns the summary can be wrong, so check it. Going the other way, AI workloads such as Gemini Enterprise Agent Platform (formerly Vertex AI) endpoints and agents write their own logs here, and writing your app's prompts, model IDs and latencies as jsonPayload fields makes them easy to filter and to route into BigQuery for evaluation.

Hands-on lab: Write, search and delete your own practice log

Write text and JSON log entries with different severities from Cloud Shell, find them with three kinds of filter, look at them in the Logs Explorer, then delete the practice log.

TIME10 minutes
COSTEffectively $0. A handful of log entries is a few kilobytes, far inside the free allotment; querying logs is not charged.
FREE TIER / CREDITSThe first 50 GiB of logs written into log buckets per project per month are free, and storage for the default 30 days is included. Nothing in this lab is retained longer than that.

Before you start

  • A sandbox Google Cloud project you own (shown here as YOUR_PROJECT_ID) with billing linked.
  • Cloud Shell, or any terminal with the gcloud CLI signed in as a user who can write, read and delete logs (the Logs Writer, Logs Viewer and Logging Admin roles; a project Owner has all three).
  • Optional: Gemini Cloud Assist set up for your account if you want to try the Investigate log button.
  1. Point gcloud at your sandbox project

    Open Cloud Shell, set the project and pick a name for the practice log. The Cloud Logging API is normally on already; enabling it again does no harm.

    gcloud config set project YOUR_PROJECT_ID
    export LOG_ID="sandbox-lab-log"
    gcloud services enable logging.googleapis.com
  2. Write three entries

    Write one plain text entry, one warning and one structured JSON entry. With no extra flags, gcloud logging write uses the global resource type and severity DEFAULT; --payload-type=json stores the message as jsonPayload so each key becomes a searchable field.

    gcloud logging write "$LOG_ID" "Hello from the sandbox lab"
    gcloud logging write "$LOG_ID" "Disk is almost full" --severity=WARNING
    gcloud logging write "$LOG_ID" '{"user": "ana", "action": "checkout", "ms": 840}' --payload-type=json --severity=ERROR
  3. Read the log back

    log_id() takes the plain log name, so you do not have to URL-encode anything. Newest entries come first by default, and --freshness limits the search to the last hour. If nothing shows, wait a few seconds and run it again.

    gcloud logging read "log_id(\"$LOG_ID\")" --freshness=1h --limit=10 \
      --format="table(timestamp, severity, textPayload, jsonPayload.user)"
  4. Filter by severity and by a JSON field

    The first query keeps only entries at WARNING or worse, so the hello message disappears. The second reaches inside the JSON payload. Field names inside jsonPayload are case-sensitive; AND must be upper case.

    gcloud logging read "log_id(\"$LOG_ID\") AND severity>=WARNING" --freshness=1h \
      --format="table(timestamp, severity)"
    
    gcloud logging read "log_id(\"$LOG_ID\") AND jsonPayload.user=\"ana\"" --freshness=1h \
      --format=json
  5. See the same entries in the Logs Explorer

    In the console, open Logging > Logs Explorer, paste log_id("sandbox-lab-log") into the query box and run it. Expand the ERROR entry to see its jsonPayload fields. If Gemini Cloud Assist is set up, click Investigate log to get a plain-language summary, and treat it as a hint, not a fact. Also run gcloud logging logs list to see your log next to the ones Google Cloud wrote for you.

    gcloud logging logs list --limit=20

Check that it worked

The first read shows three entries; the severity filter shows two (WARNING and ERROR); the JSON filter returns one entry whose jsonPayload has user "ana", action "checkout" and ms 840.

Clean up

The lab created only log entries in your practice log. Delete them (this removes every entry in that one log from the _Default bucket and asks for confirmation unless you pass --quiet), then confirm the log is gone. Do not delete any other log. Leave the Cloud Logging API enabled: Google Cloud itself writes logs through it. If you made a project just for this lab, you can delete the whole project instead.

gcloud logging logs delete "$LOG_ID" --quiet

# Confirm: no line should mention sandbox-lab-log, and the read should return nothing
gcloud logging logs list | grep "$LOG_ID" || echo "Practice log is gone"
gcloud logging read "log_id(\"$LOG_ID\")" --freshness=1h --limit=1
unset LOG_ID

Gotchas

  • gcloud logging logs delete clears the log only in the _Default bucket and needs the Logging Admin role. It does not touch copies a sink already sent to BigQuery or Cloud Storage, or Error Reporting samples.
  • When you filter on logName you must URL-encode slashes in the log ID (%2F); log_id("...") takes the plain name and avoids the problem.
  • gcloud logging read only looks back one day by default (--freshness=1d) and has no default limit, so add --limit and a time window before querying a busy project.
  • Exclusion filters stop entries from being stored and billed, but the entries still count against the entries.write API quota because exclusion happens after Logging receives them.
  • The _Default bucket keeps entries for 30 days. Raising retention costs $0.01 per GiB per month for anything kept beyond 30 days; the _Required bucket's 400 days are free and cannot be changed.