Run query
Run a time-series aggregation query against a Honeycomb dataset and return computed results.
When to use this tool:
- "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"}], "time_range": "24h"}}
```
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"}],
"time_range": "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"],
"time_range": "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.
- "# Samples" — present only when include_samples=true. Up to 10 raw matching events; aggregations are stripped from the underlying execution in this mode, so samples replace aggregates rather than accompany them.
- "# 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.
- "# 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 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.
</interpreting_results>
Important: filter operators use symbols (=, >=, !=). Expression functions inside calculated_fields use words (GTE, EQUALS). Never use GTE/LTE as filter operators.