mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
Merge branch 'master' into postgres-query-builder
This commit is contained in:
commit
3f5d325e5b
@ -14,7 +14,7 @@
|
|||||||
* **Table**: Make table sorting stable when null values exist [#12362](https://github.com/grafana/grafana/pull/12362), thx [@bz2](https://github.com/bz2)
|
* **Table**: Make table sorting stable when null values exist [#12362](https://github.com/grafana/grafana/pull/12362), thx [@bz2](https://github.com/bz2)
|
||||||
* **Prometheus**: Fix graph panel bar width issue in aligned prometheus queries [#12379](https://github.com/grafana/grafana/issues/12379)
|
* **Prometheus**: Fix graph panel bar width issue in aligned prometheus queries [#12379](https://github.com/grafana/grafana/issues/12379)
|
||||||
* **Prometheus**: Heatmap - fix unhandled error when some points are missing [#12484](https://github.com/grafana/grafana/issues/12484)
|
* **Prometheus**: Heatmap - fix unhandled error when some points are missing [#12484](https://github.com/grafana/grafana/issues/12484)
|
||||||
* **Prometheus**: Add $interval, $interval_ms, $range, and $range_ms support for dashboard and template queries [#12597](https://github.com/grafana/grafana/issues/12597)
|
* **Prometheus**: Add $__interval, $__interval_ms, $__range, $__range_s & $__range_ms support for dashboard and template queries [#12597](https://github.com/grafana/grafana/issues/12597) [#12882](https://github.com/grafana/grafana/issues/12882), thx [@roidelapluie](https://github.com/roidelapluie)
|
||||||
* **Variables**: Skip unneeded extra query request when de-selecting variable values used for repeated panels [#8186](https://github.com/grafana/grafana/issues/8186), thx [@mtanda](https://github.com/mtanda)
|
* **Variables**: Skip unneeded extra query request when de-selecting variable values used for repeated panels [#8186](https://github.com/grafana/grafana/issues/8186), thx [@mtanda](https://github.com/mtanda)
|
||||||
* **Postgres/MySQL/MSSQL**: Add previous fill mode to $__timeGroup macro which will fill in previously seen value when point is missing [#12756](https://github.com/grafana/grafana/issues/12756), thx [@svenklemm](https://github.com/svenklemm)
|
* **Postgres/MySQL/MSSQL**: Add previous fill mode to $__timeGroup macro which will fill in previously seen value when point is missing [#12756](https://github.com/grafana/grafana/issues/12756), thx [@svenklemm](https://github.com/svenklemm)
|
||||||
* **Postgres/MySQL/MSSQL**: Use floor rounding in $__timeGroup macro function [#12460](https://github.com/grafana/grafana/issues/12460), thx [@svenklemm](https://github.com/svenklemm)
|
* **Postgres/MySQL/MSSQL**: Use floor rounding in $__timeGroup macro function [#12460](https://github.com/grafana/grafana/issues/12460), thx [@svenklemm](https://github.com/svenklemm)
|
||||||
@ -40,6 +40,7 @@
|
|||||||
* **UI**: Fix iOS home screen "app" icon and Windows 10 app experience [#12752](https://github.com/grafana/grafana/issues/12752), thx [@andig](https://github.com/andig)
|
* **UI**: Fix iOS home screen "app" icon and Windows 10 app experience [#12752](https://github.com/grafana/grafana/issues/12752), thx [@andig](https://github.com/andig)
|
||||||
* **Datasource**: Fix UI issue with secret fields after updating datasource [#11270](https://github.com/grafana/grafana/issues/11270)
|
* **Datasource**: Fix UI issue with secret fields after updating datasource [#11270](https://github.com/grafana/grafana/issues/11270)
|
||||||
* **Plugins**: Convert URL-like text to links in plugins readme [#12843](https://github.com/grafana/grafana/pull/12843), thx [pgiraud](https://github.com/pgiraud)
|
* **Plugins**: Convert URL-like text to links in plugins readme [#12843](https://github.com/grafana/grafana/pull/12843), thx [pgiraud](https://github.com/pgiraud)
|
||||||
|
* **Docker**: Make it possible to set a specific plugin url [#12861](https://github.com/grafana/grafana/pull/12861), thx [ClementGautier](https://github.com/ClementGautier)
|
||||||
|
|
||||||
### Breaking changes
|
### Breaking changes
|
||||||
|
|
||||||
|
@ -78,9 +78,9 @@ For details of *metric names*, *label names* and *label values* are please refer
|
|||||||
|
|
||||||
#### Using interval and range variables
|
#### Using interval and range variables
|
||||||
|
|
||||||
> Support for `$__range` and `$__range_ms` only available from Grafana v5.3
|
> Support for `$__range`, `$__range_s` and `$__range_ms` only available from Grafana v5.3
|
||||||
|
|
||||||
It's possible to use some global built-in variables in query variables; `$__interval`, `$__interval_ms`, `$__range` and `$__range_ms`, see [Global built-in variables](/reference/templating/#global-built-in-variables) for more information. These can be convenient to use in conjunction with the `query_result` function when you need to filter variable queries since
|
It's possible to use some global built-in variables in query variables; `$__interval`, `$__interval_ms`, `$__range`, `$__range_s` and `$__range_ms`, see [Global built-in variables](/reference/templating/#global-built-in-variables) for more information. These can be convenient to use in conjunction with the `query_result` function when you need to filter variable queries since
|
||||||
`label_values` function doesn't support queries.
|
`label_values` function doesn't support queries.
|
||||||
|
|
||||||
Make sure to set the variable's `refresh` trigger to be `On Time Range Change` to get the correct instances when changing the time range on the dashboard.
|
Make sure to set the variable's `refresh` trigger to be `On Time Range Change` to get the correct instances when changing the time range on the dashboard.
|
||||||
@ -94,10 +94,10 @@ Query: query_result(topk(5, sum(rate(http_requests_total[$__range])) by (instanc
|
|||||||
Regex: /"([^"]+)"/
|
Regex: /"([^"]+)"/
|
||||||
```
|
```
|
||||||
|
|
||||||
Populate a variable with the instances having a certain state over the time range shown in the dashboard:
|
Populate a variable with the instances having a certain state over the time range shown in the dashboard, using the more precise `$__range_s`:
|
||||||
|
|
||||||
```
|
```
|
||||||
Query: query_result(max_over_time(<metric>[$__range]) != <state>)
|
Query: query_result(max_over_time(<metric>[${__range_s}s]) != <state>)
|
||||||
Regex:
|
Regex:
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -277,7 +277,7 @@ This variable is only available in the Singlestat panel and can be used in the p
|
|||||||
|
|
||||||
> Only available in Grafana v5.3+
|
> 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 representation called `$__range_ms`.
|
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`.
|
||||||
|
|
||||||
## Repeating Panels
|
## Repeating Panels
|
||||||
|
|
||||||
|
@ -1,7 +1,5 @@
|
|||||||
# Grafana Docker image
|
# Grafana Docker image
|
||||||
|
|
||||||
[](https://circleci.com/gh/grafana/grafana-docker)
|
|
||||||
|
|
||||||
## Running your Grafana container
|
## Running your Grafana container
|
||||||
|
|
||||||
Start your container binding the external port `3000`.
|
Start your container binding the external port `3000`.
|
||||||
@ -42,4 +40,4 @@ Further documentation can be found at http://docs.grafana.org/installation/docke
|
|||||||
* Plugins dir (`/var/lib/grafana/plugins`) is no longer a separate volume
|
* Plugins dir (`/var/lib/grafana/plugins`) is no longer a separate volume
|
||||||
|
|
||||||
### v3.1.1
|
### v3.1.1
|
||||||
* Make it possible to install specific plugin version https://github.com/grafana/grafana-docker/issues/59#issuecomment-260584026
|
* Make it possible to install specific plugin version https://github.com/grafana/grafana-docker/issues/59#issuecomment-260584026
|
||||||
|
@ -67,7 +67,13 @@ if [ ! -z "${GF_INSTALL_PLUGINS}" ]; then
|
|||||||
IFS=','
|
IFS=','
|
||||||
for plugin in ${GF_INSTALL_PLUGINS}; do
|
for plugin in ${GF_INSTALL_PLUGINS}; do
|
||||||
IFS=$OLDIFS
|
IFS=$OLDIFS
|
||||||
grafana-cli --pluginsDir "${GF_PATHS_PLUGINS}" plugins install ${plugin}
|
if [[ $plugin =~ .*\;.* ]]; then
|
||||||
|
pluginUrl=$(echo "$plugin" | cut -d';' -f 1)
|
||||||
|
pluginWithoutUrl=$(echo "$plugin" | cut -d';' -f 2)
|
||||||
|
grafana-cli --pluginUrl "${pluginUrl}" --pluginsDir "${GF_PATHS_PLUGINS}" plugins install ${pluginWithoutUrl}
|
||||||
|
else
|
||||||
|
grafana-cli --pluginsDir "${GF_PATHS_PLUGINS}" plugins install ${plugin}
|
||||||
|
fi
|
||||||
done
|
done
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
@ -6,8 +6,6 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"strconv"
|
|
||||||
|
|
||||||
"github.com/grafana/grafana/pkg/tsdb"
|
"github.com/grafana/grafana/pkg/tsdb"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -97,20 +95,9 @@ func (m *msSqlMacroEngine) evaluateMacro(name string, args []string) (string, er
|
|||||||
return "", fmt.Errorf("error parsing interval %v", args[1])
|
return "", fmt.Errorf("error parsing interval %v", args[1])
|
||||||
}
|
}
|
||||||
if len(args) == 3 {
|
if len(args) == 3 {
|
||||||
m.query.Model.Set("fill", true)
|
err := tsdb.SetupFillmode(m.query, interval, args[2])
|
||||||
m.query.Model.Set("fillInterval", interval.Seconds())
|
if err != nil {
|
||||||
switch args[2] {
|
return "", err
|
||||||
case "NULL":
|
|
||||||
m.query.Model.Set("fillMode", "null")
|
|
||||||
case "previous":
|
|
||||||
m.query.Model.Set("fillMode", "previous")
|
|
||||||
default:
|
|
||||||
m.query.Model.Set("fillMode", "value")
|
|
||||||
floatVal, err := strconv.ParseFloat(args[2], 64)
|
|
||||||
if err != nil {
|
|
||||||
return "", fmt.Errorf("error parsing fill value %v", args[2])
|
|
||||||
}
|
|
||||||
m.query.Model.Set("fillValue", floatVal)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return fmt.Sprintf("FLOOR(DATEDIFF(second, '1970-01-01', %s)/%.0f)*%.0f", args[0], interval.Seconds(), interval.Seconds()), nil
|
return fmt.Sprintf("FLOOR(DATEDIFF(second, '1970-01-01', %s)/%.0f)*%.0f", args[0], interval.Seconds(), interval.Seconds()), nil
|
||||||
|
@ -3,7 +3,6 @@ package mysql
|
|||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"regexp"
|
"regexp"
|
||||||
"strconv"
|
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
@ -92,20 +91,9 @@ func (m *mySqlMacroEngine) evaluateMacro(name string, args []string) (string, er
|
|||||||
return "", fmt.Errorf("error parsing interval %v", args[1])
|
return "", fmt.Errorf("error parsing interval %v", args[1])
|
||||||
}
|
}
|
||||||
if len(args) == 3 {
|
if len(args) == 3 {
|
||||||
m.query.Model.Set("fill", true)
|
err := tsdb.SetupFillmode(m.query, interval, args[2])
|
||||||
m.query.Model.Set("fillInterval", interval.Seconds())
|
if err != nil {
|
||||||
switch args[2] {
|
return "", err
|
||||||
case "NULL":
|
|
||||||
m.query.Model.Set("fillMode", "null")
|
|
||||||
case "previous":
|
|
||||||
m.query.Model.Set("fillMode", "previous")
|
|
||||||
default:
|
|
||||||
m.query.Model.Set("fillMode", "value")
|
|
||||||
floatVal, err := strconv.ParseFloat(args[2], 64)
|
|
||||||
if err != nil {
|
|
||||||
return "", fmt.Errorf("error parsing fill value %v", args[2])
|
|
||||||
}
|
|
||||||
m.query.Model.Set("fillValue", floatVal)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return fmt.Sprintf("UNIX_TIMESTAMP(%s) DIV %.0f * %.0f", args[0], interval.Seconds(), interval.Seconds()), nil
|
return fmt.Sprintf("UNIX_TIMESTAMP(%s) DIV %.0f * %.0f", args[0], interval.Seconds(), interval.Seconds()), nil
|
||||||
|
@ -3,7 +3,6 @@ package postgres
|
|||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"regexp"
|
"regexp"
|
||||||
"strconv"
|
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
@ -114,20 +113,9 @@ func (m *postgresMacroEngine) evaluateMacro(name string, args []string) (string,
|
|||||||
return "", fmt.Errorf("error parsing interval %v", args[1])
|
return "", fmt.Errorf("error parsing interval %v", args[1])
|
||||||
}
|
}
|
||||||
if len(args) == 3 {
|
if len(args) == 3 {
|
||||||
m.query.Model.Set("fill", true)
|
err := tsdb.SetupFillmode(m.query, interval, args[2])
|
||||||
m.query.Model.Set("fillInterval", interval.Seconds())
|
if err != nil {
|
||||||
switch args[2] {
|
return "", err
|
||||||
case "NULL":
|
|
||||||
m.query.Model.Set("fillMode", "null")
|
|
||||||
case "previous":
|
|
||||||
m.query.Model.Set("fillMode", "previous")
|
|
||||||
default:
|
|
||||||
m.query.Model.Set("fillMode", "value")
|
|
||||||
floatVal, err := strconv.ParseFloat(args[2], 64)
|
|
||||||
if err != nil {
|
|
||||||
return "", fmt.Errorf("error parsing fill value %v", args[2])
|
|
||||||
}
|
|
||||||
m.query.Model.Set("fillValue", floatVal)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return fmt.Sprintf("floor(extract(epoch from %s)/%v)*%v", args[0], interval.Seconds(), interval.Seconds()), nil
|
return fmt.Sprintf("floor(extract(epoch from %s)/%v)*%v", args[0], interval.Seconds(), interval.Seconds()), nil
|
||||||
|
@ -6,6 +6,7 @@ import (
|
|||||||
"database/sql"
|
"database/sql"
|
||||||
"fmt"
|
"fmt"
|
||||||
"math"
|
"math"
|
||||||
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
@ -568,3 +569,23 @@ func ConvertSqlValueColumnToFloat(columnName string, columnValue interface{}) (n
|
|||||||
|
|
||||||
return value, nil
|
return value, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func SetupFillmode(query *Query, interval time.Duration, fillmode string) error {
|
||||||
|
query.Model.Set("fill", true)
|
||||||
|
query.Model.Set("fillInterval", interval.Seconds())
|
||||||
|
switch fillmode {
|
||||||
|
case "NULL":
|
||||||
|
query.Model.Set("fillMode", "null")
|
||||||
|
case "previous":
|
||||||
|
query.Model.Set("fillMode", "previous")
|
||||||
|
default:
|
||||||
|
query.Model.Set("fillMode", "value")
|
||||||
|
floatVal, err := strconv.ParseFloat(fillmode, 64)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("error parsing fill value %v", fillmode)
|
||||||
|
}
|
||||||
|
query.Model.Set("fillValue", floatVal)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
@ -489,9 +489,11 @@ export class PrometheusDatasource {
|
|||||||
getRangeScopedVars() {
|
getRangeScopedVars() {
|
||||||
let range = this.timeSrv.timeRange();
|
let range = this.timeSrv.timeRange();
|
||||||
let msRange = range.to.diff(range.from);
|
let msRange = range.to.diff(range.from);
|
||||||
|
let sRange = Math.round(msRange / 1000);
|
||||||
let regularRange = kbn.secondsToHms(msRange / 1000);
|
let regularRange = kbn.secondsToHms(msRange / 1000);
|
||||||
return {
|
return {
|
||||||
__range_ms: { text: msRange, value: msRange },
|
__range_ms: { text: msRange, value: msRange },
|
||||||
|
__range_s: { text: sRange, value: sRange },
|
||||||
__range: { text: regularRange, value: regularRange },
|
__range: { text: regularRange, value: regularRange },
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -321,8 +321,10 @@ describe('PrometheusDatasource', () => {
|
|||||||
it('should have the correct range and range_ms', () => {
|
it('should have the correct range and range_ms', () => {
|
||||||
let range = ctx.templateSrvMock.replace.mock.calls[0][1].__range;
|
let range = ctx.templateSrvMock.replace.mock.calls[0][1].__range;
|
||||||
let rangeMs = ctx.templateSrvMock.replace.mock.calls[0][1].__range_ms;
|
let rangeMs = ctx.templateSrvMock.replace.mock.calls[0][1].__range_ms;
|
||||||
|
let rangeS = ctx.templateSrvMock.replace.mock.calls[0][1].__range_s;
|
||||||
expect(range).toEqual({ text: '21s', value: '21s' });
|
expect(range).toEqual({ text: '21s', value: '21s' });
|
||||||
expect(rangeMs).toEqual({ text: 21031, value: 21031 });
|
expect(rangeMs).toEqual({ text: 21031, value: 21031 });
|
||||||
|
expect(rangeS).toEqual({ text: 21, value: 21 });
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should pass the default interval value', () => {
|
it('should pass the default interval value', () => {
|
||||||
|
Loading…
Reference in New Issue
Block a user