Altinity / Altinity/altinity-sql-browser

Add FlameGraph panel for hierarchical profiling results

Aperta
#389 0 commenti 0 reazioni 0 assegnatari Vedi su GitHub

Nessuno ha ancora preso questa issue.

cool feature enhancement
Lingua principale
TypeScript
Stelle
8
Fork
2
Merge medio
1h 34m
PR unite (30g)
6

Descrizione

Summary

Add a first-class FlameGraph panel for hierarchical profiling results, suitable for ClickHouse system.trace_log queries and other stack/call-tree datasets.

Adopt Grafana's flat nested-set result contract and use d3-flame-graph as the preferred implementation path, behind a SQL Browser-owned adapter and panel lifecycle wrapper. Do not embed Grafana's React component or replace Chart.js solely for this feature.

Research

Grafana

Grafana has a built-in Flame graph visualization and an independently published @grafana/flamegraph component.

Grafana's data contract is a flat table in depth-first order with these fields:

Field Meaning
level Zero-based stack depth
value Inclusive sample count or duration
self Exclusive sample count or duration
label Frame/function name
color Optional explicit color

This is attractive for SQL results because the browser does not need a nested JSON object. Rows can stream as an ordinary table and be validated deterministically.

Grafana supports:

  • flame-graph and table views;
  • zooming into a frame;
  • text search/highlighting;
  • tooltips with inclusive and self values;
  • optional sandwich-style/profile navigation in profiling integrations.

Sources:

The published Grafana component is not a suitable direct dependency for this project. It pulls in React, Grafana UI/data packages, Emotion, lodash, and other runtime dependencies. SQL Browser is a vanilla, single-file application with no third-party network requests, so importing that package would be disproportionate.

Apache Superset

Apache Superset does not currently register a built-in FlameGraph visualization in its main visualization preset. Its built-in hierarchical alternatives include Tree, Sunburst, Treemap, Graph, and Sankey, mostly through ECharts.

Superset's architecture allows a FlameGraph to be added as a custom visualization plugin, but it is not an out-of-the-box chart type.

Sources:

d3-flame-graph

d3-flame-graph is the preferred renderer to prototype before writing a custom SVG implementation.

It is a purpose-built Apache-2.0 FlameGraph component with:

  • SVG rendering;
  • click-to-zoom and reset;
  • search and match highlighting;
  • tooltips;
  • inverted/icicle orientation;
  • self-value support;
  • custom color mapping;
  • an explicit destroy() lifecycle;
  • ESM output and modular D3 dependencies.

Source:

Its input is a nested tree rather than Grafana's flat rows:

{
  "name": "root",
  "value": 100,
  "children": [
    {
      "name": "functionA",
      "value": 70
    }
  ]
}

SQL Browser therefore owns a pure, tested adapter from the flat result contract into the nested d3-flame-graph hierarchy. The adapter remains independent of the renderer and can support a native implementation later.

The dependency does not remove SQL Browser's responsibility for:

  • schema and hierarchy validation;
  • keyboard focus and navigation;
  • accessible frame labels;
  • theme integration;
  • result-size limits;
  • resize and teardown integration;
  • safe tooltip content;
  • bundle-size review.

Do not import the full monolithic d3 package. Use only the dependency graph required by d3-flame-graph and record the resulting production bundle increase.

Implications for SQL Browser

The current application uses Chart.js for ordinary bar/line/area/pie charts and has a closed panel configuration union. Flame graphs are not a natural Chart.js chart type. Implement this as a dedicated panel arm rather than forcing it into the existing chart-family abstraction or replacing Chart.js.

Proposed v1 design

Add an explicit panel configuration:

{
  "panel": {
    "cfg": {
      "type": "flamegraph",
      "level": "level",
      "value": "value",
      "self": "self",
      "label": "label",
      "color": "color"
    }
  }
}

color should be optional. Role fields should use column names, not indexes, matching the Logs panel's resilience to reordered result schemas.

Required result contract

Rows must be in depth-first traversal order.

Required columns:

  • level: non-negative integer;
  • value: finite non-negative number;
  • self: finite non-negative number;
  • label: string.

Optional:

  • color: CSS-compatible color string.

Validation rules:

  • first row must start at level 0;
  • depth may increase by at most one between adjacent rows;
  • self <= value;
  • child spans must fit within their parent's inclusive value;
  • malformed input produces a panel diagnostic and falls back safely rather than throwing.

The exact sibling-width accounting should follow Grafana's nested-set transform semantics so Grafana-compatible SQL output renders equivalently.

Flat-row adapter

Implement a pure transform that:

  1. resolves configured column names;
  2. validates every row and depth transition;
  3. constructs the nested hierarchy expected by d3-flame-graph;
  4. preserves inclusive and self values separately;
  5. handles or explicitly rejects multiple roots;
  6. produces deterministic diagnostics with result-row paths;
  7. never mutates the result rows.

The renderer must consume only the validated adapter output, never raw query rows.

Rendering recommendation

Use d3-flame-graph for the v1 renderer, wrapped by the existing panel registry and lifecycle:

  • mount into a panel-owned host;
  • map validated tree nodes into the library's data shape;
  • provide SQL Browser-owned tooltip formatting;
  • expose click-to-zoom and reset/breadcrumb controls;
  • wire text search and matching-frame emphasis;
  • derive a deterministic theme-aware palette when color is absent;
  • update dimensions through the existing panel resize lifecycle;
  • call destroy() and remove all wrapper listeners/observers on repaint or teardown.

