Custom dimensions
Every attribute you stamp on a span or event becomes a queryable dimension. How axonpush discovers them, how to slice by them, and how to name them so they stay useful.
axonpush preserves every attribute on a span or event in the one
events table — there is no allowlist. That means the
dimensions you can analyse by are not a fixed set (model, provider, status); they
are whatever your app chooses to stamp. Add a participant_role, tenant or
plan attribute and you can immediately break down, trend and filter your traffic
by your own business, not just by infrastructure.
Discovery
Raw attribute capture is only useful if you can find out what exists. As events arrive, axonpush records the distinct attribute keys (and a bounded set of their values) an organisation emits into a lightweight catalog, so the dashboard and an MCP client can list the available dimensions before querying them:
GET /analytics/dimensions— the custom dimension keys your app emits.GET /analytics/dimensions/values?key=<key>— the observed values for one key.
The catalog is populated from live telemetry, so a dimension appears once events carrying it have arrived. Stamping a new attribute takes effect for new traffic, not retroactively.
Stamping attributes
axonpush turns any attribute into a dimension, so the mechanism is just whatever your stack already uses to attach one:
- OpenTelemetry (any language, including the gateway path):
span.set_attribute("participant_role", role)on the current span. - Direct event publish (the
eventsAPI): add the key under the event’sattributesmap. - Structured logging (logging, loguru, structlog, Pino, Winston): add the key as a structured field — it lands in the event’s attributes.
Slicing by a dimension
Once a key exists, every analytics read can group or filter by it:
- Break down by a custom dimension:
GET /analytics/breakdown?dimension=tag&tagKey=participant_role - Filter any analytics read to one value — works on
/analytics/timeseries,/analytics/latencyand/analytics/breakdown:?filterTagKey=participant_role&filterTagValue=candidate
So “how is participant_role=candidate traffic trending, and how slow is it?” is a
timeseries plus a latency read with the same two filter params.
Naming guidance
Use stable, low-cardinality keys and values. axonpush drops id-shaped values (UUIDs, long hex or number runs) and very long strings from the dimension catalog: a value that is unique on every request is a useless facet and would bloat the catalog. Put per-request identifiers in the event payload, not in an attribute you intend to analyse by.
Related
- Usage & dashboards, the explorer and boards built on these
- Events model, where attributes are stored
- Analytics API
Events model
One append-only events table is the source of truth. How an event is shaped, how events group into a trace, what gets spilled to S3, and how retention ages data out.
Authentication
Two planes of auth, Better Auth JWTs for the dashboard and MCP, and ak_ API keys plus pt_ public ingest tokens for programmatic access. What each is for, and how the Go API verifies them.