Skip to content

feat(profiling): label-discovery endpoint (POST /profiles/labels)#4

Closed
FrameAutomata wants to merge 2 commits into
mainfrom
feat/profiling-labels-discovery
Closed

feat(profiling): label-discovery endpoint (POST /profiles/labels)#4
FrameAutomata wants to merge 2 commits into
mainfrom
feat/profiling-labels-discovery

Conversation

@FrameAutomata

Copy link
Copy Markdown
Owner

What

Adds POST /api/profiles/labels — given {fromDate, toDate, serviceName, type}, returns a map of allowlisted label key → distinct values pulled from profiling_samples.labels, e.g.:

{ "endpoint": ["/a", "/b"] }

Values are deduplicated, sorted ascending, and filtered by project, service, profile type, and time range. Empty values are excluded, and a key with no values is omitted from the response entirely.

The allowlist currently exposes a single key (endpoint); it's a slice so adding keys later is a one-line change.

Why

The dashboard profiles UI needs to discover which label values exist (e.g. which endpoints were profiled) so it can offer them as flame-graph filters. The labels column and label-based filtering already landed on main; this PR adds the read/discovery side.

How

  • RepositoryDiscoverLabels lives in a build-tag-agnostic file (profile.repository_labels.go); it loops the allowlist and delegates each key to distinctLabelValues, which is implemented per backend: ClickHouse (labels[?], pgch build) and SQLite (json_extract, default build). This mirrors the existing MetricPointRepository.DiscoverTagValues.
  • Controller / routeDiscoverLabels handler follows the sibling GetSeries / GetFlameGraph pattern (validates serviceName/type, 400 otherwise).
  • The SQLite result model is registered once at startup via models.ExtensionModelRegistrations (alongside profileGroupRow) rather than per request.

Testing

  • New profile_labels_test.go (SQLite build): asserts distinct + sorted values, allowlist enforcement (non-allowlisted region excluded), the service/type/time filters, and that a key with only empty values is omitted.
  • Both default (SQLite) and -tags pgch (ClickHouse) builds compile; go vet clean.
  • Manually verified end-to-end against a local SQLite backend: seeded profiling_samples rows → POST /api/profiles/labels returns {"endpoint":["/a","/b"]}.

🤖 Generated with Claude Code

FrameAutomata and others added 2 commits June 24, 2026 15:26
Add POST /profiles/labels returning a map of allowlisted label key to
distinct values from profiling_samples.labels, filtered by service, type,
and time range. The allowlist currently exposes only "endpoint".

The repository method mirrors the existing metric tag discovery
(DiscoverTagValues): one DISTINCT query per allowlisted key. The shared
allowlist loop lives in a build-tag-agnostic file so only the
dialect-specific query is split across the pgch and sqlite builds.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
distinctLabelValues called lit.RegisterModel on every request, writing
lit's unsynchronized global model map while concurrent lit queries read
it — a potential "concurrent map writes" fatal crash under parallel
SQLite-mode requests. Register the result model once in init() via
models.ExtensionModelRegistrations, matching profileGroupRow.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@FrameAutomata

Copy link
Copy Markdown
Owner Author

Opened against the wrong base — superseded by the upstream PR tracewayapp#238.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant