Skip to content

di.grafana module#105

Open
Olly99999 wants to merge 1 commit into
DataIntellectTech:mainfrom
Olly99999:di.grafana-pr
Open

di.grafana module#105
Olly99999 wants to merge 1 commit into
DataIntellectTech:mainfrom
Olly99999:di.grafana-pr

Conversation

@Olly99999

Copy link
Copy Markdown
Contributor
image

@Olly99999

Olly99999 commented Jun 18, 2026

Copy link
Copy Markdown
Contributor Author

Summary

Extracts the .grafana namespace from TorQ's grafana.q into a standalone kdb-x module: di.grafana. The module turns a kdb+ process into a Grafana SimPod JSON datasource: it installs HTTP handlers that answer Grafana's /search, /query and connection-test requests with the JSON the plugin expects, serving the process's tables as timeseries and table panels. It satisfies the di.* module contract: dependency injection via init, a clean exported API, and no hard dependencies beyond an injected logger.

Background

TorQ's grafana.q implements the Grafana JSON-datasource adaptor as a .grafana namespace that hooks .z.pp/.z.ph through TorQ's .dotz handler manager. This PR is part of the broader TorQ → kdb-x modularisation effort: make each functional area independently loadable, testable, and injectable, removing the dependency on TorQ's global process framework.

Changes

New files

File Description
di/grafana/grafana.q Core implementation — init, getconfig, the .z.pp/.z.ph wrappers, and the search/query request builders
di/grafana/init.q Module entry point — loads grafana.q and declares the export list
di/grafana/test.csv k4unit test suite (32 tests)
di/grafana/grafana.md Module README

Differences from TorQ original

Aspect TorQ .grafana di.grafana
Handlers .dotz.set / .dotz.getcommand (TorQ handler manager) init closure-wraps .z.pp/.z.ph directly, preserving any pre-existing handler so non-Grafana traffic falls through untouched. Follows the di.timer precedent (.z.ts); no di.handlers module exists yet to inject. Verified by a fall-through test.
Logging None Required injected log dependency (info/warn/error, {[ctx;msg]}). Request dispatch trapped; failures logged under the grafana context
Config @[value; .grafana.x ;default] globals Module-local defaults + optional config dict in init (timecol, sym, timebackdate, ticks, del)
Global state / namespace \d .grafana Flat module namespace; mutable state on .z.m/.z.M
Dependency validation N/A init validates a non-null log dep and errors with a di.grafana-prefixed message if absent
Module contract None kdb-x use singleton, init[deps] pattern, export: list

Exported API

grafana:use`di.grafana

grafana.init[deps]      / wire dependencies + config, install handlers; required before use
grafana.getconfig[]     / return the currently active configuration dict

Everything else is driven by inbound Grafana HTTP requests via the installed handlers, so it is intentionally not exported.

deps forms:

grafana.init[enlist[`log]!enlist logdep]              / logger only, default config
grafana.init[`log`config!(logdep;`ticks!500)]         / logger + config overrides

Query target syntax

/search emits encoded metric strings that /query parses back; del (default .) separates the arguments:

Target Meaning
t.<table> table panel, whole table
t.<table>.<sym> table panel filtered to one sym
g.<table> graph, one series per numeric column
g.<table>.<col> graph, one series per sym for a column
o.<table>... "other" panels (stat/gauge)
f.... target is a function call rather than a table

Test coverage

Run via k4unit: k4unit.moduletest `di.grafana

Area Tests
Export surface only init + getconfig exported
init — dependency validation rejects :: and a null log dep
init — wiring wired flag set; handlers installed
Config defaults applied; override takes; getconfig reflects it
Parsing helpers isfunc / istab / istype / prefix
Data fetch finddistinctsyms, memvals, catchvals
/query table tbfunc returns the columns/rows/table schema
/query timeseries tsfunc returns target/datapoints numeric series
Handler routing /search POST + GET test-connection via live handlers; non-Grafana POST falls through to the pre-existing handler

Total: 32 tests, all passing.

Notes

  • di.grafana has no hard module dependencies — only the injected log dict is required.
  • di.log satisfies the log contract out of the box:
logdep:`info`warn`error!(log.info;log.warn;log.error)
  • The handler wrapper preserves any pre-existing .z.pp/.z.ph, so adding the module to a process that already serves HTTP does not break existing endpoints.
  • The /annotations endpoint returns a "not yet implemented" marker, matching the TorQ original.

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