Add an accessibility wrapper because mouse interaction alone is insufficient:

  • keyboard-focusable visible frames or an equivalent navigable frame list;
  • Enter/Space to zoom;
  • Escape or a dedicated control to reset one level;
  • accessible labels containing frame name, inclusive value, self value, and percentage;
  • visible focus indication in light and dark themes.

A native SVG renderer remains the fallback if the prototype fails the bundle, lifecycle, performance, accessibility, or styling gates.

Prototype decision gate

Before completing full integration, create a focused prototype and record:

  • minified and compressed production bundle increase;
  • frame-count performance at representative sizes;
  • responsiveness inside Workbench and Dashboard tiles;
  • cleanup behavior across repeated renders;
  • keyboard/accessibility gaps and wrapper cost;
  • theme and print/export compatibility.

Proceed with d3-flame-graph unless one of these is materially unacceptable. Do not replace Chart.js as part of this issue.

UX scope

V1 should include:

  • FlameGraph entry in the panel picker;
  • explicit column-role controls;
  • zoom into frame and reset/breadcrumb navigation;
  • text search/highlighting;
  • tooltip showing label, inclusive value, self value, and percentage of the current root;
  • empty, loading, invalid-schema, and result-too-large states;
  • Workbench and Dashboard rendering through the shared panel registry;
  • read-only Dashboard behavior without write-back callbacks.

Out of scope for v1:

  • differential flame graphs;
  • left-heavy/sandwich comparison;
  • profile backend integration or Pyroscope API support;
  • automatic querying of system.trace_log;
  • automatic FlameGraph detection. It should be an explicit panel type initially;
  • replacement of Chart.js for existing chart panels.

Performance and safety

Define and test a maximum rendered frame count. Suggested initial behavior:

  • render up to a documented cap;
  • display a clear truncation/aggregation message above the cap;
  • avoid one SQL Browser event listener per rectangle where possible;
  • destroy all library, tooltip, search, and resize state through the panel lifecycle;
  • never evaluate labels or color strings as HTML;
  • sanitize or reject invalid explicit colors;
  • do not expose raw result values through unsafe DOM insertion.

Acceptance criteria

  • Query Spec schema and generated types include panel.cfg.type = "flamegraph" with name-based roles.
  • The panel registry, picker, resolver, cloning, normalization, validation, and fallback paths recognize the new type.
  • A pure adapter converts valid Grafana-style flat nested-set rows into the nested renderer model.
  • The adapter reports deterministic diagnostics for missing, renamed, malformed, negative, non-finite, or structurally invalid data without throwing.
  • A valid result renders the expected hierarchy through d3-flame-graph.
  • Click zoom, reset/breadcrumb navigation, search highlighting, and tooltips work in Workbench and Dashboard.
  • Multiple roots are either supported explicitly or rejected with a clear diagnostic; choose and document one behavior.
  • SQL Browser adds keyboard navigation, accessible frame labels, and visible focus behavior beyond the library defaults.
  • The renderer is usable in light and dark themes.
  • Rendering is bounded for large profiles and cleanup leaves no listeners, observers, SVG state, or tooltips behind.
  • Repeated repaint and resize cycles do not duplicate controls or event handlers.
  • Unit tests cover transform, validation, role resolution, lifecycle, and renderer integration at repository coverage thresholds.
  • Browser tests cover zoom, search, tooltip, keyboard operation, Dashboard rendering, teardown, and resize on Chromium, Firefox, and WebKit.
  • The PR records the exact d3-flame-graph version, license, dependency tree, and production bundle-size impact.
  • No React, Grafana UI packages, full d3 bundle, ECharts, or replacement chart framework is added.
  • If the dependency fails the prototype decision gate, the PR documents the result before switching to a native SVG renderer.

Suggested implementation sequence

  1. Pure Grafana-compatible flat-row parser, validator, and nested-tree adapter.
  2. Small d3-flame-graph prototype with bundle/performance/lifecycle measurements.
  3. Schema/type and panel-registry integration.
  4. Panel lifecycle wrapper, tooltip, zoom, reset, and resize integration.
  5. Search plus SQL Browser-owned keyboard accessibility.
  6. Dashboard lifecycle, truncation, teardown, and cross-browser tests.
  7. Add a documented ClickHouse profiling query example after validating it against supported server versions.

Guida per i contributori

Apri la guida per i contributori

Come iniziare

  1. Leggi tutta la issue e poi la guida ai contributi del progetto.
  2. Commenta sulla issue per dire che te ne occupi tu — evita che due persone facciano lo stesso lavoro.
  3. Fai un fork del repository e lavora su un branch.
  4. Apri una pull request che faccia riferimento al numero della issue.

Direzione di ricerca

Inizia individuando lo schema di Query Spec e i tipi generati, il registro e il selettore dei pannelli, il resolver, la normalizzazione, la validazione e il ciclo di vita condiviso dei pannelli menzionati nell’issue. Prototipa prima il puro adattatore per righe piatte, quindi esegui i test unitari e browser del repository; il lavoro è completato quando viene superata l’intera checklist di accettazione, inclusi accessibilità, rendering vincolato, teardown e revisione del bundle.

Scritto dal modello di indicizzazione a partire dal testo della issue.

Valutazione

Stack tecnologico
clickhouse, d3js, typescript
Ambito
databases, frontend
Tipo di issue
Funzionalità
Difficoltà
5/5
Tempo stimato
Più di una settimana
Stato di attività
Tranquilla
Chiarezza
Abbastanza chiara
Idoneità per principianti
28/100

Ricevi le nuove issue nella tua casella

Un breve riepilogo di issue GitHub adatte ai principianti.