Altinity / Altinity/altinity-sql-browser
Add FlameGraph panel for hierarchical profiling results
Nobody has claimed this yet.
- Dominant language
- TypeScript
- Stars
- 8
- Forks
- 2
- Avg merge
- 1h 34m
- Merged PRs (30d)
- 6
Description
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:
- https://grafana.com/docs/grafana/latest/visualizations/panels-visualizations/visualizations/flame-graph/
- https://github.com/grafana/grafana/tree/main/packages/grafana-flamegraph
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:
- https://superset.apache.org/docs/configuration/visualization-plugins/
- https://github.com/apache/superset/blob/master/superset-frontend/src/visualizations/presets/MainPreset.ts
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:
- resolves configured column names;
- validates every row and depth transition;
- constructs the nested hierarchy expected by
d3-flame-graph; - preserves inclusive and self values separately;
- handles or explicitly rejects multiple roots;
- produces deterministic diagnostics with result-row paths;
- 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
coloris 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-graphversion, license, dependency tree, and production bundle-size impact. - No React, Grafana UI packages, full
d3bundle, 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
- Pure Grafana-compatible flat-row parser, validator, and nested-tree adapter.
- Small
d3-flame-graphprototype with bundle/performance/lifecycle measurements. - Schema/type and panel-registry integration.
- Panel lifecycle wrapper, tooltip, zoom, reset, and resize integration.
- Search plus SQL Browser-owned keyboard accessibility.
- Dashboard lifecycle, truncation, teardown, and cross-browser tests.
- Add a documented ClickHouse profiling query example after validating it against supported server versions.
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start by locating the Query Spec schema and generated types, panel registry and picker, resolver, normalization, validation, and shared panel lifecycle mentioned in the issue. Prototype the pure flat-row adapter first, then run the repository's unit and browser tests; done means the full acceptance checklist passes, including accessibility, bounded rendering, teardown, and bundle review.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- clickhouse, d3js, typescript
- Domain
- databases, frontend
- Issue type
- Feature
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Quiet
- Clarity
- Mostly clear
- Newbie friendliness
- 28/100