mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
Merge pull request #12680 from svenklemm/timebucket
[postgres] add timescaledb option to postgres datasource
This commit is contained in:
commit
74077be19e
@ -31,6 +31,7 @@ Name | Description
|
||||
*User* | Database user's login/username
|
||||
*Password* | Database user's password
|
||||
*SSL Mode* | This option determines whether or with what priority a secure SSL TCP/IP connection will be negotiated with the server.
|
||||
*TimescaleDB* | With this option enabled Grafana will use TimescaleDB features, e.g. use ```time_bucket``` for grouping by time (only available in Grafana 5.3+).
|
||||
|
||||
### Database User Permissions (Important!)
|
||||
|
||||
@ -289,4 +290,5 @@ datasources:
|
||||
password: "Password!"
|
||||
jsonData:
|
||||
sslmode: "disable" # disable/require/verify-ca/verify-full
|
||||
timescaledb: false
|
||||
```
|
||||
|
@ -14,12 +14,13 @@ const rsIdentifier = `([_a-zA-Z0-9]+)`
|
||||
const sExpr = `\$` + rsIdentifier + `\(([^\)]*)\)`
|
||||
|
||||
type postgresMacroEngine struct {
|
||||
timeRange *tsdb.TimeRange
|
||||
query *tsdb.Query
|
||||
timeRange *tsdb.TimeRange
|
||||
query *tsdb.Query
|
||||
timescaledb bool
|
||||
}
|
||||
|
||||
func newPostgresMacroEngine() tsdb.SqlMacroEngine {
|
||||
return &postgresMacroEngine{}
|
||||
func newPostgresMacroEngine(timescaledb bool) tsdb.SqlMacroEngine {
|
||||
return &postgresMacroEngine{timescaledb: timescaledb}
|
||||
}
|
||||
|
||||
func (m *postgresMacroEngine) Interpolate(query *tsdb.Query, timeRange *tsdb.TimeRange, sql string) (string, error) {
|
||||
@ -118,7 +119,12 @@ func (m *postgresMacroEngine) evaluateMacro(name string, args []string) (string,
|
||||
return "", err
|
||||
}
|
||||
}
|
||||
return fmt.Sprintf("floor(extract(epoch from %s)/%v)*%v", args[0], interval.Seconds(), interval.Seconds()), nil
|
||||
|
||||
if m.timescaledb {
|
||||
return fmt.Sprintf("time_bucket('%vs',%s)", interval.Seconds(), args[0]), nil
|
||||
} else {
|
||||
return fmt.Sprintf("floor(extract(epoch from %s)/%v)*%v", args[0], interval.Seconds(), interval.Seconds()), nil
|
||||
}
|
||||
case "__timeGroupAlias":
|
||||
tg, err := m.evaluateMacro("__timeGroup", args)
|
||||
if err == nil {
|
||||
|
@ -12,7 +12,10 @@ import (
|
||||
|
||||
func TestMacroEngine(t *testing.T) {
|
||||
Convey("MacroEngine", t, func() {
|
||||
engine := newPostgresMacroEngine()
|
||||
timescaledbEnabled := false
|
||||
engine := newPostgresMacroEngine(timescaledbEnabled)
|
||||
timescaledbEnabled = true
|
||||
engineTS := newPostgresMacroEngine(timescaledbEnabled)
|
||||
query := &tsdb.Query{}
|
||||
|
||||
Convey("Given a time range between 2018-04-12 00:00 and 2018-04-12 00:05", func() {
|
||||
@ -83,6 +86,22 @@ func TestMacroEngine(t *testing.T) {
|
||||
So(sql2, ShouldEqual, sql+" AS \"time\"")
|
||||
})
|
||||
|
||||
Convey("interpolate __timeGroup function with TimescaleDB enabled", func() {
|
||||
|
||||
sql, err := engineTS.Interpolate(query, timeRange, "GROUP BY $__timeGroup(time_column,'5m')")
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
So(sql, ShouldEqual, "GROUP BY time_bucket('300s',time_column)")
|
||||
})
|
||||
|
||||
Convey("interpolate __timeGroup function with spaces between args and TimescaleDB enabled", func() {
|
||||
|
||||
sql, err := engineTS.Interpolate(query, timeRange, "GROUP BY $__timeGroup(time_column , '5m')")
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
So(sql, ShouldEqual, "GROUP BY time_bucket('300s',time_column)")
|
||||
})
|
||||
|
||||
Convey("interpolate __timeTo function", func() {
|
||||
sql, err := engine.Interpolate(query, timeRange, "select $__timeTo(time_column)")
|
||||
So(err, ShouldBeNil)
|
||||
|
@ -32,7 +32,9 @@ func newPostgresQueryEndpoint(datasource *models.DataSource) (tsdb.TsdbQueryEndp
|
||||
log: logger,
|
||||
}
|
||||
|
||||
return tsdb.NewSqlQueryEndpoint(&config, &rowTransformer, newPostgresMacroEngine(), logger)
|
||||
timescaledb := datasource.JsonData.Get("timescaledb").MustBool(false)
|
||||
|
||||
return tsdb.NewSqlQueryEndpoint(&config, &rowTransformer, newPostgresMacroEngine(timescaledb), logger)
|
||||
}
|
||||
|
||||
func generateConnectionString(datasource *models.DataSource) string {
|
||||
|
@ -27,7 +27,7 @@ import (
|
||||
// use to verify that the generated data are vizualized as expected, see
|
||||
// devenv/README.md for setup instructions.
|
||||
func TestPostgres(t *testing.T) {
|
||||
// change to true to run the MySQL tests
|
||||
// change to true to run the PostgreSQL tests
|
||||
runPostgresTests := false
|
||||
// runPostgresTests := true
|
||||
|
||||
|
@ -124,25 +124,7 @@ export class PostgresDatasource {
|
||||
}
|
||||
|
||||
testDatasource() {
|
||||
return this.backendSrv
|
||||
.datasourceRequest({
|
||||
url: '/api/tsdb/query',
|
||||
method: 'POST',
|
||||
data: {
|
||||
from: '5m',
|
||||
to: 'now',
|
||||
queries: [
|
||||
{
|
||||
refId: 'A',
|
||||
intervalMs: 1,
|
||||
maxDataPoints: 1,
|
||||
datasourceId: this.id,
|
||||
rawSql: 'SELECT 1',
|
||||
format: 'table',
|
||||
},
|
||||
],
|
||||
},
|
||||
})
|
||||
return this.metricFindQuery('SELECT 1', {})
|
||||
.then(res => {
|
||||
return { status: 'success', message: 'Database Connection OK' };
|
||||
})
|
||||
|
@ -38,6 +38,14 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<h3 class="page-heading">PostgreSQL details</h3>
|
||||
|
||||
<div class="gf-form-group">
|
||||
<div class="gf-form">
|
||||
<gf-form-switch class="gf-form" label="TimescaleDB" tooltip="Use TimescaleDB features (e.g., time_bucket) in Grafana" label-class="width-9" checked="ctrl.current.jsonData.timescaledb" switch-class="max-width-6"></gf-form-switch>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="gf-form-group">
|
||||
<div class="grafana-info-box">
|
||||
<h5>User Permission</h5>
|
||||
|
Loading…
Reference in New Issue
Block a user