Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
N
nexpie-grafana-theme
Overview
Overview
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Registry
Registry
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Kornkitt Poolsup
nexpie-grafana-theme
Commits
c897d39d
Commit
c897d39d
authored
Nov 08, 2016
by
bergquist
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
feat(influxdb): add support for serie alias replacement
ref #6510
parent
24a3a100
Hide whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
191 additions
and
54 deletions
+191
-54
pkg/tsdb/influxdb/influxdb.go
+15
-12
pkg/tsdb/influxdb/response_parser.go
+48
-5
pkg/tsdb/influxdb/response_parser_test.go
+124
-33
pkg/tsdb/prometheus/prometheus.go
+4
-4
No files found.
pkg/tsdb/influxdb/influxdb.go
View file @
c897d39d
...
...
@@ -11,6 +11,7 @@ import (
"golang.org/x/net/context/ctxhttp"
"github.com/grafana/grafana/pkg/log"
"github.com/grafana/grafana/pkg/setting"
"github.com/grafana/grafana/pkg/tsdb"
)
...
...
@@ -50,9 +51,16 @@ func (e *InfluxDBExecutor) Execute(ctx context.Context, queries tsdb.QuerySlice,
return
result
.
WithError
(
err
)
}
glog
.
Debug
(
"Influxdb query"
,
"raw query"
,
query
)
rawQuery
,
err
:=
e
.
QueryBuilder
.
Build
(
query
,
context
)
if
err
!=
nil
{
return
result
.
WithError
(
err
)
}
if
setting
.
Env
==
setting
.
DEV
{
glog
.
Debug
(
"Influxdb query"
,
"raw query"
,
query
)
}
req
,
err
:=
e
.
createRequest
(
q
uery
)
req
,
err
:=
e
.
createRequest
(
rawQ
uery
)
if
err
!=
nil
{
return
result
.
WithError
(
err
)
}
...
...
@@ -77,28 +85,23 @@ func (e *InfluxDBExecutor) Execute(ctx context.Context, queries tsdb.QuerySlice,
}
result
.
QueryResults
=
make
(
map
[
string
]
*
tsdb
.
QueryResult
)
result
.
QueryResults
[
"A"
]
=
e
.
ResponseParser
.
Parse
(
&
response
)
result
.
QueryResults
[
"A"
]
=
e
.
ResponseParser
.
Parse
(
&
response
,
query
)
return
result
}
func
(
e
*
InfluxDBExecutor
)
getQuery
(
queries
tsdb
.
QuerySlice
,
context
*
tsdb
.
QueryContext
)
(
string
,
error
)
{
func
(
e
*
InfluxDBExecutor
)
getQuery
(
queries
tsdb
.
QuerySlice
,
context
*
tsdb
.
QueryContext
)
(
*
Query
,
error
)
{
for
_
,
v
:=
range
queries
{
query
,
err
:=
e
.
QueryParser
.
Parse
(
v
.
Model
,
e
.
DataSourceInfo
)
if
err
!=
nil
{
return
""
,
err
}
rawQuery
,
err
:=
e
.
QueryBuilder
.
Build
(
query
,
context
)
if
err
!=
nil
{
return
""
,
err
return
nil
,
err
}
return
rawQ
uery
,
nil
return
q
uery
,
nil
}
return
""
,
fmt
.
Errorf
(
"query request contains no queries"
)
return
nil
,
fmt
.
Errorf
(
"query request contains no queries"
)
}
func
(
e
*
InfluxDBExecutor
)
createRequest
(
query
string
)
(
*
http
.
Request
,
error
)
{
...
...
pkg/tsdb/influxdb/response_parser.go
View file @
c897d39d
...
...
@@ -3,6 +3,7 @@ package influxdb
import
(
"encoding/json"
"fmt"
"regexp"
"strings"
"github.com/grafana/grafana/pkg/tsdb"
...
...
@@ -11,17 +12,25 @@ import (
type
ResponseParser
struct
{}
func
(
rp
*
ResponseParser
)
Parse
(
response
*
Response
)
*
tsdb
.
QueryResult
{
var
(
legendFormat
*
regexp
.
Regexp
)
func
init
()
{
legendFormat
=
regexp
.
MustCompile
(
`\[\[(\w+?)*\]\]*|\$\s*(\w+?)*`
)
}
func
(
rp
*
ResponseParser
)
Parse
(
response
*
Response
,
query
*
Query
)
*
tsdb
.
QueryResult
{
queryRes
:=
tsdb
.
NewQueryResult
()
for
_
,
result
:=
range
response
.
Results
{
queryRes
.
Series
=
append
(
queryRes
.
Series
,
rp
.
transformRows
(
result
.
Series
,
queryRes
)
...
)
queryRes
.
Series
=
append
(
queryRes
.
Series
,
rp
.
transformRows
(
result
.
Series
,
queryRes
,
query
)
...
)
}
return
queryRes
}
func
(
rp
*
ResponseParser
)
transformRows
(
rows
[]
Row
,
queryResult
*
tsdb
.
QueryResult
)
tsdb
.
TimeSeriesSlice
{
func
(
rp
*
ResponseParser
)
transformRows
(
rows
[]
Row
,
queryResult
*
tsdb
.
QueryResult
,
query
*
Query
)
tsdb
.
TimeSeriesSlice
{
var
result
tsdb
.
TimeSeriesSlice
for
_
,
row
:=
range
rows
{
...
...
@@ -38,7 +47,7 @@ func (rp *ResponseParser) transformRows(rows []Row, queryResult *tsdb.QueryResul
}
}
result
=
append
(
result
,
&
tsdb
.
TimeSeries
{
Name
:
rp
.
formatSerieName
(
row
,
column
),
Name
:
rp
.
formatSerieName
(
row
,
column
,
query
),
Points
:
points
,
})
}
...
...
@@ -47,7 +56,41 @@ func (rp *ResponseParser) transformRows(rows []Row, queryResult *tsdb.QueryResul
return
result
}
func
(
rp
*
ResponseParser
)
formatSerieName
(
row
Row
,
column
string
)
string
{
func
(
rp
*
ResponseParser
)
formatSerieName
(
row
Row
,
column
string
,
query
*
Query
)
string
{
if
query
.
Alias
==
""
{
return
rp
.
buildSerieNameFromQuery
(
row
,
column
)
}
result
:=
legendFormat
.
ReplaceAllFunc
([]
byte
(
query
.
Alias
),
func
(
in
[]
byte
)
[]
byte
{
aliasFormat
:=
string
(
in
)
aliasFormat
=
strings
.
Replace
(
aliasFormat
,
"[["
,
""
,
1
)
aliasFormat
=
strings
.
Replace
(
aliasFormat
,
"]]"
,
""
,
1
)
aliasFormat
=
strings
.
Replace
(
aliasFormat
,
"$"
,
""
,
1
)
if
aliasFormat
==
"m"
||
aliasFormat
==
"measurement"
{
return
[]
byte
(
query
.
Measurement
)
}
if
aliasFormat
==
"col"
{
return
[]
byte
(
column
)
}
if
!
strings
.
HasPrefix
(
aliasFormat
,
"tag_"
)
{
return
in
}
tagKey
:=
strings
.
Replace
(
aliasFormat
,
"tag_"
,
""
,
1
)
tagValue
,
exist
:=
row
.
Tags
[
tagKey
]
if
exist
{
return
[]
byte
(
tagValue
)
}
return
in
})
return
string
(
result
)
}
func
(
rp
*
ResponseParser
)
buildSerieNameFromQuery
(
row
Row
,
column
string
)
string
{
var
tags
[]
string
for
k
,
v
:=
range
row
.
Tags
{
...
...
pkg/tsdb/influxdb/response_parser_test.go
View file @
c897d39d
...
...
@@ -4,56 +4,147 @@ import (
"encoding/json"
"testing"
"github.com/grafana/grafana/pkg/setting"
.
"github.com/smartystreets/goconvey/convey"
)
func
TestInfluxdbResponseParser
(
t
*
testing
.
T
)
{
Convey
(
"Influxdb response parser"
,
t
,
func
()
{
Convey
(
"Response parser"
,
func
()
{
parser
:=
&
ResponseParser
{}
parser
:=
&
ResponseParser
{}
response
:=
&
Response
{
Results
:
[]
Result
{
Result
{
Series
:
[]
Row
{
{
Name
:
"cpu"
,
Columns
:
[]
string
{
"time"
,
"mean"
,
"sum"
},
Tags
:
map
[
string
]
string
{
"datacenter"
:
"America"
},
Values
:
[][]
interface
{}{
{
json
.
Number
(
"111"
),
json
.
Number
(
"222"
),
json
.
Number
(
"333"
)},
{
json
.
Number
(
"111"
),
json
.
Number
(
"222"
),
json
.
Number
(
"333"
)},
{
json
.
Number
(
"111"
),
json
.
Number
(
"null"
),
json
.
Number
(
"333"
)},
setting
.
NewConfigContext
(
&
setting
.
CommandLineArgs
{
HomePath
:
"../../../"
,
})
response
:=
&
Response
{
Results
:
[]
Result
{
Result
{
Series
:
[]
Row
{
{
Name
:
"cpu"
,
Columns
:
[]
string
{
"time"
,
"mean"
,
"sum"
},
Tags
:
map
[
string
]
string
{
"datacenter"
:
"America"
},
Values
:
[][]
interface
{}{
{
json
.
Number
(
"111"
),
json
.
Number
(
"222"
),
json
.
Number
(
"333"
)},
{
json
.
Number
(
"111"
),
json
.
Number
(
"222"
),
json
.
Number
(
"333"
)},
{
json
.
Number
(
"111"
),
json
.
Number
(
"null"
),
json
.
Number
(
"333"
)},
},
},
},
},
},
},
}
}
result
:=
parser
.
Parse
(
response
)
query
:=
&
Query
{}
Convey
(
"can parse all series"
,
func
()
{
So
(
len
(
result
.
Series
),
ShouldEqual
,
2
)
})
result
:=
parser
.
Parse
(
response
,
query
)
Convey
(
"can parse all points"
,
func
()
{
So
(
len
(
result
.
Series
[
0
]
.
Points
),
ShouldEqual
,
3
)
So
(
len
(
result
.
Series
[
1
]
.
Points
),
ShouldEqual
,
3
)
})
Convey
(
"can parse all series"
,
func
()
{
So
(
len
(
result
.
Series
),
ShouldEqual
,
2
)
})
Convey
(
"can parse multi row result
"
,
func
()
{
So
(
result
.
Series
[
0
]
.
Points
[
1
][
0
]
.
Float64
,
ShouldEqual
,
float64
(
222
)
)
So
(
result
.
Series
[
1
]
.
Points
[
1
][
0
]
.
Float64
,
ShouldEqual
,
float64
(
333
)
)
})
Convey
(
"can parse all points
"
,
func
()
{
So
(
len
(
result
.
Series
[
0
]
.
Points
),
ShouldEqual
,
3
)
So
(
len
(
result
.
Series
[
1
]
.
Points
),
ShouldEqual
,
3
)
})
Convey
(
"can parse null points"
,
func
()
{
So
(
result
.
Series
[
0
]
.
Points
[
2
][
0
]
.
Valid
,
ShouldBeFalse
)
Convey
(
"can parse multi row result"
,
func
()
{
So
(
result
.
Series
[
0
]
.
Points
[
1
][
0
]
.
Float64
,
ShouldEqual
,
float64
(
222
))
So
(
result
.
Series
[
1
]
.
Points
[
1
][
0
]
.
Float64
,
ShouldEqual
,
float64
(
333
))
})
Convey
(
"can parse null points"
,
func
()
{
So
(
result
.
Series
[
0
]
.
Points
[
2
][
0
]
.
Valid
,
ShouldBeFalse
)
})
Convey
(
"can format serie names"
,
func
()
{
So
(
result
.
Series
[
0
]
.
Name
,
ShouldEqual
,
"cpu.mean { datacenter: America }"
)
So
(
result
.
Series
[
1
]
.
Name
,
ShouldEqual
,
"cpu.sum { datacenter: America }"
)
})
})
Convey
(
"can format serie names"
,
func
()
{
So
(
result
.
Series
[
0
]
.
Name
,
ShouldEqual
,
"cpu.mean { datacenter: America }"
)
So
(
result
.
Series
[
1
]
.
Name
,
ShouldEqual
,
"cpu.sum { datacenter: America }"
)
Convey
(
"Response parser with alias"
,
func
()
{
parser
:=
&
ResponseParser
{}
response
:=
&
Response
{
Results
:
[]
Result
{
Result
{
Series
:
[]
Row
{
{
Name
:
"cpu"
,
Columns
:
[]
string
{
"time"
,
"mean"
,
"sum"
},
Tags
:
map
[
string
]
string
{
"datacenter"
:
"America"
},
Values
:
[][]
interface
{}{
{
json
.
Number
(
"111"
),
json
.
Number
(
"222"
),
json
.
Number
(
"333"
)},
},
},
},
},
},
}
Convey
(
"$ alias"
,
func
()
{
Convey
(
"simple alias"
,
func
()
{
query
:=
&
Query
{
Alias
:
"serie alias"
}
result
:=
parser
.
Parse
(
response
,
query
)
So
(
result
.
Series
[
0
]
.
Name
,
ShouldEqual
,
"serie alias"
)
})
Convey
(
"measurement alias"
,
func
()
{
query
:=
&
Query
{
Alias
:
"alias $m $measurement"
,
Measurement
:
"10m"
}
result
:=
parser
.
Parse
(
response
,
query
)
So
(
result
.
Series
[
0
]
.
Name
,
ShouldEqual
,
"alias 10m 10m"
)
})
Convey
(
"column alias"
,
func
()
{
query
:=
&
Query
{
Alias
:
"alias $col"
,
Measurement
:
"10m"
}
result
:=
parser
.
Parse
(
response
,
query
)
So
(
result
.
Series
[
0
]
.
Name
,
ShouldEqual
,
"alias mean"
)
So
(
result
.
Series
[
1
]
.
Name
,
ShouldEqual
,
"alias sum"
)
})
Convey
(
"tag alias"
,
func
()
{
query
:=
&
Query
{
Alias
:
"alias $tag_datacenter"
}
result
:=
parser
.
Parse
(
response
,
query
)
So
(
result
.
Series
[
0
]
.
Name
,
ShouldEqual
,
"alias America"
)
})
})
Convey
(
"[[]] alias"
,
func
()
{
Convey
(
"simple alias"
,
func
()
{
query
:=
&
Query
{
Alias
:
"serie alias"
}
result
:=
parser
.
Parse
(
response
,
query
)
So
(
result
.
Series
[
0
]
.
Name
,
ShouldEqual
,
"serie alias"
)
})
Convey
(
"measurement alias"
,
func
()
{
query
:=
&
Query
{
Alias
:
"alias [[m]] [[measurement]]"
,
Measurement
:
"10m"
}
result
:=
parser
.
Parse
(
response
,
query
)
So
(
result
.
Series
[
0
]
.
Name
,
ShouldEqual
,
"alias 10m 10m"
)
})
Convey
(
"column alias"
,
func
()
{
query
:=
&
Query
{
Alias
:
"alias [[col]]"
,
Measurement
:
"10m"
}
result
:=
parser
.
Parse
(
response
,
query
)
So
(
result
.
Series
[
0
]
.
Name
,
ShouldEqual
,
"alias mean"
)
So
(
result
.
Series
[
1
]
.
Name
,
ShouldEqual
,
"alias sum"
)
})
Convey
(
"tag alias"
,
func
()
{
query
:=
&
Query
{
Alias
:
"alias [[tag_datacenter]]"
}
result
:=
parser
.
Parse
(
response
,
query
)
So
(
result
.
Series
[
0
]
.
Name
,
ShouldEqual
,
"alias America"
)
})
})
})
})
}
pkg/tsdb/prometheus/prometheus.go
View file @
c897d39d
...
...
@@ -24,12 +24,14 @@ func NewPrometheusExecutor(dsInfo *tsdb.DataSourceInfo) tsdb.Executor {
}
var
(
plog
log
.
Logger
plog
log
.
Logger
legendFormat
*
regexp
.
Regexp
)
func
init
()
{
plog
=
log
.
New
(
"tsdb.prometheus"
)
tsdb
.
RegisterExecutor
(
"prometheus"
,
NewPrometheusExecutor
)
legendFormat
=
regexp
.
MustCompile
(
`\{\{\s*(.+?)\s*\}\}`
)
}
func
(
e
*
PrometheusExecutor
)
getClient
()
(
prometheus
.
QueryAPI
,
error
)
{
...
...
@@ -79,13 +81,11 @@ func (e *PrometheusExecutor) Execute(ctx context.Context, queries tsdb.QuerySlic
}
func
formatLegend
(
metric
pmodel
.
Metric
,
query
*
PrometheusQuery
)
string
{
reg
,
_
:=
regexp
.
Compile
(
`\{\{\s*(.+?)\s*\}\}`
)
if
query
.
LegendFormat
==
""
{
return
metric
.
String
()
}
result
:=
reg
.
ReplaceAllFunc
([]
byte
(
query
.
LegendFormat
),
func
(
in
[]
byte
)
[]
byte
{
result
:=
legendFormat
.
ReplaceAllFunc
([]
byte
(
query
.
LegendFormat
),
func
(
in
[]
byte
)
[]
byte
{
labelName
:=
strings
.
Replace
(
string
(
in
),
"{{"
,
""
,
1
)
labelName
=
strings
.
Replace
(
labelName
,
"}}"
,
""
,
1
)
labelName
=
strings
.
TrimSpace
(
labelName
)
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment