HarperFast / HarperFast/harper

recordAnalytics: support arbitrary key/value dimensions

Open
#565 0 comments 0 reactions 0 assignees View on GitHub
area:metrics enhancement from-jira
Dominant language
JavaScript
Stars
89
Forks
10
Avg merge
2d 6h
Merged PRs (30d)
200

Description

`server.recordAnalytics` currently accepts only three fixed positional dimensions (`path`, `method`, `type`), which forces consumers to encode unrelated dimensions into those slots or split a metric into multiple metrics. The PXG team has asked for a custom-dimensions API.

## Desired API

Additive to the current signature (existing 3-positional form remains supported for back-compat):

```ts
recordAnalytics(value: number | boolean, metric: string, dimensions?: Record): void;
```

Example:
```ts
recordAnalytics(1000, 'response_time', { device_type: 'mobile', status_code: 200 });
```

## Implementation notes

- Current impl ([resources/analytics/write.ts:729](resources/analytics/write.ts)) builds the aggregation key by concatenating `metric-path-method-type`. With variable dimensions, the key needs a stable canonicalization (sorted keys, joined). Cardinality of the dimension set affects memory in `activeActions`.
- Downstream consumers (the analytics report payload, listeners via `addAnalyticsListener`, and storage in the `analytics` table) need to surface custom dimensions — likely as a nested object rather than the current flat fields.
- Existing `path` / `method` / `type` callers and dashboards should continue to work unchanged.

## Acceptance criteria

- New dimensions-object form is supported alongside the positional form.
- Aggregation correctly groups records sharing the same `(metric, dimensions)` tuple.
- Reported analytics include custom dimensions in a structured way that the metrics exporter / Grafana plugin can consume.
- Document the new signature; deprecate the positional form in docs (without removing).

## Open design questions (keeps this Not Ready)

- Cardinality guardrails — recommend bounded values (status code, device type) and warn against unbounded ones (user IDs). Should we enforce a per-metric dimension allowlist or a cardinality cap at recording time? Without guardrails, customer misuse could blow up memory in `activeActions` and storage size.
- How should custom dimensions surface in the existing Prometheus exporter and Grafana plugin? Mapping a variable-cardinality record onto Prometheus labels requires a registration step.
- Naming / collision rules with the reserved `path` / `method` / `type` keys.

---

Tracked in Jira: [CORE-3075](https://harperdb.atlassian.net/browse/CORE-3075)

🤖 Filed by Claude on behalf of Kris.

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.