Commit 6c49fdb5 by Torkel Ödegaard Committed by GitHub

TemplateSrv: Formatting options for ${__from} and ${__to}, unix seconds epoch,…

TemplateSrv: Formatting options for ${__from} and ${__to}, unix seconds epoch, ISO 8601/RFC 3339  (#26466)

* TemplateSrv: WIP date formats

* Templating: formats with arguments

* WIP docs updates

* Docs: Updated docs

* fixed spelling

* Update docs/sources/variables/global-variables.md

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

* Update docs/sources/variables/global-variables.md

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

* Update docs/sources/variables/global-variables.md

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

* Update docs/sources/variables/global-variables.md

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

Co-authored-by: Diana Payton <52059945+oddlittlebird@users.noreply.github.com>
parent e3ea7253
...@@ -140,10 +140,10 @@ You can use a variable in a metric node path or as a parameter to a function. ...@@ -140,10 +140,10 @@ You can use a variable in a metric node path or as a parameter to a function.
There are two syntaxes: There are two syntaxes:
- `$<varname>` Example: apps.frontend.$server.requests.count - `$<varname>` Example: apps.frontend.$server.requests.count
- `[[varname]]` Example: apps.frontend.[[server]].requests.count - `${varname}` Example: apps.frontend.${server}.requests.count
Why two ways? The first syntax is easier to read and write but does not allow you to use a variable in the middle of a word. Use Why two ways? The first syntax is easier to read and write but does not allow you to use a variable in the middle of a word. Use
the second syntax in expressions like `my.server[[serverNumber]].count`. the second syntax in expressions like `my.server${serverNumber}.count`.
Example: Example:
[Graphite Templated Dashboard](https://play.grafana.org/dashboard/db/graphite-templated-nested) [Graphite Templated Dashboard](https://play.grafana.org/dashboard/db/graphite-templated-nested)
......
...@@ -10,23 +10,32 @@ weight = 200 ...@@ -10,23 +10,32 @@ weight = 200
# Global variables # Global variables
Grafana has global built-in variables that can be used in expressions in the query editor. This topic lists them in alphabetical order and defines them. Grafana has global built-in variables that can be used in expressions in the query editor. This topic lists them in alphabetical order and defines them. These variables are useful in queries, dashboard links, panel links, and data links.
## $__dashboard ## $__dashboard
> Only available in Grafana v6.7+
This variable is the UID of the current dashboard. - `${__dashboard.name}` is the name of the current dashboard
`${__dashboard.name}` is the name of the current dashboard. - `${__dashboard.uid}` is the UID of the current dashboard (used in url)
## $__from and $__to ## $__from and $__to
> Only available in Grafana v6.0+ Grafana has two built in time range variables: `$__from` and `$__to`. They are currently always interpolated as epoch milliseconds by default but you can control date formatting.
Grafana has two built in time range variables: `$__from` and `$__to`. They are currently always interpolated as epoch milliseconds. > This special formatting syntax is only available in Grafan a 7.1.2+
| Syntax | Example result | Description |
| ------------------------ | ------------------------ | ----------- |
| `${__from}` | 1594671549254 | Unix millisecond epoch |
| `${__from:date}` | 2020-07-13T20:19:09.254Z | No args, defaults to ISO 8601/RFC 3339 |
| `${__from:date:iso}` | 2020-07-13T20:19:09.254Z | ISO 8601/RFC 3339 |
| `${__from:date:seconds}` | 1594671549 | Unix seconds epoch |
| `${__from:date:YYYY-MM}` | 2020-07 | Any custom [date format](https://momentjs.com/docs/#/displaying/) |
The above syntax works with `${__to}` as well.
## $__interval ## $__interval
The `$__interval` variable can be used as a parameter to group by time (for InfluxDB, MySQL, Postgres, MSSQL), Date histogram interval (for Elasticsearch) or as a *summarize* function parameter (for Graphite). You can use the `$__interval` variable as a parameter to group by time (for InfluxDB, MySQL, Postgres, MSSQL), Date histogram interval (for Elasticsearch), or as a _summarize_ function parameter (for Graphite).
Grafana automatically calculates an interval that can be used to group by time in queries. When there are more data points than can be shown on a graph then queries can be made more efficient by grouping by a larger interval. It is more efficient to group by 1 day than by 10s when looking at 3 months of data and the graph will look the same and the query will be faster. The `$__interval` is calculated using the time range and the width of the graph (the number of pixels). Grafana automatically calculates an interval that can be used to group by time in queries. When there are more data points than can be shown on a graph then queries can be made more efficient by grouping by a larger interval. It is more efficient to group by 1 day than by 10s when looking at 3 months of data and the graph will look the same and the query will be faster. The `$__interval` is calculated using the time range and the width of the graph (the number of pixels).
...@@ -48,8 +57,6 @@ This variable is only available in the Singlestat panel and can be used in the p ...@@ -48,8 +57,6 @@ This variable is only available in the Singlestat panel and can be used in the p
## $__org ## $__org
> Only available in Grafana v6.7+
This variable is the ID of the current organization. This variable is the ID of the current organization.
`${__org.name}` is the name of the current organization. `${__org.name}` is the name of the current organization.
...@@ -62,8 +69,6 @@ This variable is the ID of the current organization. ...@@ -62,8 +69,6 @@ This variable is the ID of the current organization.
## $__range ## $__range
> Only available in Grafana v5.3+
Currently only supported for Prometheus data sources. This variable represents the range for the current dashboard. It is calculated by `to - from`. It has a millisecond and a second representation called `$__range_ms` and `$__range_s`. Currently only supported for Prometheus data sources. This variable represents the range for the current dashboard. It is calculated by `to - from`. It has a millisecond and a second representation called `$__range_ms` and `$__range_s`.
## $timeFilter or $__timeFilter ## $timeFilter or $__timeFilter
...@@ -71,7 +76,8 @@ Currently only supported for Prometheus data sources. This variable represents t ...@@ -71,7 +76,8 @@ Currently only supported for Prometheus data sources. This variable represents t
The `$timeFilter` variable returns the currently selected time range as an expression. For example, the time range interval `Last 7 days` expression is `time > now() - 7d`. The `$timeFilter` variable returns the currently selected time range as an expression. For example, the time range interval `Last 7 days` expression is `time > now() - 7d`.
This is used in several places, including: This is used in several places, including:
* The WHERE clause for the InfluxDB data source. Grafana adds it automatically to InfluxDB queries when in Query Editor Mode. It has to be added manually in Text Editor Mode: `WHERE $timeFilter`.
* Log Analytics queries in the Azure Monitor data source. - The WHERE clause for the InfluxDB data source. Grafana adds it automatically to InfluxDB queries when in Query Editor mode. You can add it manually in Text Editor mode: `WHERE $timeFilter`.
* SQL queries in MySQL, Postgres, and MSSQL - Log Analytics queries in the Azure Monitor data source.
* The `$__timeFilter` variable is used in the MySQL data source. - SQL queries in MySQL, Postgres, and MSSQL
\ No newline at end of file - The `$__timeFilter` variable is used in the MySQL data source.
...@@ -3,15 +3,16 @@ import { convertToStoreState } from 'test/helpers/convertToStoreState'; ...@@ -3,15 +3,16 @@ import { convertToStoreState } from 'test/helpers/convertToStoreState';
import { getTemplateSrvDependencies } from '../../../test/helpers/getTemplateSrvDependencies'; import { getTemplateSrvDependencies } from '../../../test/helpers/getTemplateSrvDependencies';
import { variableAdapters } from '../variables/adapters'; import { variableAdapters } from '../variables/adapters';
import { createQueryVariableAdapter } from '../variables/query/adapter'; import { createQueryVariableAdapter } from '../variables/query/adapter';
import { dateTime, TimeRange } from '@grafana/data';
describe('templateSrv', () => { describe('templateSrv', () => {
let _templateSrv: any; let _templateSrv: any;
function initTemplateSrv(variables: any[]) { function initTemplateSrv(variables: any[], timeRange?: TimeRange) {
const state = convertToStoreState(variables); const state = convertToStoreState(variables);
_templateSrv = new TemplateSrv(getTemplateSrvDependencies(state)); _templateSrv = new TemplateSrv(getTemplateSrvDependencies(state));
_templateSrv.init(variables); _templateSrv.init(variables, timeRange);
} }
describe('init', () => { describe('init', () => {
...@@ -606,4 +607,38 @@ describe('templateSrv', () => { ...@@ -606,4 +607,38 @@ describe('templateSrv', () => {
expect(target).toBe('10 * 100'); expect(target).toBe('10 * 100');
}); });
}); });
describe('date formating', () => {
beforeEach(() => {
initTemplateSrv([], {
from: dateTime(1594671549254),
to: dateTime(1595237229747),
} as TimeRange);
});
it('should replace ${__from} with ms epoch value', () => {
const target = _templateSrv.replace('${__from}');
expect(target).toBe('1594671549254');
});
it('should replace ${__from:date:seconds} with epoch in seconds', () => {
const target = _templateSrv.replace('${__from:date:seconds}');
expect(target).toBe('1594671549');
});
it('should replace ${__from:date} with iso date', () => {
const target = _templateSrv.replace('${__from:date}');
expect(target).toBe('2020-07-13T20:19:09.254Z');
});
it('should replace ${__from:date:iso} with iso date', () => {
const target = _templateSrv.replace('${__from:date:iso}');
expect(target).toBe('2020-07-13T20:19:09.254Z');
});
it('should replace ${__from:date:YYYY-MM} using custom format', () => {
const target = _templateSrv.replace('${__from:date:YYYY-MM}');
expect(target).toBe('2020-07');
});
});
}); });
import kbn from 'app/core/utils/kbn'; import kbn from 'app/core/utils/kbn';
import _ from 'lodash'; import _ from 'lodash';
import { deprecationWarning, ScopedVars, textUtil, TimeRange } from '@grafana/data'; import { deprecationWarning, ScopedVars, textUtil, TimeRange, dateTime } from '@grafana/data';
import { getFilteredVariables, getVariables, getVariableWithName } from '../variables/state/selectors'; import { getFilteredVariables, getVariables, getVariableWithName } from '../variables/state/selectors';
import { variableRegex } from '../variables/utils'; import { variableRegex } from '../variables/utils';
import { isAdHoc } from '../variables/guard'; import { isAdHoc } from '../variables/guard';
...@@ -154,6 +154,19 @@ export class TemplateSrv implements BaseTemplateSrv { ...@@ -154,6 +154,19 @@ export class TemplateSrv implements BaseTemplateSrv {
return format(value, variable, this.formatValue); return format(value, variable, this.formatValue);
} }
if (!format) {
format = 'glob';
}
// some formats have arguments that come after ':' character
let args = format.split(':');
if (args.length > 1) {
format = args[0];
args = args.slice(1);
} else {
args = [];
}
switch (format) { switch (format) {
case 'regex': { case 'regex': {
if (typeof value === 'string') { if (typeof value === 'string') {
...@@ -227,7 +240,10 @@ export class TemplateSrv implements BaseTemplateSrv { ...@@ -227,7 +240,10 @@ export class TemplateSrv implements BaseTemplateSrv {
} }
return `'${_.replace(value, regExp, "''")}'`; return `'${_.replace(value, regExp, "''")}'`;
} }
default: { case 'date': {
return this.formatDate(value, args);
}
case 'glob': {
if (_.isArray(value) && value.length > 1) { if (_.isArray(value) && value.length > 1) {
return '{' + value.join(',') + '}'; return '{' + value.join(',') + '}';
} }
...@@ -236,6 +252,21 @@ export class TemplateSrv implements BaseTemplateSrv { ...@@ -236,6 +252,21 @@ export class TemplateSrv implements BaseTemplateSrv {
} }
} }
formatDate(value: any, args: string[]): string {
const arg = args[0] ?? 'iso';
switch (arg) {
case 'ms':
return value;
case 'seconds':
return `${Math.round(parseInt(value, 10)! / 1000)}`;
case 'iso':
return dateTime(parseInt(value, 10)).toISOString();
default:
return dateTime(parseInt(value, 10)).format(arg);
}
}
setGrafanaVariable(name: string, value: any) { setGrafanaVariable(name: string, value: any) {
this.grafanaVariables[name] = value; this.grafanaVariables[name] = value;
} }
......
...@@ -7,7 +7,7 @@ import { ScopedVars } from '@grafana/data'; ...@@ -7,7 +7,7 @@ import { ScopedVars } from '@grafana/data';
* \[\[([\s\S]+?)(?::(\w+))?\]\] [[var2]] or [[var2:fmt2]] * \[\[([\s\S]+?)(?::(\w+))?\]\] [[var2]] or [[var2:fmt2]]
* \${(\w+)(?::(\w+))?} ${var3} or ${var3:fmt3} * \${(\w+)(?::(\w+))?} ${var3} or ${var3:fmt3}
*/ */
export const variableRegex = /\$(\w+)|\[\[([\s\S]+?)(?::(\w+))?\]\]|\${(\w+)(?:\.([^:^\}]+))?(?::(\w+))?}/g; export const variableRegex = /\$(\w+)|\[\[([\s\S]+?)(?::(\w+))?\]\]|\${(\w+)(?:\.([^:^\}]+))?(?::([^\}]+))?}/g;
// Helper function since lastIndex is not reset // Helper function since lastIndex is not reset
export const variableRegexExec = (variableString: string) => { export const variableRegexExec = (variableString: string) => {
......
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