Run an aggregate query or return a scoped set of raw rows from a Honeycomb dataset. When to use this tool: - "Reconstruct the events for one session", filter to the session and request the needed raw_row_columns. - "Compute a percentile / histogram of X", use P50/P99/HEATMAP calculations. - "Show me error rate before and after deploy", use two named calcs + a formula, scoped by time. - "Rank services by p99 latency", use P99 with a breakdown + order. - "See distinct values of X and their frequency", COUNT with a breakdown on X. - "Compare request volume across services", COUNT breakdown on service.name. - "Find endpoints where tail latency exceeds 1s", P99 + having clause. - "Generate a heatmap of request duration", HEATMAP calculation. When NOT to use this tool: - Discovering what spans or operations exist → use list_spans instead. - Looking at a specific trace → use get_trace instead. - Finding existing saved queries → use find_queries instead. - Exploring which columns a dataset has → use get_dataset_columns or find_columns first. Pairs with: list_spans, get_span_details, find_columns, get_dataset_columns, get_trace, run_bubbleup. <examples> Basic COUNT over the last 24 hours: ```json {"environment_slug": "production", "dataset_slug": "api", "query_spec": {"calculations": [{"op": "COUNT"}], "from": "-24h"}} ``` Raw rows for one session, limited to ten selected columns and up to 100 matching events: ```json {"environment_slug": "production", "dataset_slug": "agent-events", "query_spec": { "filters": [{"column": "session.id", "op": "=", "value": "session-123"}], "from": "-2h"}, "raw_row_columns": [ "session.id", "gen_ai.operation.name", "gen_ai.agent.name", "gen_ai.tool.name", "gen_ai.tool.call.id", "gen_ai.tool.call.arguments", "gen_ai.tool.call.result", "error", "duration_ms", "trace.trace_id"], "results_limit": 100} ``` When a raw-row response includes next_cursor, fetch the next page by repeating the request with the same scope, replace the prior time fields in query_spec with the response Metadata's absolute from and to, and pass next_cursor as cursor. Continue until next_cursor is omitted. Error rate formula: two named calcs combined with a formula, ordered by the formula name (the correct ordering style when formulas are present). The passthrough formula "volume" surfaces a raw calc value alongside formulas: ```json {"environment_slug": "production", "dataset_slug": "api", "query_spec": { "calculations": [ {"op": "COUNT", "name": "total"}, {"op": "COUNT", "name": "errors", "filters": [{"column": "error", "op": "=", "value": true}]}], "formulas": [ {"name": "error_rate", "expression": "$errors / $total * 100"}, {"name": "volume", "expression": "$total"}], "breakdowns": ["service.name"], "orders": [{"column": "error_rate", "order": "descending"}], "from": "-1h", "limit": 20}} ``` Relational fields: any.X in a breakdown requires a matching WHERE filter on the same any.X column: ```json {"environment_slug": "production", "dataset_slug": "traces", "query_spec": { "calculations": [{"op": "COUNT"}, {"op": "P99", "column": "duration_ms"}], "filters": [{"column": "any.http.route", "op": "exists"}], "breakdowns": ["any.http.route"], "from": "-2h"}} ``` </examples> <interpreting_results> The response is rendered as Markdown with these sections (each is omitted if empty): - "# Results", a Markdown table of aggregate rows. Headers are breakdown columns followed by calculation columns. When formulas are present, the table contains ONLY breakdown columns and formula columns, raw calculation columns (including percentiles like P50/P95, and even named COUNTs) are NOT rendered. To surface a raw calculation's value alongside formulas, add a passthrough formula such as {"name": "p95", "expression": "$p95_latency"}. If a breakdown's cardinality exceeded the spec's limit, an "OTHER" row collapses the remainder; a "TOTAL" row may also appear summing across groups. A "Truncated: shown N / total M" footer indicates more rows than the table displays. - 1D heatmaps render inline within Results when a HEATMAP calculation has no breakdown. - "# Raw Rows", present when raw_row_columns is provided. Contains matching events restricted to those columns, plus timestamp. The row and column counts share a 1000-value budget. Metadata includes the effective absolute from and to. A full page also includes next_cursor; pass it as cursor in an otherwise equivalent request with those absolute time bounds to fetch more rows. Pagination is not a snapshot. - "# Time Series", ASCII line graphs per group when the spec has a granularity (time-bucketed series). Width 120, height 12. - "# Heatmaps", 2D time-series heatmaps when a HEATMAP calculation is paired with breakdowns or granularity. - "# Markers", deploy/incident markers overlapping the time range, when present. Includes both dataset-scoped and environment-wide markers; the Scope column labels each row "dataset" or "environment". - "# Query Spec", the canonicalized JSON spec the server actually executed. Useful when comparing what you sent to what ran. - "Metadata:" YAML block at the bottom, contains query_run_pk (passable to get_query_results), query_url (Honeycomb permalink to share with humans), query_result_json / query_result_image (download URLs), elapsed_str, granularity, total (result count), rows_examined. When the requested or auto-selected granularity was adjusted (clamped to the valid window, or raised to the metrics-dataset floor), granularity_note explains the change and granularity_requested echoes an explicit request. When data is sampled, a sampling banner appears above Results listing the mean sample rate and which calculations are sample-rate-weighted vs. raw. If mean_sample_rate > 10x and usage_mode is off, an extra warning notes that COUNT values are corrected estimates and won't match raw trace span counts. When results contain a trace.trace_id column (grouped-by or in raw rows), a "Trace links" block above Results lists ready-to-use UI URLs for those traces. These are already scoped to this query's time range, pass them through verbatim. Do NOT hand-build a trace URL from a trace ID: a link without the query's time scope resolves against a default 2h window and fails to load older traces. </interpreting_results> Important: filter operators use symbols (=, >=, !=). Expression functions inside calculated_fields use words (GTE, EQUALS). Never use GTE/LTE as filter operators.
Parameters
Core query parameters. Time fields: use from/to. When omitted, the default 2-hour lookback is queried. <relational_fields> Each result row is a span. Prefix a column with one of these to read or test it on a related span in the same trace: Constraints: Note: To filter to root spans without joining, use a does-not-exist filter on the dataset's parent-id column. There is no "is_root" column in the query API. </relational_fields> <metrics_datasets> On metrics datasets, temporal aggregation (LAST, SUMMARIZE, INCREASE) is applied automatically based on metric type. Do not use these as calculated_field expressions. Operators not allowed on metrics datasets: RATE_SUM, RATE_AVG, RATE_MAX, CONCURRENCY, bare COUNT (without column). Use SUM, AVG, MAX, or percentiles on metric fields instead. COUNT_DISTINCT is not allowed on a metric column, since it would count distinct datapoint values. It is allowed on attribute columns, including alongside an aggregate over a metric column: COUNT_DISTINCT(host.name) with SUM(system.cpu.time) counts the hosts reporting. COUNT_DATAPOINTS(column) counts how many raw metric datapoints (samples) were reported for a metric column. HISTOGRAM_COUNT(column) returns the total number of observations recorded across a Metrics 2.0 histogram or summary column, the sum of its per-bucket counts. Reach for it when asked for the "sum of counts from a histogram", "total observations", "how many observations/samples are in this histogram", or "total request count from a latency histogram". COUNT_DATAPOINTS and HISTOGRAM_COUNT are only allowed on metrics datasets. For histogram metrics, use AVG/P50/P99/MAX/HEATMAP directly on the histogram column name. </metrics_datasets> <sampling> When data is sampled, results include sampling metadata. COUNT, SUM, AVG, percentiles, HEATMAP, CONCURRENCY, RATE_SUM, and RATE_AVG are weighted by sample rate. COUNT_DISTINCT, MIN, MAX, and RATE_MAX are not corrected. Set usage_mode=true to disable all sample rate correction and see raw event counts. </sampling>
Continue a raw-row query from the previous page. Copy the previous response's next_cursor value and repeat the same environment, dataset, filters, calculated fields, and selected columns. Replace all prior time fields with the absolute from and to values from the previous response's Metadata. Only valid with raw_row_columns.
Dataset identifier. Required unless environment_wide_query is true.
Query all datasets in the environment. When true, dataset_slug is not required. Not compatible with legacy environments. Default: false.
Include the table of deploy/incident markers overlapping the query window. Default: true. Set to false to skip markers you do not need, which avoids a wall of repeated deploy markers on every call.
Return raw matching events with only these columns. A non-empty list selects raw-row mode; omit calculations and other aggregate-only query fields. The event timestamp is always returned and does not need to be listed. Rows are returned in storage order, not time order; sort by the returned timestamp column before interpreting a sequence. Between 1 and 100 unique column names.
Maximum raw rows to return. Raw-row results are limited to 1000 returned values, including the timestamp column, so results_limit × (number of raw_row_columns + 1) must be at most 1000. If omitted, returns the largest number of rows that fits that budget. For aggregate queries, this legacy argument is accepted and ignored.
Team to run this tool against; only needed when your authorization covers multiple teams
Return raw event counts without sampling rate correction. Applies only to aggregate queries. Default: false.