axonpush
Concepts

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 events API): add the key under the event’s attributes map.
  • 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/latency and /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.