Skip to main content
The query guide tells an agent which API operation answers a question, with example URLs. When no operation fits, the safe SQL API runs a bounded, read-only query over logs, spans, and metrics.

Find the right query

The response has one entry in surfaces for each query family: logs, metrics, traces, errors_and_events, ai_observability, monitors, and incidents. Each entry has: Log and event search q also accepts field://pattern// regular expressions (RE2 syntax, at most 64 characters). See Logs search syntax. The request needs the project:read scope. Call it first when you do not know which operation fits. For monitor and incident operations, see Monitors and Incidents.

Read the SQL schema

The response lists each table with its columns and types, its timestamp_column, and its retention_days. The safe SQL API accepts only these tables and columns. Every table uses timestamp as its time column. The attributes and resource columns hold OpenTelemetry attributes. Read one with a dotted path, for example attributes.http.request.method. Selecting the whole column returns a flat object with dotted keys, for example {"http.request.method": "GET"}. Use current attribute names. A path with an older name, such as attributes.http.method, reads the current name first and then the older one, and the result column keeps the name you wrote. See Use current attribute names.

Run a safe SQL query

The response has rows, columns (each with name and type), scanned_rows, scanned_bytes, and duration_ms. scanned_rows and scanned_bytes are the rows and bytes the query read, not the rows it returned. Use them to see the cost of a query and to narrow the time window or filters of an expensive one. Squasher adds the project filter to the query itself, so a query can read only its own project. To check a query before you run it, send the same body to /query/explain. It returns estimated_rows, estimated_bytes, suggested_indexes, and exceeds_budget, and it reads no rows.

Write a query that passes validation

Squasher checks every query before it runs:
  • Use one SELECT statement on one table. Joins, UNION, and scalar subqueries are rejected. A subquery or a CTE in FROM is allowed.
  • Put a lower bound on timestamp in the WHERE clause of every table scan. A bound inside NOT, or on only one side of an OR, does not count.
  • Keep the window to 30 days, or 90 days with long_range.
  • Name your columns. SELECT * is rejected.
  • Do not read outside the scanned rows. Dictionary and Join-table functions (dictGet, joinGet), file, URL and remote functions, server functions (hostName, getSetting, currentUser), sleep, and SELECT ... INTO are rejected.
  • Keep LIMIT at 10,000 or less.
A query can return at most 10,000 rows and 8 MiB.

Fix a rejected query

A rejected query returns status 400 with a code in error, a message, and often a hint. A status of 503 with QUERY_TEMPORARILY_UNAVAILABLE means the query backend is busy or briefly unavailable. Telemetry reads on other endpoints answer the same way. Wait for the Retry-After seconds, then retry, with a narrower window if the backend was busy.

Use the CLI or MCP

Pass --sql or --file. Over MCP, call search("query.run"), search("query.explain"), or search("schema.get"), then execute the operation.

Ready-made security queries

Squasher has ready-made queries over security events (OCSF attributes on logs), such as failed login bursts, root logins, and MFA changes. Each one has its SQL and, when it can alert, a query monitor config. install adds the queries to the project’s saved queries. A query the project already has is not added again. install needs a user token, because a saved query has an owner. run takes a query id from list, or its saved query id, and an optional { "long_range": true } body. A security query reads only the logs table and only ocsf.* and squasher.* attributes, plus cloud.provider, cloud.region, cloud.account.id, and user_agent.original. A rejected run returns QUERY_ORG_SCOPE_MISSING or QUERY_SCOPE_DENIED (403), QUERY_TABLE_NOT_ALLOWED, QUERY_ATTRIBUTE_NOT_ALLOWED, QUERY_TIME_RANGE_TOO_WIDE, or QUERY_ROW_LIMIT (400), or QUERY_BUDGET_EXCEEDED (429 with Retry-After). A query monitor that searches ocsf.* attributes gets the same checks.

Next steps

Find the API for a task

Map a task to its operations.

Logs API

Search logs with filters instead of SQL.