Grafana
Goal: Build a Grafana dashboard from a warm query.
Grafana reads a warm query with a JSON data source: a GET to the endpoint with a bearer token. OpenX ships no Grafana plugin. What follows is the OpenX side, which the code settles, and the Grafana side as it usually looks. Plugin menus change between versions, so check the names in Grafana itself.
Before you start
- A Grafana instance, self-hosted or cloud, with a "JSON API" data source plugin installed (search for "JSON API" in Grafana's plugin catalog). Any plugin that reads JSON over HTTP and lets you set a header works the same way.
- A warm query that is saved or accepted. It is live as soon as it is saved or its proposal is accepted.
- A token from APIs -> API Keys, up to 90 days. Any right will do: a team key's route right is not checked today (see Call the API from your app). A team key works in Team and Hybrid mode, and is turned away in App Identity mode (see Call the API from your app).
1. Add the data source
In Grafana, open Connections (older versions: Configuration) -> Data sources -> Add data source, and pick the "JSON API" data source.
| Setting | Value |
|---|---|
| Name | Anything you will recognise, for example OpenX |
| URL | https://openx.fathym.com/ox-api/warm-queries |
| Header | Authorization with the value Bearer YOUR_TOKEN |
Save and test it. The token goes in the data source's secret header setting, never in a dashboard's JSON.
2. Query a warm query
Add a panel, pick the data source, and give it the path of your warm query: /{lookup}, the last part of the
endpoint the API Manager shows.
3. Read the rows
A warm query answers one JSON object, not a list of records:
| Part | What it holds |
|---|---|
Outputs.<name>.Columns | A list of { Name, Type }, in column order |
Outputs.<name>.Rows | A list of rows. Each row is a list of values in the order of Columns |
Outputs.<name>.Status | Succeeded, Skipped or Failed |
A query saved as plain text has one output, named result. A field's path therefore picks one position out of
every row. If Columns lists Timestamp first and AvgTemp second, the time field is
$.Outputs.result.Rows[*][0] and the value field is $.Outputs.result.Rows[*][1]. Set the first as a time field
and the second as a number.
NOT TESTED HERE
These paths follow the response shape in the code. They were not run against a Grafana plugin while this page was written, so check them in the plugin's own field editor. If the column order of your query changes, the paths change with it.
4. Variables
A dashboard variable can hold a warm query's lookup, and a panel can use it in the path, for example
/${queryVar}. Use it when several warm queries return the same columns in the same order. If their columns
differ, the position-based paths above will not fit them all.
5. Alerts
Create the alert rule in Grafana on the panel's query: pick the condition (for example, value above 80), the notification channel and the evaluation interval. An alert fires from whatever the panel's query returns; OpenX does not know about it. Each evaluation is a run of the warm query.
Good habits
| Habit | Why |
|---|---|
| One warm query per panel | Easier to read and to change |
| Aggregate in the query | The API adds no row cap of its own, so a query answers every row the engine returns |
| Set a sensible refresh | Each refresh and each alert evaluation runs the query; faster than your data arrives only adds load |
| Give the dashboard its own key | You can revoke it without touching anyone else's |
| Renew keys before they expire | A key lives at most 90 days; a dashboard and its alerts stop working when it does |
When it does not work
| What you see | What to check |
|---|---|
| The data source test fails | The URL, and that the header is exactly Authorization: Bearer .... The token may have expired |
| The panel is empty | Run the query in the API Manager (Try it) first, then check the field paths |
| An error in App Identity mode | Team keys are turned away there. See Secure your workspace API |
Every refusal the API can give is in API refusals.
Next steps
- The same query in a report -> Power BI
- Other ways to call it -> APIs
- Connect an AI instead -> Bring Any AI