How to Write and Test Snuba Queries in Sentry’s Data Platform
This guide walks through discovering Snuba datasets and entities, inspecting their schemas, building queries with the Python SDK or Sentry code, testing via the Web UI or curl, and interpreting request, response, and debugging information including HTTP status codes and ClickHouse metrics.
Explore Snuba Data Model
Snuba queries require selecting a dataset, an entity, and understanding the entity schema. Documentation of the data model is at https://getsentry.github.io/snuba/architecture/datamodel.html. Datasets are defined in snuba/datasets/factory.py (https://github.com/getsentry/snuba/blob/master/snuba/datasets/factory.py). List declared entities with: snuba entities list Typical output includes discover, errors, events, groups, groupedmessage, etc. Describe a specific entity, e.g. groupedmessage, with: snuba entities describe groupedmessage The command prints the column list, types, and relationship definitions. For groupedmessage the output shows columns such as offset UInt64, project_id UInt64, id UInt64, and a LEFT join to the events table on project_id = LEFT.project_id and id = LEFT.group_id.
Prepare Snuba Query
Snuba uses the SnQL language (https://getsentry.github.io/snuba/language/snql.html). The Python SDK ( getsentry/snuba-sdk – https://github.com/getsentry/snuba-sdk) provides classes to build a Query object. Example:
query = Query(
dataset="discover",
match=Entity("events"),
select=[
Column("title"),
Function("uniq", [Column("event_id")], "uniq_events"),
],
groupby=[Column("title")],
where=[
Condition(Column("timestamp"), Op.GT, datetime.datetime(2021, 1, 1)),
Condition(Column("project_id"), Op.IN, Function("tuple", [1, 2, 3])),
],
limit=Limit(10),
offset=Offset(0),
granularity=Granularity(3600),
)Further details are in the SDK docs at https://getsentry.github.io/snuba-sdk/.
Send Query via Sentry
Sentry imports the Snuba SDK and provides a client API (see https://github.com/getsentry/sentry/blob/master/src/sentry/utils/snuba.py#L667). The API sends the Query object to Snuba and returns a dictionary containing data, meta, timing, and stats. Example response:
{
"data": [{"title": "very bad", "uniq_events": 2}],
"meta": [
{"name": "title", "type": "String"},
{"name": "uniq_events", "type": "UInt64"}
],
"timing": {"...": "details ..."}
}The meta section lists column names and ClickHouse‑inferred types.
Web UI Testing
Snuba ships a minimal Web UI reachable at http://localhost:1218/[DATASET]/snql. Paste a SnQL string into the query field; the JSON response matches the SDK output.
Sending Queries with curl
The Web UI performs a POST of a JSON payload. The same payload can be sent with curl or any HTTP client to the same endpoint.
Request and Response Formats
query: string containing the SnQL query. dataset: name of the dataset (may also be part of the URL). debug: includes detailed ClickHouse statistics. consistent: forces single‑threaded ClickHouse execution and guarantees order consistency via the in_order load‑balancing setting (https://clickhouse.tech/docs/en/operations/settings/settings/#load_balancing-in_order). turbo: applies the TURBO_SAMPLE_RATE defined in Snuba settings and prevents the FINAL mode from being applied unintentionally.
HTTP Status Codes
200– successful query. 400 – query validation failed (e.g., missing timestamp condition). 500 – ClickHouse‑related error such as timeout or connection issue. 429 – internal Snuba rate‑limiting.
Successful responses contain data, meta, timing, and stats. The stats dictionary includes fields such as clickhouse_table, final, sample, project_rate, global_rate, project_concurrent, global_concurrent, consistent, result_rows, result_cols, and query_id. The sql element shows the underlying ClickHouse query, and timing breaks down execution time into marks_ms stages (e.g., cache_get, cache_set, execute, prepare_query, validate_schema).
{
"data": [],
"meta": [{"name": "title", "type": "String"}],
"timing": {
"timestamp": 1621038379,
"duration_ms": 95,
"marks_ms": {
"cache_get": 1,
"cache_set": 4,
"execute": 39,
"prepare_query": 10,
"validate_schema": 34
}
},
"stats": {
"clickhouse_table": "errors_local",
"final": false,
"referrer": "http://localhost:1218/events/snql",
"sample": null,
"project_rate": 0,
"project_concurrent": 1,
"global_rate": 0,
"global_concurrent": 1,
"consistent": false,
"result_rows": 0,
"result_cols": 1,
"query_id": "f09f3f9e1c632f395792c6a4bfe7c4fe"
},
"sql": "SELECT (title AS _snuba_title) FROM errors_local PREWHERE equals((project_id AS _snuba_project_id), 1) WHERE equals(deleted, 0) AND greaterOrEquals((timestamp AS _snuba_timestamp), toDateTime('2021-05-01T00:00:00', 'Universal')) AND less(_snuba_timestamp, toDateTime('2021-05-11T00:00:00', 'Universal')) LIMIT 1000 OFFSET 0"
}Query Validation Errors
When validation fails, Snuba returns a JSON error object, for example:
{
"error": {
"type": "invalid_query",
"message": "missing >= condition on column timestamp for entity events"
}
}ClickHouse errors have a similar structure with type": "clickhouse" and a detailed message.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
