ax — explore your OpenTelemetry data from the terminal
ax is a terminal app for exploring your OpenTelemetry data —
traces, logs, and metrics in axiom. It
correlates the three signals in a single keystroke, renders charts
inline as you query, and lets you edit dashboards live, without ever
leaving the terminal. Your data lives in Axiom and
is ingested via the open OTel standard.
What you can do
- Traces — open a trace to get the span waterfall, with each span's workload metrics (CPU, latency, request rate) shown inline. Pivot to the matching logs or metrics with one keystroke.
- Dashboards — list, open, and edit dashboards; rearrange tiles and save back to Axiom.
- Queries — write MPL and the chart renders next to the editor. A pragma sets the chart kind and display unit.
Getting set up
ax reads OpenTelemetry data stored in Axiom. You need an Axiom
workspace with telemetry flowing into it:
- Send OpenTelemetry data
- Create a free account · Getting started guide
- Datasets · MPL · APL · Dashboards · Monitors
Correlate traces, logs & metrics
A trace is the normal entry point. ax trace <trace-id> opens the span
waterfall with workload metrics shown inline (see below). From there
you can pivot to the logs for the same request, or to the logs and
metrics for the same workload.
Correlation uses OpenTelemetry semantic conventions, so it works
regardless of which exporter produced the telemetry. ax matches the
common OTel and Prometheus spellings of each identity (trace id, pod,
namespace, node, container), so a pivot that should match doesn't come
back empty because a field was named differently.
From the trace view:
| Keys | Pivot |
|---|---|
gL |
the whole trace → its logs (request grain) |
gl |
the cursor span's workload (pod) → logs |
gm |
the cursor span's workload → a live metrics dashboard |
Inline vitals. As the cursor moves across the waterfall, ax
queries the current span's workload metrics and renders them as
sparklines beside the span — request rate, latency percentiles, CPU,
memory. Which metrics appear is driven by a metrics catalog that maps
OpenTelemetry and Prometheus names to a query. The catalog is
extensible, and :catalog bootstrap generates entries from the metrics
found on the current trace to expand it with application specific
metrics.
For the full design — the reach graph, field dictionary, and query
builders — see docs/otel-corelation.md and
the catalog reference in docs/catalog.md.
Dashboards
:dash ls opens a searchable picker over every dashboard in your
workspace. Pick one and you land in a grid view; the editor binds to
the focused tile, so navigating with Tab / hjkl swaps which query
you're editing. Press Enter on a tile to zoom into it.
Edits save back to Axiom. Change a query, move tiles with m/s
(auto-shove cascades neighbours; shrinking pulls lower tiles up) or
:tile mv! / :tile size!, then :w (which refuses if someone else
bumped the version) or :w! to overwrite. :wq waits for the async
save to land before quitting.
The dashboard pane is vim-flavoured at the tile level: y / x / p
yank, cut, and paste tiles (block shape preserved); u is a one-level
undo; a adds a tile; d deletes with confirm. Counts work (3y,
2x).
Installing
Install the latest from source with Cargo:
cargo install --git https://github.com/axiomhq/ax
Or clone and build from a local checkout:
git clone https://github.com/axiomhq/ax cd ax cargo install --path .
Rust 1.85 or newer is required.
Configuring
ax uses the same ~/.axiom.toml config file as the official
Axiom CLI, so if you've already
authenticated there, you're done.
If you don't have one yet:
active_deployments = "prod" [deployments.prod] url = "https://api.axiom.co" token = "xaat-..." org_id = "..." # Which dataset each signal queries. traces-dataset = "traces-prod" logs-dataset = "logs-prod" metrics-dataset = "metrics-prod"
active_deployments is optional when you only have one entry. To pick
a different deployment for a single launch without editing the file,
pass --deployment NAME (or -d NAME); the flag overrides
active_deployments for that session only.
The <signal>-dataset keys are the only source for which dataset each
signal queries — ax trace, the gl/gL/gm pivots, and the vitals
panel all read them. Edit them from inside ax with :deployment set traces=… logs=… metrics=…; :dep reports the current values.
Running
ax opens an empty editor; your last query comes back from the cache.
To open a file:
To jump straight into a resource, use a subcommand (names may be
abbreviated to any unambiguous prefix, e.g. ax tr / ax da):
ax dashboard <dashboard-uid> ax trace <trace-id>
The trace dataset is the active deployment's traces-dataset; the
global -d/--deployment flag selects the deployment for either
subcommand.
If your MPL declares parameters (param $host: string;) you can supply
values from the command line:
ax -p host=db-01 -p region=us-east
--help prints the full list; --version prints the build version.
Querying
Type MPL, hit Enter, see the chart. Use : for commands (:w to save
the file, :q to quit, :open <uid> to load a dashboard). Use ? for
the full key reference at any time.
The chart kind is picked by a comment at the top of the buffer:
Change line to bar, area, scatter, pie, heatmap, table,
top_list, statistic, log_stream, monitor_list, note, or
spacer to switch chart kinds without touching the query.
A second pragma sets the display unit, which drives axis labels and statistic readouts:
// @viz line
// @unit MiBy/s
The value is a UCUM expression. Storage,
throughput, time, frequency, and SI engineering units scale
automatically by magnitude — 1500000 By/s renders as 1.43 MiB/s,
1500 W as 1.50 kW. Percent (%) and OTEL-style annotations
({request}) render verbatim, and ISO 4217 currency codes (EUR,
USD, …) render with the currency symbol (€1234.50). The pragma
updates live as you type — no need to rerun the query to switch the
axis from By to MiB.
When several sources supply a unit, the resolution order is:
MetricInfo.unit from the metrics-info endpoint, then the
otel.metric.unit tag on a series, then the // @unit pragma.
Time range
:time opens a preset menu (last 5 minutes, last hour, today,
yesterday, …) or a calendar for custom ranges. The range applies to
whichever query or dashboard is in front of you.
Parameters
If your query has param $host: string; at the top, the param panel on
the right shows it; press i in the panel to fill in a value, or set
it from the command line with :p host=db-01. The same panel clears a
value (x) or wipes everything (:p!).
Keys
Full reference: docs/keys.md — the same file the
in-app ? renders. The keymap is vim-flavoured: hjkl, gg/G,
dd/yy/p, : for commands, visual mode, operators on text
objects, the usual.
A few things to know up front:
:qis the only quit. There's no bareqshortcut anywhere.Escalways closes the current thing — an overlay, a picker, a zoomed-in chart back to the grid, or a sidebar pane back to the editor.- Ex-command completion is fuzzy:
:dl<Tab>finds:dash ls,:tm<Tab>finds:time. Plain prefix matches still come first.
Where state lives
Datasets, metric lists, dashboard listings, and the last query you
edited are cached under $XDG_CACHE_HOME/ax/ (or the platform
equivalent). Deleting the directory resets the app; nothing on the
Axiom server is affected.
Limitations
APL queries inside dashboards are shown but not executed — only MPL tiles fetch live data.
