Commit e27ab89a by Jerry Ylilammi Committed by Marcus Efraimsson

Postgres/MySQL/MSSQL: Adds support for region annotations (#20752)

Adds support for region annotations in Postgres, MySQL and 
MSSQL data sources by adding a column named timeend to 
annotation query.

Co-Authored-By: Diana Payton <52059945+oddlittlebird@users.noreply.github.com>

Closes #20918
Ref #10589
parent f65da93d
......@@ -4,11 +4,37 @@
{
"builtIn": 1,
"datasource": "-- Grafana --",
"enable": true,
"enable": false,
"hide": true,
"iconColor": "rgba(0, 211, 255, 1)",
"limit": 100,
"name": "Annotations & Alerts",
"showIn": 0,
"type": "dashboard"
},
{
"datasource": "gdev-mssql",
"enable": false,
"hide": false,
"iconColor": "rgba(0, 211, 255, 1)",
"limit": 100,
"name": "Single",
"rawQuery": "SELECT TOP 1\n createdAt as time,\n 'single' as text,\n hostname as tags\nFROM\n grafana_metric\nWHERE\n $__timeFilter(createdAt)\nORDER BY time\n",
"showIn": 0,
"tags": [],
"type": "tags"
},
{
"datasource": "gdev-mssql",
"enable": false,
"hide": false,
"iconColor": "rgba(0, 211, 255, 1)",
"limit": 100,
"name": "Region",
"rawQuery": "SELECT TOP 1\n DATEADD(MINUTE, 1, createdAt) as time,\n DATEADD(MINUTE, 6, createdAt) as timeend,\n 'region' as text,\n hostname as tags\nFROM\n grafana_metric\nWHERE\n $__timeFilter(createdAt)\nORDER BY time",
"showIn": 0,
"tags": [],
"type": "tags"
}
]
},
......@@ -16,7 +42,7 @@
"editable": true,
"gnetId": null,
"graphTooltip": 0,
"iteration": 1532618661457,
"iteration": 1576251075020,
"links": [],
"panels": [
{
......@@ -28,12 +54,14 @@
"dashes": false,
"datasource": "gdev-mssql",
"fill": 2,
"fillGradient": 0,
"gridPos": {
"h": 9,
"w": 12,
"x": 0,
"y": 0
},
"hiddenSeries": false,
"id": 2,
"legend": {
"avg": false,
......@@ -48,6 +76,9 @@
"linewidth": 2,
"links": [],
"nullPointMode": "null",
"options": {
"dataLinks": []
},
"percentage": false,
"pointradius": 5,
"points": false,
......@@ -79,6 +110,7 @@
],
"thresholds": [],
"timeFrom": null,
"timeRegions": [],
"timeShift": null,
"title": "Average logins / $summarize",
"tooltip": {
......@@ -125,12 +157,14 @@
"dashes": false,
"datasource": "gdev-mssql",
"fill": 2,
"fillGradient": 0,
"gridPos": {
"h": 18,
"w": 12,
"x": 12,
"y": 0
},
"hiddenSeries": false,
"id": 8,
"legend": {
"avg": false,
......@@ -145,6 +179,9 @@
"linewidth": 2,
"links": [],
"nullPointMode": "null",
"options": {
"dataLinks": []
},
"percentage": false,
"pointradius": 5,
"points": false,
......@@ -169,6 +206,7 @@
],
"thresholds": [],
"timeFrom": null,
"timeRegions": [],
"timeShift": null,
"title": "Average payments started/ended / $summarize",
"tooltip": {
......@@ -214,12 +252,14 @@
"dashes": false,
"datasource": "gdev-mssql",
"fill": 2,
"fillGradient": 0,
"gridPos": {
"h": 9,
"w": 12,
"x": 0,
"y": 9
},
"hiddenSeries": false,
"id": 6,
"legend": {
"avg": false,
......@@ -234,6 +274,9 @@
"linewidth": 2,
"links": [],
"nullPointMode": "null",
"options": {
"dataLinks": []
},
"percentage": false,
"pointradius": 5,
"points": false,
......@@ -252,6 +295,7 @@
],
"thresholds": [],
"timeFrom": null,
"timeRegions": [],
"timeShift": null,
"title": "Max CPU / $summarize",
"tooltip": {
......@@ -302,6 +346,7 @@
},
"id": 4,
"links": [],
"options": {},
"pageSize": null,
"scroll": true,
"showHeader": true,
......@@ -340,15 +385,19 @@
"type": "table"
}
],
"schemaVersion": 16,
"schemaVersion": 21,
"style": "dark",
"tags": ["gdev", "mssql", "datasource-test"],
"templating": {
"list": [
{
"allValue": null,
"current": {},
"current": {
"text": "Africa",
"value": "Africa"
},
"datasource": "gdev-mssql",
"definition": "",
"hide": 0,
"includeAll": false,
"label": "Datacenter",
......@@ -368,8 +417,13 @@
},
{
"allValue": null,
"current": {},
"current": {
"selected": false,
"text": "All",
"value": "$__all"
},
"datasource": "gdev-mssql",
"definition": "",
"hide": 0,
"includeAll": true,
"label": "Hostname",
......@@ -392,6 +446,7 @@
"auto_count": 30,
"auto_min": "10s",
"current": {
"selected": false,
"text": "1m",
"value": "1m"
},
......@@ -488,5 +543,5 @@
"timezone": "",
"title": "Datasource tests - MSSQL",
"uid": "86Js1xRmk",
"version": 1
"version": 2
}
......@@ -4,11 +4,35 @@
{
"builtIn": 1,
"datasource": "-- Grafana --",
"enable": true,
"enable": false,
"hide": true,
"iconColor": "rgba(0, 211, 255, 1)",
"name": "Annotations & Alerts",
"type": "dashboard"
},
{
"datasource": "gdev-mysql",
"enable": false,
"hide": false,
"iconColor": "rgba(0, 211, 255, 1)",
"limit": 100,
"name": "Single",
"rawQuery": "SELECT\n createdAt as time,\n 'single' as text,\n hostname as tags\nFROM\n grafana_metric\nWHERE\n $__timeFilter(createdAt)\nORDER BY time\nLIMIT 1\n",
"showIn": 0,
"tags": [],
"type": "tags"
},
{
"datasource": "gdev-mysql",
"enable": false,
"hide": false,
"iconColor": "rgba(0, 211, 255, 1)",
"limit": 100,
"name": "Region",
"rawQuery": "SELECT\n ADDTIME(createdAt, '00:01:00') as time,\n ADDTIME(createdAt, '00:06:00') as timeend,\n 'region' as text,\n hostname as tags\nFROM\n grafana_metric\nWHERE\n $__timeFilter(createdAt)\nORDER BY time\nLIMIT 1\n",
"showIn": 0,
"tags": [],
"type": "tags"
}
]
},
......@@ -16,7 +40,7 @@
"editable": true,
"gnetId": null,
"graphTooltip": 0,
"iteration": 1532620738041,
"iteration": 1576250298312,
"links": [],
"panels": [
{
......@@ -28,12 +52,14 @@
"dashes": false,
"datasource": "gdev-mysql",
"fill": 2,
"fillGradient": 0,
"gridPos": {
"h": 9,
"w": 12,
"x": 0,
"y": 0
},
"hiddenSeries": false,
"id": 2,
"legend": {
"avg": false,
......@@ -48,6 +74,9 @@
"linewidth": 2,
"links": [],
"nullPointMode": "null",
"options": {
"dataLinks": []
},
"percentage": false,
"pointradius": 5,
"points": false,
......@@ -81,6 +110,7 @@
],
"thresholds": [],
"timeFrom": null,
"timeRegions": [],
"timeShift": null,
"title": "Average logins / $summarize",
"tooltip": {
......@@ -126,12 +156,14 @@
"dashes": false,
"datasource": "gdev-mysql",
"fill": 2,
"fillGradient": 0,
"gridPos": {
"h": 18,
"w": 12,
"x": 12,
"y": 0
},
"hiddenSeries": false,
"id": 4,
"legend": {
"avg": false,
......@@ -146,6 +178,9 @@
"linewidth": 2,
"links": [],
"nullPointMode": "null",
"options": {
"dataLinks": []
},
"percentage": false,
"pointradius": 5,
"points": false,
......@@ -171,6 +206,7 @@
],
"thresholds": [],
"timeFrom": null,
"timeRegions": [],
"timeShift": null,
"title": "Average payments started/ended / $summarize",
"tooltip": {
......@@ -216,12 +252,14 @@
"dashes": false,
"datasource": "gdev-mysql",
"fill": 2,
"fillGradient": 0,
"gridPos": {
"h": 9,
"w": 12,
"x": 0,
"y": 9
},
"hiddenSeries": false,
"id": 3,
"legend": {
"avg": false,
......@@ -236,6 +274,9 @@
"linewidth": 2,
"links": [],
"nullPointMode": "null",
"options": {
"dataLinks": []
},
"percentage": false,
"pointradius": 5,
"points": false,
......@@ -255,6 +296,7 @@
],
"thresholds": [],
"timeFrom": null,
"timeRegions": [],
"timeShift": null,
"title": "Max CPU / $summarize",
"tooltip": {
......@@ -305,6 +347,7 @@
},
"id": 6,
"links": [],
"options": {},
"pageSize": null,
"scroll": true,
"showHeader": true,
......@@ -346,7 +389,8 @@
"type": "table"
}
],
"schemaVersion": 16,
"refresh": false,
"schemaVersion": 21,
"style": "dark",
"tags": ["gdev", "mysql", "datasource-tags"],
"templating": {
......@@ -358,6 +402,7 @@
"value": "America"
},
"datasource": "gdev-mysql",
"definition": "",
"hide": 0,
"includeAll": false,
"label": "Datacenter",
......@@ -378,10 +423,12 @@
{
"allValue": null,
"current": {
"selected": false,
"text": "All",
"value": "$__all"
},
"datasource": "gdev-mysql",
"definition": "",
"hide": 0,
"includeAll": true,
"label": "Hostname",
......@@ -404,6 +451,7 @@
"auto_count": 5,
"auto_min": "10s",
"current": {
"selected": false,
"text": "1m",
"value": "1m"
},
......@@ -500,5 +548,5 @@
"timezone": "",
"title": "Datasource tests - MySQL",
"uid": "DGsCac3kz",
"version": 8
"version": 2
}
......@@ -4,11 +4,35 @@
{
"builtIn": 1,
"datasource": "-- Grafana --",
"enable": true,
"enable": false,
"hide": true,
"iconColor": "rgba(0, 211, 255, 1)",
"name": "Annotations & Alerts",
"type": "dashboard"
},
{
"datasource": "gdev-postgres",
"enable": false,
"hide": false,
"iconColor": "rgba(0, 211, 255, 1)",
"limit": 100,
"name": "Single",
"rawQuery": "SELECT\n \"createdAt\" as time,\n 'single' as text,\n hostname as tags\nFROM\n grafana_metric\nWHERE\n $__timeFilter(\"createdAt\")\nORDER BY time\nLIMIT 1\n",
"showIn": 0,
"tags": [],
"type": "tags"
},
{
"datasource": "gdev-postgres",
"enable": false,
"hide": false,
"iconColor": "rgba(0, 211, 255, 1)",
"limit": 100,
"name": "Region",
"rawQuery": "SELECT\n \"createdAt\" + (interval '1 minute') as time,\n \"createdAt\" + (6 * interval '1 minute') as timeend,\n 'region' as text,\n hostname as tags\nFROM\n grafana_metric\nWHERE\n $__timeFilter(\"createdAt\")\nORDER BY time\nLIMIT 1\n",
"showIn": 0,
"tags": [],
"type": "tags"
}
]
},
......@@ -16,7 +40,7 @@
"editable": true,
"gnetId": null,
"graphTooltip": 0,
"iteration": 1532620601931,
"iteration": 1576249087264,
"links": [],
"panels": [
{
......@@ -28,12 +52,14 @@
"dashes": false,
"datasource": "gdev-postgres",
"fill": 2,
"fillGradient": 0,
"gridPos": {
"h": 9,
"w": 12,
"x": 0,
"y": 0
},
"hiddenSeries": false,
"id": 2,
"legend": {
"avg": false,
......@@ -48,6 +74,9 @@
"linewidth": 2,
"links": [],
"nullPointMode": "null",
"options": {
"dataLinks": []
},
"percentage": false,
"pointradius": 5,
"points": false,
......@@ -67,20 +96,59 @@
{
"alias": "",
"format": "time_series",
"group": [],
"hide": false,
"metricColumn": "none",
"rawQuery": true,
"rawSql": "SELECT\n $__timeGroup(\"createdAt\",'$summarize'),\n avg(value) as \"value\",\n hostname as \"metric\"\nFROM \n grafana_metric\nWHERE\n $__timeFilter(\"createdAt\") AND\n measurement = 'logins.count' AND\n hostname IN($host)\nGROUP BY time, metric\nORDER BY time",
"refId": "A",
"target": ""
"select": [
[
{
"params": ["value"],
"type": "column"
}
]
],
"target": "",
"timeColumn": "time",
"where": [
{
"name": "$__timeFilter",
"params": [],
"type": "macro"
}
]
},
{
"alias": "",
"format": "time_series",
"group": [],
"metricColumn": "none",
"rawQuery": true,
"rawSql": "SELECT\n $__timeGroup(\"createdAt\",'$summarize'),\n min(value) as \"value\",\n 'total avg' as \"metric\"\nFROM \n grafana_metric\nWHERE\n $__timeFilter(\"createdAt\") AND\n measurement = 'logins.count'\nGROUP BY time\nORDER BY time",
"refId": "B"
"refId": "B",
"select": [
[
{
"params": ["value"],
"type": "column"
}
]
],
"timeColumn": "time",
"where": [
{
"name": "$__timeFilter",
"params": [],
"type": "macro"
}
]
}
],
"thresholds": [],
"timeFrom": null,
"timeRegions": [],
"timeShift": null,
"title": "Average logins / $summarize",
"tooltip": {
......@@ -126,12 +194,14 @@
"dashes": false,
"datasource": "gdev-postgres",
"fill": 2,
"fillGradient": 0,
"gridPos": {
"h": 18,
"w": 12,
"x": 12,
"y": 0
},
"hiddenSeries": false,
"id": 4,
"legend": {
"avg": false,
......@@ -146,6 +216,9 @@
"linewidth": 2,
"links": [],
"nullPointMode": "null",
"options": {
"dataLinks": []
},
"percentage": false,
"pointradius": 5,
"points": false,
......@@ -171,6 +244,7 @@
],
"thresholds": [],
"timeFrom": null,
"timeRegions": [],
"timeShift": null,
"title": "Average payments started/ended / $summarize",
"tooltip": {
......@@ -216,12 +290,14 @@
"dashes": false,
"datasource": "gdev-postgres",
"fill": 2,
"fillGradient": 0,
"gridPos": {
"h": 9,
"w": 12,
"x": 0,
"y": 9
},
"hiddenSeries": false,
"id": 3,
"legend": {
"avg": false,
......@@ -236,6 +312,9 @@
"linewidth": 2,
"links": [],
"nullPointMode": "null",
"options": {
"dataLinks": []
},
"percentage": false,
"pointradius": 5,
"points": false,
......@@ -255,6 +334,7 @@
],
"thresholds": [],
"timeFrom": null,
"timeRegions": [],
"timeShift": null,
"title": "Max CPU / $summarize",
"tooltip": {
......@@ -305,6 +385,7 @@
},
"id": 6,
"links": [],
"options": {},
"pageSize": null,
"scroll": true,
"showHeader": true,
......@@ -345,7 +426,7 @@
"type": "table"
}
],
"schemaVersion": 16,
"schemaVersion": 21,
"style": "dark",
"tags": ["gdev", "postgres", "datasource-test"],
"templating": {
......@@ -357,6 +438,7 @@
"value": "America"
},
"datasource": "gdev-postgres",
"definition": "",
"hide": 0,
"includeAll": false,
"label": "Datacenter",
......@@ -377,10 +459,12 @@
{
"allValue": null,
"current": {
"selected": false,
"text": "All",
"value": "$__all"
},
"datasource": "gdev-postgres",
"definition": "",
"hide": 0,
"includeAll": true,
"label": "Hostname",
......@@ -403,6 +487,7 @@
"auto_count": 5,
"auto_min": "10s",
"current": {
"selected": false,
"text": "1m",
"value": "1m"
},
......@@ -499,5 +584,5 @@
"timezone": "",
"title": "Datasource tests - Postgres",
"uid": "JYola5qzz",
"version": 4
"version": 5
}
......@@ -178,7 +178,7 @@ The resulting table panel:
## Time series queries
If you set `Format as` to `Time series`, for use in Graph panel for example, then the query must have a column named `time` that returns either a sql datetime or any numeric datatype representing Unix epoch in seconds. You may return a column named `metric` that is used as metric name for the value column. Any column except `time` and `metric` is treated as a value column. If you omit the `metric` column, the name of the value column will be the metric name. You may select multiple value columns, each will have its name as metric.
If you set `Format as` to `Time series`, for use in Graph panel for example, then the query must have a column named `time` that returns either a SQL datetime or any numeric datatype representing Unix epoch in seconds. You may return a column named `metric` that is used as metric name for the value column. Any column except `time` and `metric` is treated as a value column. If you omit the `metric` column, the name of the value column will be the metric name. You may select multiple value columns, each will have its name as metric.
If you return multiple value columns and a column named `metric` then this column is used as prefix for the series name (only available in Grafana 5.3+).
Resultsets of time series queries need to be sorted by time.
......@@ -380,7 +380,8 @@ Read more about variable formatting options in the [Variables]({{< relref "../..
Name | Description
------------ | -------------
time | The name of the date/time field. Could be a column with a native sql date/time data type or epoch value.
time | The name of the date/time field. Could be a column with a native SQL date/time data type or epoch value.
timeend | Optional name of the end date/time field. Could be a column with a native SQL date/time data type or epoch value.
text | Event description field.
tags | Optional field name to use for event tags as a comma separated string.
......@@ -410,7 +411,7 @@ WHERE
ORDER BY 1
```
**Example query using time column of native sql date/time data type:**
**Example query using time column of native SQL date/time data type:**
```sql
SELECT
......
......@@ -182,7 +182,7 @@ The resulting table panel:
## Time series queries
If you set `Format as` to `Time series`, for use in Graph panel for example, then the query must return a column named `time` that returns either a sql datetime or any numeric datatype representing Unix epoch.
If you set `Format as` to `Time series`, for use in Graph panel for example, then the query must return a column named `time` that returns either a SQL datetime or any numeric datatype representing Unix epoch.
Any column except `time` and `metric` is treated as a value column.
You may return a column named `metric` that is used as metric name for the value column.
If you return multiple value columns and a column named `metric` then this column is used as prefix for the series name (only available in Grafana 5.3+).
......@@ -350,7 +350,7 @@ WHERE
$__unixEpochFilter(epoch_time)
```
**Example query using time column of native sql date/time data type:**
**Example query using time column of native SQL date/time data type:**
```sql
SELECT
......@@ -365,7 +365,8 @@ WHERE
Name | Description
------------ | -------------
time | The name of the date/time field. Could be a column with a native sql date/time data type or epoch value.
time | The name of the date/time field. Could be a column with a native SQL date/time data type or epoch value.
timeend | Optional name of the end date/time field. Could be a column with a native SQL date/time data type or epoch value.
text | Event description field.
tags | Optional field name to use for event tags as a comma separated string.
......
......@@ -354,7 +354,7 @@ WHERE
$__unixEpochFilter(epoch_time)
```
**Example query using time column of native sql date/time data type:**
**Example query using time column of native SQL date/time data type:**
```sql
SELECT
......@@ -369,7 +369,8 @@ WHERE
Name | Description
------------ | -------------
time | The name of the date/time field. Could be a column with a native sql date/time data type or epoch value.
time | The name of the date/time field. Could be a column with a native SQL date/time data type or epoch value.
timeend | Optional name of the time end field, needs to be date/time data type. If set, then annotations are marked as regions between time and time-end.
text | Event description field.
tags | Optional field name to use for event tags as a comma separated string.
......
......@@ -56,6 +56,8 @@ var NewXormEngine = func(driverName string, connectionString string) (*xorm.Engi
return xorm.NewEngine(driverName, connectionString)
}
const timeEndColumnName = "timeend"
type sqlQueryEndpoint struct {
macroEngine SqlMacroEngine
queryResultTransformer SqlQueryResultTransformer
......@@ -218,6 +220,7 @@ func (e *sqlQueryEndpoint) transformToTable(query *tsdb.Query, rows *core.Rows,
rowCount := 0
timeIndex := -1
timeEndIndex := -1
table := &tsdb.Table{
Columns: make([]tsdb.TableColumn, columnCount),
......@@ -232,6 +235,11 @@ func (e *sqlQueryEndpoint) transformToTable(query *tsdb.Query, rows *core.Rows,
timeIndex = i
break
}
if timeIndex >= 0 && name == timeEndColumnName {
timeEndIndex = i
break
}
}
}
......@@ -250,10 +258,11 @@ func (e *sqlQueryEndpoint) transformToTable(query *tsdb.Query, rows *core.Rows,
return err
}
// converts column named time to unix timestamp in milliseconds
// converts column named time and timeend to unix timestamp in milliseconds
// to make native mssql datetime types and epoch dates work in
// annotation and table queries.
ConvertSqlTimeColumnToEpochMs(values, timeIndex)
ConvertSqlTimeColumnToEpochMs(values, timeEndIndex)
table.Rows = append(table.Rows, values)
}
......
......@@ -18,9 +18,10 @@
<div class="gf-form" ng-show="ctrl.showHelp">
<pre class="gf-form-pre alert alert-info"><h6>Annotation Query Format</h6>
An annotation is an event that is overlaid on top of graphs. The query can have up to three columns per row, the <b>time</b> column is mandatory. Annotation rendering is expensive so it is important to limit the number of rows returned.
An annotation is an event that is overlaid on top of graphs. The query can have up to four columns per row, the <b>time</b> column is mandatory. Annotation rendering is expensive so it is important to limit the number of rows returned.
- column with alias: <b>time</b> for the annotation event time. Use epoch time or any native date data type.
- column with alias: <b>timeend</b> for the annotation event end time. Use epoch time or any native date data type.
- column with alias: <b>text</b> for the annotation text.
- column with alias: <b>tags</b> for annotation tags. This is a comma separated string of tags e.g. 'tag1,tag2'.
......
......@@ -104,12 +104,15 @@ export default class ResponseParser {
const table = data.data.results[options.annotation.name].tables[0];
let timeColumnIndex = -1;
let timeEndColumnIndex = -1;
let textColumnIndex = -1;
let tagsColumnIndex = -1;
for (let i = 0; i < table.columns.length; i++) {
if (table.columns[i].text === 'time') {
timeColumnIndex = i;
} else if (table.columns[i].text === 'timeend') {
timeEndColumnIndex = i;
} else if (table.columns[i].text === 'text') {
textColumnIndex = i;
} else if (table.columns[i].text === 'tags') {
......@@ -124,9 +127,12 @@ export default class ResponseParser {
const list = [];
for (let i = 0; i < table.rows.length; i++) {
const row = table.rows[i];
const timeEnd =
timeEndColumnIndex !== -1 && row[timeEndColumnIndex] ? Math.floor(row[timeEndColumnIndex]) : undefined;
list.push({
annotation: options.annotation,
time: Math.floor(row[timeColumnIndex]),
timeEnd,
text: row[textColumnIndex],
tags: row[tagsColumnIndex] ? row[tagsColumnIndex].trim().split(/\s*,\s*/) : [],
});
......
......@@ -18,9 +18,10 @@
<div class="gf-form" ng-show="ctrl.showHelp">
<pre class="gf-form-pre alert alert-info"><h6>Annotation Query Format</h6>
An annotation is an event that is overlaid on top of graphs. The query can have up to three columns per row, the <i>time</i> or <i>time_sec</i> column is mandatory. Annotation rendering is expensive so it is important to limit the number of rows returned.
An annotation is an event that is overlaid on top of graphs. The query can have up to four columns per row, the <i>time</i> or <i>time_sec</i> column is mandatory. Annotation rendering is expensive so it is important to limit the number of rows returned.
- column with alias: <b>time</b> or <i>time_sec</i> for the annotation event time. Use epoch time or any native date data type.
- column with alias: <b>timeend</b> for the annotation event end time. Use epoch time or any native date data type.
- column with alias: <b>text</b> for the annotation text
- column with alias: <b>tags</b> for annotation tags. This is a comma separated string of tags e.g. 'tag1,tag2'
......
......@@ -107,12 +107,15 @@ export default class ResponseParser {
const table = data.data.results[options.annotation.name].tables[0];
let timeColumnIndex = -1;
let timeEndColumnIndex = -1;
let textColumnIndex = -1;
let tagsColumnIndex = -1;
for (let i = 0; i < table.columns.length; i++) {
if (table.columns[i].text === 'time_sec' || table.columns[i].text === 'time') {
timeColumnIndex = i;
} else if (table.columns[i].text === 'timeend') {
timeEndColumnIndex = i;
} else if (table.columns[i].text === 'title') {
return Promise.reject({
message: 'The title column for annotations is deprecated, now only a column named text is returned',
......@@ -133,9 +136,12 @@ export default class ResponseParser {
const list = [];
for (let i = 0; i < table.rows.length; i++) {
const row = table.rows[i];
const timeEnd =
timeEndColumnIndex !== -1 && row[timeEndColumnIndex] ? Math.floor(row[timeEndColumnIndex]) : undefined;
list.push({
annotation: options.annotation,
time: Math.floor(row[timeColumnIndex]),
timeEnd,
text: row[textColumnIndex] ? row[textColumnIndex].toString() : '',
tags: row[tagsColumnIndex] ? row[tagsColumnIndex].trim().split(/\s*,\s*/) : [],
});
......
......@@ -18,9 +18,10 @@
<div class="gf-form" ng-show="ctrl.showHelp">
<pre class="gf-form-pre alert alert-info"><h6>Annotation Query Format</h6>
An annotation is an event that is overlaid on top of graphs. The query can have up to three columns per row, the time column is mandatory. Annotation rendering is expensive so it is important to limit the number of rows returned.
An annotation is an event that is overlaid on top of graphs. The query can have up to four columns per row, the time column is mandatory. Annotation rendering is expensive so it is important to limit the number of rows returned.
- column with alias: <b>time</b> for the annotation event time. Use epoch time or any native date data type.
- column with alias: <b>timeend</b> for the annotation event time-end. Use epoch time or any native date data type.
- column with alias: <b>text</b> for the annotation text
- column with alias: <b>tags</b> for annotation tags. This is a comma separated string of tags e.g. 'tag1,tag2'
......
......@@ -107,6 +107,7 @@ export default class ResponseParser {
const table = data.data.results[options.annotation.name].tables[0];
let timeColumnIndex = -1;
let timeEndColumnIndex = -1;
const titleColumnIndex = -1;
let textColumnIndex = -1;
let tagsColumnIndex = -1;
......@@ -114,6 +115,8 @@ export default class ResponseParser {
for (let i = 0; i < table.columns.length; i++) {
if (table.columns[i].text === 'time') {
timeColumnIndex = i;
} else if (table.columns[i].text === 'timeend') {
timeEndColumnIndex = i;
} else if (table.columns[i].text === 'text') {
textColumnIndex = i;
} else if (table.columns[i].text === 'tags') {
......@@ -130,9 +133,12 @@ export default class ResponseParser {
const list = [];
for (let i = 0; i < table.rows.length; i++) {
const row = table.rows[i];
const timeEnd =
timeEndColumnIndex !== -1 && row[timeEndColumnIndex] ? Math.floor(row[timeEndColumnIndex]) : undefined;
list.push({
annotation: options.annotation,
time: Math.floor(row[timeColumnIndex]),
timeEnd,
title: row[titleColumnIndex],
text: row[textColumnIndex],
tags: row[tagsColumnIndex] ? row[tagsColumnIndex].trim().split(/\s*,\s*/) : [],
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment