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
199d0d15
Commit
199d0d15
authored
Oct 13, 2017
by
Alexander Zobnin
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
graphite: datasource refactor
parent
a834812e
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
290 additions
and
16 deletions
+290
-16
public/app/plugins/datasource/graphite/graphite_query.ts
+274
-0
public/app/plugins/datasource/graphite/partials/query.editor.html
+5
-5
public/app/plugins/datasource/graphite/query_ctrl.ts
+0
-0
public/app/plugins/datasource/graphite/specs/query_ctrl_specs.ts
+11
-11
No files found.
public/app/plugins/datasource/graphite/graphite_query.ts
0 → 100644
View file @
199d0d15
import
_
from
'lodash'
;
import
gfunc
from
'./gfunc'
;
import
{
Parser
}
from
'./parser'
;
export
default
class
GraphiteQuery
{
target
:
any
;
functions
:
any
[];
segments
:
any
[];
tags
:
any
[];
error
:
any
;
seriesByTagUsed
:
boolean
;
checkOtherSegmentsIndex
:
number
;
removeTagValue
:
string
;
templateSrv
:
any
;
scopedVars
:
any
;
/** @ngInject */
constructor
(
target
,
templateSrv
?,
scopedVars
?)
{
this
.
target
=
target
;
this
.
parseTarget
();
this
.
removeTagValue
=
'-- remove tag --'
;
}
parseTarget
()
{
this
.
functions
=
[];
this
.
segments
=
[];
this
.
error
=
null
;
if
(
this
.
target
.
textEditor
)
{
return
;
}
var
parser
=
new
Parser
(
this
.
target
.
target
);
var
astNode
=
parser
.
getAst
();
if
(
astNode
===
null
)
{
this
.
checkOtherSegmentsIndex
=
0
;
return
;
}
if
(
astNode
.
type
===
'error'
)
{
this
.
error
=
astNode
.
message
+
" at position: "
+
astNode
.
pos
;
this
.
target
.
textEditor
=
true
;
return
;
}
try
{
this
.
parseTargetRecursive
(
astNode
,
null
,
0
);
}
catch
(
err
)
{
console
.
log
(
'error parsing target:'
,
err
.
message
);
this
.
error
=
err
.
message
;
this
.
target
.
textEditor
=
true
;
}
this
.
checkOtherSegmentsIndex
=
this
.
segments
.
length
-
1
;
this
.
checkForSeriesByTag
();
}
checkForSeriesByTag
()
{
let
seriesByTagFunc
=
_
.
find
(
this
.
functions
,
(
func
)
=>
func
.
def
.
name
===
'seriesByTag'
);
if
(
seriesByTagFunc
)
{
this
.
seriesByTagUsed
=
true
;
seriesByTagFunc
.
hidden
=
true
;
let
tags
=
this
.
splitSeriesByTagParams
(
seriesByTagFunc
);
this
.
tags
=
tags
;
}
}
getSegmentPathUpTo
(
index
)
{
var
arr
=
this
.
segments
.
slice
(
0
,
index
);
return
_
.
reduce
(
arr
,
function
(
result
,
segment
)
{
return
result
?
(
result
+
"."
+
segment
.
value
)
:
segment
.
value
;
},
""
);
}
parseTargetRecursive
(
astNode
,
func
,
index
)
{
if
(
astNode
===
null
)
{
return
null
;
}
switch
(
astNode
.
type
)
{
case
'function'
:
var
innerFunc
=
gfunc
.
createFuncInstance
(
astNode
.
name
,
{
withDefaultParams
:
false
});
_
.
each
(
astNode
.
params
,
(
param
,
index
)
=>
{
this
.
parseTargetRecursive
(
param
,
innerFunc
,
index
);
});
innerFunc
.
updateText
();
this
.
functions
.
push
(
innerFunc
);
break
;
case
'series-ref'
:
this
.
addFunctionParameter
(
func
,
astNode
.
value
,
index
,
this
.
segments
.
length
>
0
);
break
;
case
'bool'
:
case
'string'
:
case
'number'
:
if
((
index
-
1
)
>=
func
.
def
.
params
.
length
)
{
throw
{
message
:
'invalid number of parameters to method '
+
func
.
def
.
name
};
}
var
shiftBack
=
this
.
isShiftParamsBack
(
func
);
this
.
addFunctionParameter
(
func
,
astNode
.
value
,
index
,
shiftBack
);
break
;
case
'metric'
:
if
(
this
.
segments
.
length
>
0
)
{
if
(
astNode
.
segments
.
length
!==
1
)
{
throw
{
message
:
'Multiple metric params not supported, use text editor.'
};
}
this
.
addFunctionParameter
(
func
,
astNode
.
segments
[
0
].
value
,
index
,
true
);
break
;
}
this
.
segments
=
astNode
.
segments
;
}
}
isShiftParamsBack
(
func
)
{
return
func
.
def
.
name
!==
'seriesByTag'
;
}
updateSegmentValue
(
segment
,
index
)
{
this
.
segments
[
index
].
value
=
segment
.
value
;
}
addSelectMetricSegment
()
{
this
.
segments
.
push
({
value
:
"select metric"
});
}
addFunction
(
newFunc
)
{
this
.
functions
.
push
(
newFunc
);
this
.
moveAliasFuncLast
();
}
moveAliasFuncLast
()
{
var
aliasFunc
=
_
.
find
(
this
.
functions
,
function
(
func
)
{
return
func
.
def
.
name
===
'alias'
||
func
.
def
.
name
===
'aliasByNode'
||
func
.
def
.
name
===
'aliasByMetric'
;
});
if
(
aliasFunc
)
{
this
.
functions
=
_
.
without
(
this
.
functions
,
aliasFunc
);
this
.
functions
.
push
(
aliasFunc
);
}
}
addFunctionParameter
(
func
,
value
,
index
,
shiftBack
)
{
if
(
shiftBack
)
{
index
=
Math
.
max
(
index
-
1
,
0
);
}
func
.
params
[
index
]
=
value
;
}
removeFunction
(
func
)
{
this
.
functions
=
_
.
without
(
this
.
functions
,
func
);
}
updateModelTarget
(
targets
)
{
// render query
if
(
!
this
.
target
.
textEditor
)
{
var
metricPath
=
this
.
getSegmentPathUpTo
(
this
.
segments
.
length
);
this
.
target
.
target
=
_
.
reduce
(
this
.
functions
,
wrapFunction
,
metricPath
);
}
this
.
updateRenderedTarget
(
this
.
target
,
targets
);
// loop through other queries and update targetFull as needed
for
(
const
target
of
targets
||
[])
{
if
(
target
.
refId
!==
this
.
target
.
refId
)
{
this
.
updateRenderedTarget
(
target
,
targets
);
}
}
}
updateRenderedTarget
(
target
,
targets
)
{
// render nested query
var
targetsByRefId
=
_
.
keyBy
(
targets
,
'refId'
);
// no references to self
delete
targetsByRefId
[
target
.
refId
];
var
nestedSeriesRefRegex
=
/
\#([
A-Z
])
/g
;
var
targetWithNestedQueries
=
target
.
target
;
// Keep interpolating until there are no query references
// The reason for the loop is that the referenced query might contain another reference to another query
while
(
targetWithNestedQueries
.
match
(
nestedSeriesRefRegex
))
{
var
updated
=
targetWithNestedQueries
.
replace
(
nestedSeriesRefRegex
,
(
match
,
g1
)
=>
{
var
t
=
targetsByRefId
[
g1
];
if
(
!
t
)
{
return
match
;
}
// no circular references
delete
targetsByRefId
[
g1
];
return
t
.
target
;
});
if
(
updated
===
targetWithNestedQueries
)
{
break
;
}
targetWithNestedQueries
=
updated
;
}
delete
target
.
targetFull
;
if
(
target
.
target
!==
targetWithNestedQueries
)
{
target
.
targetFull
=
targetWithNestedQueries
;
}
}
splitSeriesByTagParams
(
func
)
{
const
tagPattern
=
/
([^\!
=~
]
+
)([\!
=~
]
+
)([^\!
=~
]
+
)
/
;
return
_
.
flatten
(
_
.
map
(
func
.
params
,
(
param
:
string
)
=>
{
let
matches
=
tagPattern
.
exec
(
param
);
if
(
matches
)
{
let
tag
=
matches
.
slice
(
1
);
if
(
tag
.
length
===
3
)
{
return
{
key
:
tag
[
0
],
operator
:
tag
[
1
],
value
:
tag
[
2
]
};
}
}
return
[];
}));
}
getSeriesByTagFuncIndex
()
{
return
_
.
findIndex
(
this
.
functions
,
(
func
)
=>
func
.
def
.
name
===
'seriesByTag'
);
}
getSeriesByTagFunc
()
{
let
seriesByTagFuncIndex
=
this
.
getSeriesByTagFuncIndex
();
if
(
seriesByTagFuncIndex
>=
0
)
{
return
this
.
functions
[
seriesByTagFuncIndex
];
}
else
{
return
undefined
;
}
}
addTag
(
tag
)
{
let
newTagParam
=
renderTagString
(
tag
);
this
.
getSeriesByTagFunc
().
params
.
push
(
newTagParam
);
this
.
tags
.
push
(
tag
);
}
removeTag
(
index
)
{
this
.
getSeriesByTagFunc
().
params
.
splice
(
index
,
1
);
this
.
tags
.
splice
(
index
,
1
);
}
updateTag
(
tag
,
tagIndex
)
{
this
.
error
=
null
;
if
(
tag
.
key
===
this
.
removeTagValue
)
{
this
.
removeTag
(
tagIndex
);
return
;
}
let
newTagParam
=
renderTagString
(
tag
);
this
.
getSeriesByTagFunc
().
params
[
tagIndex
]
=
newTagParam
;
this
.
tags
[
tagIndex
]
=
tag
;
}
}
function
wrapFunction
(
target
,
func
)
{
return
func
.
render
(
target
);
}
function
renderTagString
(
tag
)
{
return
tag
.
key
+
tag
.
operator
+
tag
.
value
;
}
public/app/plugins/datasource/graphite/partials/query.editor.html
View file @
199d0d15
...
@@ -6,11 +6,11 @@
...
@@ -6,11 +6,11 @@
<div
ng-hide=
"ctrl.target.textEditor"
>
<div
ng-hide=
"ctrl.target.textEditor"
>
<div
class=
"gf-form-inline"
>
<div
class=
"gf-form-inline"
>
<div
class=
"gf-form"
ng-if=
"ctrl.seriesByTagUsed"
>
<div
class=
"gf-form"
ng-if=
"ctrl.
queryModel.
seriesByTagUsed"
>
<label
class=
"gf-form-label query-keyword"
>
seriesByTag
</label>
<label
class=
"gf-form-label query-keyword"
>
seriesByTag
</label>
</div>
</div>
<div
ng-repeat=
"tag in ctrl.tags"
class=
"gf-form"
>
<div
ng-repeat=
"tag in ctrl.
queryModel.
tags"
class=
"gf-form"
>
<gf-form-dropdown
model=
"tag.key"
lookup-text=
"false"
allow-custom=
"false"
label-mode=
"true"
css-class=
"query-segment-key"
<gf-form-dropdown
model=
"tag.key"
lookup-text=
"false"
allow-custom=
"false"
label-mode=
"true"
css-class=
"query-segment-key"
get-options=
"ctrl.getTags()"
get-options=
"ctrl.getTags()"
on-change=
"ctrl.tagChanged(tag, $index)"
>
on-change=
"ctrl.tagChanged(tag, $index)"
>
...
@@ -25,7 +25,7 @@
...
@@ -25,7 +25,7 @@
</gf-form-dropdown>
</gf-form-dropdown>
<label
class=
"gf-form-label query-keyword"
ng-if=
"ctrl.showDelimiter($index)"
>
,
</label>
<label
class=
"gf-form-label query-keyword"
ng-if=
"ctrl.showDelimiter($index)"
>
,
</label>
</div>
</div>
<div
ng-if=
"ctrl.seriesByTagUsed"
ng-repeat=
"segment in ctrl.addTagSegments"
role=
"menuitem"
class=
"gf-form"
>
<div
ng-if=
"ctrl.
queryModel.
seriesByTagUsed"
ng-repeat=
"segment in ctrl.addTagSegments"
role=
"menuitem"
class=
"gf-form"
>
<metric-segment
segment=
"segment"
<metric-segment
segment=
"segment"
get-options=
"ctrl.getTagsAsSegments()"
get-options=
"ctrl.getTagsAsSegments()"
on-change=
"ctrl.addNewTag(segment)"
>
on-change=
"ctrl.addNewTag(segment)"
>
...
@@ -36,8 +36,8 @@
...
@@ -36,8 +36,8 @@
<metric-segment
segment=
"segment"
get-options=
"ctrl.getAltSegments($index)"
on-change=
"ctrl.segmentValueChanged(segment, $index)"
></metric-segment>
<metric-segment
segment=
"segment"
get-options=
"ctrl.getAltSegments($index)"
on-change=
"ctrl.segmentValueChanged(segment, $index)"
></metric-segment>
</div>
</div>
<div
ng-repeat=
"func in ctrl.functions"
class=
"gf-form"
>
<div
ng-repeat=
"func in ctrl.
queryModel.
functions"
class=
"gf-form"
>
<span
graphite-func-editor
class=
"gf-form-label query-part"
ng-hide=
"
ctrl.getSeriesByTagFuncIndex() === $index
"
></span>
<span
graphite-func-editor
class=
"gf-form-label query-part"
ng-hide=
"
func.hidden
"
></span>
</div>
</div>
<div
class=
"gf-form dropdown"
>
<div
class=
"gf-form dropdown"
>
...
...
public/app/plugins/datasource/graphite/query_ctrl.ts
View file @
199d0d15
This diff is collapsed.
Click to expand it.
public/app/plugins/datasource/graphite/specs/query_ctrl_specs.ts
View file @
199d0d15
...
@@ -48,7 +48,7 @@ describe('GraphiteQueryCtrl', function() {
...
@@ -48,7 +48,7 @@ describe('GraphiteQueryCtrl', function() {
});
});
it
(
'should parse expression and build function model'
,
function
()
{
it
(
'should parse expression and build function model'
,
function
()
{
expect
(
ctx
.
ctrl
.
functions
.
length
).
to
.
be
(
2
);
expect
(
ctx
.
ctrl
.
queryModel
.
functions
.
length
).
to
.
be
(
2
);
});
});
});
});
...
@@ -61,7 +61,7 @@ describe('GraphiteQueryCtrl', function() {
...
@@ -61,7 +61,7 @@ describe('GraphiteQueryCtrl', function() {
});
});
it
(
'should add function with correct node number'
,
function
()
{
it
(
'should add function with correct node number'
,
function
()
{
expect
(
ctx
.
ctrl
.
functions
[
0
].
params
[
0
]).
to
.
be
(
2
);
expect
(
ctx
.
ctrl
.
queryModel
.
functions
[
0
].
params
[
0
]).
to
.
be
(
2
);
});
});
it
(
'should update target'
,
function
()
{
it
(
'should update target'
,
function
()
{
...
@@ -99,7 +99,7 @@ describe('GraphiteQueryCtrl', function() {
...
@@ -99,7 +99,7 @@ describe('GraphiteQueryCtrl', function() {
});
});
it
(
'should add both series refs as params'
,
function
()
{
it
(
'should add both series refs as params'
,
function
()
{
expect
(
ctx
.
ctrl
.
functions
[
0
].
params
.
length
).
to
.
be
(
2
);
expect
(
ctx
.
ctrl
.
queryModel
.
functions
[
0
].
params
.
length
).
to
.
be
(
2
);
});
});
});
});
...
@@ -115,7 +115,7 @@ describe('GraphiteQueryCtrl', function() {
...
@@ -115,7 +115,7 @@ describe('GraphiteQueryCtrl', function() {
});
});
it
(
'should add function param'
,
function
()
{
it
(
'should add function param'
,
function
()
{
expect
(
ctx
.
ctrl
.
functions
[
0
].
params
.
length
).
to
.
be
(
1
);
expect
(
ctx
.
ctrl
.
queryModel
.
functions
[
0
].
params
.
length
).
to
.
be
(
1
);
});
});
});
});
...
@@ -131,7 +131,7 @@ describe('GraphiteQueryCtrl', function() {
...
@@ -131,7 +131,7 @@ describe('GraphiteQueryCtrl', function() {
});
});
it
(
'should have correct func params'
,
function
()
{
it
(
'should have correct func params'
,
function
()
{
expect
(
ctx
.
ctrl
.
functions
[
0
].
params
.
length
).
to
.
be
(
1
);
expect
(
ctx
.
ctrl
.
queryModel
.
functions
[
0
].
params
.
length
).
to
.
be
(
1
);
});
});
});
});
...
@@ -219,11 +219,11 @@ describe('GraphiteQueryCtrl', function() {
...
@@ -219,11 +219,11 @@ describe('GraphiteQueryCtrl', function() {
});
});
it
(
'should update functions'
,
function
()
{
it
(
'should update functions'
,
function
()
{
expect
(
ctx
.
ctrl
.
getSeriesByTagFuncIndex
()).
to
.
be
(
0
);
expect
(
ctx
.
ctrl
.
queryModel
.
getSeriesByTagFuncIndex
()).
to
.
be
(
0
);
});
});
it
(
'should update seriesByTagUsed flag'
,
function
()
{
it
(
'should update seriesByTagUsed flag'
,
function
()
{
expect
(
ctx
.
ctrl
.
seriesByTagUsed
).
to
.
be
(
true
);
expect
(
ctx
.
ctrl
.
queryModel
.
seriesByTagUsed
).
to
.
be
(
true
);
});
});
it
(
'should update target'
,
function
()
{
it
(
'should update target'
,
function
()
{
...
@@ -247,7 +247,7 @@ describe('GraphiteQueryCtrl', function() {
...
@@ -247,7 +247,7 @@ describe('GraphiteQueryCtrl', function() {
{
key
:
'tag1'
,
operator
:
'='
,
value
:
'value1'
},
{
key
:
'tag1'
,
operator
:
'='
,
value
:
'value1'
},
{
key
:
'tag2'
,
operator
:
'!=~'
,
value
:
'value2'
}
{
key
:
'tag2'
,
operator
:
'!=~'
,
value
:
'value2'
}
];
];
expect
(
ctx
.
ctrl
.
tags
).
to
.
eql
(
expected
);
expect
(
ctx
.
ctrl
.
queryModel
.
tags
).
to
.
eql
(
expected
);
});
});
it
(
'should add plus button'
,
function
()
{
it
(
'should add plus button'
,
function
()
{
...
@@ -267,7 +267,7 @@ describe('GraphiteQueryCtrl', function() {
...
@@ -267,7 +267,7 @@ describe('GraphiteQueryCtrl', function() {
const
expected
=
[
const
expected
=
[
{
key
:
'tag1'
,
operator
:
'='
,
value
:
'select tag value'
}
{
key
:
'tag1'
,
operator
:
'='
,
value
:
'select tag value'
}
];
];
expect
(
ctx
.
ctrl
.
tags
).
to
.
eql
(
expected
);
expect
(
ctx
.
ctrl
.
queryModel
.
tags
).
to
.
eql
(
expected
);
});
});
it
(
'should update target'
,
function
()
{
it
(
'should update target'
,
function
()
{
...
@@ -289,7 +289,7 @@ describe('GraphiteQueryCtrl', function() {
...
@@ -289,7 +289,7 @@ describe('GraphiteQueryCtrl', function() {
{
key
:
'tag1'
,
operator
:
'='
,
value
:
'new_value'
},
{
key
:
'tag1'
,
operator
:
'='
,
value
:
'new_value'
},
{
key
:
'tag2'
,
operator
:
'!=~'
,
value
:
'value2'
}
{
key
:
'tag2'
,
operator
:
'!=~'
,
value
:
'value2'
}
];
];
expect
(
ctx
.
ctrl
.
tags
).
to
.
eql
(
expected
);
expect
(
ctx
.
ctrl
.
queryModel
.
tags
).
to
.
eql
(
expected
);
});
});
it
(
'should update target'
,
function
()
{
it
(
'should update target'
,
function
()
{
...
@@ -310,7 +310,7 @@ describe('GraphiteQueryCtrl', function() {
...
@@ -310,7 +310,7 @@ describe('GraphiteQueryCtrl', function() {
const
expected
=
[
const
expected
=
[
{
key
:
'tag2'
,
operator
:
'!=~'
,
value
:
'value2'
}
{
key
:
'tag2'
,
operator
:
'!=~'
,
value
:
'value2'
}
];
];
expect
(
ctx
.
ctrl
.
tags
).
to
.
eql
(
expected
);
expect
(
ctx
.
ctrl
.
queryModel
.
tags
).
to
.
eql
(
expected
);
});
});
it
(
'should update target'
,
function
()
{
it
(
'should update target'
,
function
()
{
...
...
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