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
5aa91fc1
Unverified
Commit
5aa91fc1
authored
Oct 04, 2018
by
David
Committed by
GitHub
Oct 04, 2018
Browse files
Options
Browse Files
Download
Plain Diff
Merge pull request #13528 from grafana/davkal/fix-rate-hint
Explore: fix rate hint for series with null values
parents
1a6b0adb
107bef2d
Hide whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
189 additions
and
178 deletions
+189
-178
public/app/plugins/datasource/prometheus/datasource.ts
+2
-99
public/app/plugins/datasource/prometheus/query_hints.ts
+100
-0
public/app/plugins/datasource/prometheus/specs/datasource.test.ts
+0
-79
public/app/plugins/datasource/prometheus/specs/query_hints.test.ts
+87
-0
No files found.
public/app/plugins/datasource/prometheus/datasource.ts
View file @
5aa91fc1
...
...
@@ -8,6 +8,7 @@ import { ResultTransformer } from './result_transformer';
import
{
BackendSrv
}
from
'app/core/services/backend_srv'
;
import
addLabelToQuery
from
'./add_label_to_query'
;
import
{
getQueryHints
}
from
'./query_hints'
;
export
function
alignRange
(
start
,
end
,
step
)
{
const
alignedEnd
=
Math
.
ceil
(
end
/
step
)
*
step
;
...
...
@@ -18,104 +19,6 @@ export function alignRange(start, end, step) {
};
}
export
function
determineQueryHints
(
series
:
any
[],
datasource
?:
any
):
any
[]
{
const
hints
=
series
.
map
((
s
,
i
)
=>
{
const
query
:
string
=
s
.
query
;
const
index
:
number
=
s
.
responseIndex
;
if
(
query
===
undefined
||
index
===
undefined
)
{
return
null
;
}
// ..._bucket metric needs a histogram_quantile()
const
histogramMetric
=
query
.
trim
().
match
(
/^
\w
+_bucket$/
);
if
(
histogramMetric
)
{
const
label
=
'Time series has buckets, you probably wanted a histogram.'
;
return
{
index
,
label
,
fix
:
{
label
:
'Fix by adding histogram_quantile().'
,
action
:
{
type
:
'ADD_HISTOGRAM_QUANTILE'
,
query
,
index
,
},
},
};
}
// Check for monotony
const
datapoints
:
number
[][]
=
s
.
datapoints
;
if
(
query
.
indexOf
(
'rate('
)
===
-
1
&&
datapoints
.
length
>
1
)
{
let
increasing
=
false
;
const
monotonic
=
datapoints
.
filter
(
dp
=>
dp
[
0
]
!==
null
).
every
((
dp
,
index
)
=>
{
if
(
index
===
0
)
{
return
true
;
}
increasing
=
increasing
||
dp
[
0
]
>
datapoints
[
index
-
1
][
0
];
// monotonic?
return
dp
[
0
]
>=
datapoints
[
index
-
1
][
0
];
});
if
(
increasing
&&
monotonic
)
{
const
simpleMetric
=
query
.
trim
().
match
(
/^
\w
+$/
);
let
label
=
'Time series is monotonously increasing.'
;
let
fix
;
if
(
simpleMetric
)
{
fix
=
{
label
:
'Fix by adding rate().'
,
action
:
{
type
:
'ADD_RATE'
,
query
,
index
,
},
};
}
else
{
label
=
`
${
label
}
Try applying a rate() function.`
;
}
return
{
label
,
index
,
fix
,
};
}
}
// Check for recording rules expansion
if
(
datasource
&&
datasource
.
ruleMappings
)
{
const
mapping
=
datasource
.
ruleMappings
;
const
mappingForQuery
=
Object
.
keys
(
mapping
).
reduce
((
acc
,
ruleName
)
=>
{
if
(
query
.
search
(
ruleName
)
>
-
1
)
{
return
{
...
acc
,
[
ruleName
]:
mapping
[
ruleName
],
};
}
return
acc
;
},
{});
if
(
_
.
size
(
mappingForQuery
)
>
0
)
{
const
label
=
'Query contains recording rules.'
;
return
{
label
,
index
,
fix
:
{
label
:
'Expand rules'
,
action
:
{
type
:
'EXPAND_RULES'
,
query
,
index
,
mapping
:
mappingForQuery
,
},
},
};
}
}
// No hint found
return
null
;
});
return
hints
;
}
export
function
extractRuleMappingFromGroups
(
groups
:
any
[])
{
return
groups
.
reduce
(
(
mapping
,
group
)
=>
...
...
@@ -300,7 +203,7 @@ export class PrometheusDatasource {
result = [...result, ...series];
if (queries[index].hinting) {
const queryHints =
determine
QueryHints(series, this);
const queryHints =
get
QueryHints(series, this);
hints = [...hints, ...queryHints];
}
});
...
...
public/app/plugins/datasource/prometheus/query_hints.ts
0 → 100644
View file @
5aa91fc1
import
_
from
'lodash'
;
export
function
getQueryHints
(
series
:
any
[],
datasource
?:
any
):
any
[]
{
const
hints
=
series
.
map
((
s
,
i
)
=>
{
const
query
:
string
=
s
.
query
;
const
index
:
number
=
s
.
responseIndex
;
if
(
query
===
undefined
||
index
===
undefined
)
{
return
null
;
}
// ..._bucket metric needs a histogram_quantile()
const
histogramMetric
=
query
.
trim
().
match
(
/^
\w
+_bucket$/
);
if
(
histogramMetric
)
{
const
label
=
'Time series has buckets, you probably wanted a histogram.'
;
return
{
index
,
label
,
fix
:
{
label
:
'Fix by adding histogram_quantile().'
,
action
:
{
type
:
'ADD_HISTOGRAM_QUANTILE'
,
query
,
index
,
},
},
};
}
// Check for monotony
const
datapoints
:
number
[][]
=
s
.
datapoints
;
if
(
query
.
indexOf
(
'rate('
)
===
-
1
&&
datapoints
.
length
>
1
)
{
let
increasing
=
false
;
const
nonNullData
=
datapoints
.
filter
(
dp
=>
dp
[
0
]
!==
null
);
const
monotonic
=
nonNullData
.
every
((
dp
,
index
)
=>
{
if
(
index
===
0
)
{
return
true
;
}
increasing
=
increasing
||
dp
[
0
]
>
nonNullData
[
index
-
1
][
0
];
// monotonic?
return
dp
[
0
]
>=
nonNullData
[
index
-
1
][
0
];
});
if
(
increasing
&&
monotonic
)
{
const
simpleMetric
=
query
.
trim
().
match
(
/^
\w
+$/
);
let
label
=
'Time series is monotonously increasing.'
;
let
fix
;
if
(
simpleMetric
)
{
fix
=
{
label
:
'Fix by adding rate().'
,
action
:
{
type
:
'ADD_RATE'
,
query
,
index
,
},
};
}
else
{
label
=
`
${
label
}
Try applying a rate() function.`
;
}
return
{
label
,
index
,
fix
,
};
}
}
// Check for recording rules expansion
if
(
datasource
&&
datasource
.
ruleMappings
)
{
const
mapping
=
datasource
.
ruleMappings
;
const
mappingForQuery
=
Object
.
keys
(
mapping
).
reduce
((
acc
,
ruleName
)
=>
{
if
(
query
.
search
(
ruleName
)
>
-
1
)
{
return
{
...
acc
,
[
ruleName
]:
mapping
[
ruleName
],
};
}
return
acc
;
},
{});
if
(
_
.
size
(
mappingForQuery
)
>
0
)
{
const
label
=
'Query contains recording rules.'
;
return
{
label
,
index
,
fix
:
{
label
:
'Expand rules'
,
action
:
{
type
:
'EXPAND_RULES'
,
query
,
index
,
mapping
:
mappingForQuery
,
},
},
};
}
}
// No hint found
return
null
;
});
return
hints
;
}
public/app/plugins/datasource/prometheus/specs/datasource.test.ts
View file @
5aa91fc1
...
...
@@ -3,7 +3,6 @@ import moment from 'moment';
import
q
from
'q'
;
import
{
alignRange
,
determineQueryHints
,
extractRuleMappingFromGroups
,
PrometheusDatasource
,
prometheusSpecialRegexEscape
,
...
...
@@ -216,84 +215,6 @@ describe('PrometheusDatasource', () => {
});
});
describe
(
'determineQueryHints()'
,
()
=>
{
it
(
'returns no hints for no series'
,
()
=>
{
expect
(
determineQueryHints
([])).
toEqual
([]);
});
it
(
'returns no hints for empty series'
,
()
=>
{
expect
(
determineQueryHints
([{
datapoints
:
[],
query
:
''
}])).
toEqual
([
null
]);
});
it
(
'returns no hint for a monotonously decreasing series'
,
()
=>
{
const
series
=
[{
datapoints
:
[[
23
,
1000
],
[
22
,
1001
]],
query
:
'metric'
,
responseIndex
:
0
}];
const
hints
=
determineQueryHints
(
series
);
expect
(
hints
).
toEqual
([
null
]);
});
it
(
'returns a rate hint for a monotonously increasing series'
,
()
=>
{
const
series
=
[{
datapoints
:
[[
23
,
1000
],
[
24
,
1001
]],
query
:
'metric'
,
responseIndex
:
0
}];
const
hints
=
determineQueryHints
(
series
);
expect
(
hints
.
length
).
toBe
(
1
);
expect
(
hints
[
0
]).
toMatchObject
({
label
:
'Time series is monotonously increasing.'
,
index
:
0
,
fix
:
{
action
:
{
type
:
'ADD_RATE'
,
query
:
'metric'
,
},
},
});
});
it
(
'returns no rate hint for a monotonously increasing series that already has a rate'
,
()
=>
{
const
series
=
[{
datapoints
:
[[
23
,
1000
],
[
24
,
1001
]],
query
:
'rate(metric[1m])'
,
responseIndex
:
0
}];
const
hints
=
determineQueryHints
(
series
);
expect
(
hints
).
toEqual
([
null
]);
});
it
(
'returns a rate hint w/o action for a complex monotonously increasing series'
,
()
=>
{
const
series
=
[{
datapoints
:
[[
23
,
1000
],
[
24
,
1001
]],
query
:
'sum(metric)'
,
responseIndex
:
0
}];
const
hints
=
determineQueryHints
(
series
);
expect
(
hints
.
length
).
toBe
(
1
);
expect
(
hints
[
0
].
label
).
toContain
(
'rate()'
);
expect
(
hints
[
0
].
fix
).
toBeUndefined
();
});
it
(
'returns a rate hint for a monotonously increasing series with missing data'
,
()
=>
{
const
series
=
[{
datapoints
:
[[
23
,
1000
],
[
null
,
1001
],
[
24
,
1002
]],
query
:
'metric'
,
responseIndex
:
0
}];
const
hints
=
determineQueryHints
(
series
);
expect
(
hints
.
length
).
toBe
(
1
);
expect
(
hints
[
0
]).
toMatchObject
({
label
:
'Time series is monotonously increasing.'
,
index
:
0
,
fix
:
{
action
:
{
type
:
'ADD_RATE'
,
query
:
'metric'
,
},
},
});
});
it
(
'returns a histogram hint for a bucket series'
,
()
=>
{
const
series
=
[{
datapoints
:
[[
23
,
1000
]],
query
:
'metric_bucket'
,
responseIndex
:
0
}];
const
hints
=
determineQueryHints
(
series
);
expect
(
hints
.
length
).
toBe
(
1
);
expect
(
hints
[
0
]).
toMatchObject
({
label
:
'Time series has buckets, you probably wanted a histogram.'
,
index
:
0
,
fix
:
{
action
:
{
type
:
'ADD_HISTOGRAM_QUANTILE'
,
query
:
'metric_bucket'
,
},
},
});
});
});
describe
(
'extractRuleMappingFromGroups()'
,
()
=>
{
it
(
'returns empty mapping for no rule groups'
,
()
=>
{
expect
(
extractRuleMappingFromGroups
([])).
toEqual
({});
...
...
public/app/plugins/datasource/prometheus/specs/query_hints.test.ts
0 → 100644
View file @
5aa91fc1
import
{
getQueryHints
}
from
'../query_hints'
;
describe
(
'getQueryHints()'
,
()
=>
{
it
(
'returns no hints for no series'
,
()
=>
{
expect
(
getQueryHints
([])).
toEqual
([]);
});
it
(
'returns no hints for empty series'
,
()
=>
{
expect
(
getQueryHints
([{
datapoints
:
[],
query
:
''
}])).
toEqual
([
null
]);
});
it
(
'returns no hint for a monotonously decreasing series'
,
()
=>
{
const
series
=
[{
datapoints
:
[[
23
,
1000
],
[
22
,
1001
]],
query
:
'metric'
,
responseIndex
:
0
}];
const
hints
=
getQueryHints
(
series
);
expect
(
hints
).
toEqual
([
null
]);
});
it
(
'returns no hint for a flat series'
,
()
=>
{
const
series
=
[
{
datapoints
:
[[
null
,
1000
],
[
23
,
1001
],
[
null
,
1002
],
[
23
,
1003
]],
query
:
'metric'
,
responseIndex
:
0
},
];
const
hints
=
getQueryHints
(
series
);
expect
(
hints
).
toEqual
([
null
]);
});
it
(
'returns a rate hint for a monotonously increasing series'
,
()
=>
{
const
series
=
[{
datapoints
:
[[
23
,
1000
],
[
24
,
1001
]],
query
:
'metric'
,
responseIndex
:
0
}];
const
hints
=
getQueryHints
(
series
);
expect
(
hints
.
length
).
toBe
(
1
);
expect
(
hints
[
0
]).
toMatchObject
({
label
:
'Time series is monotonously increasing.'
,
index
:
0
,
fix
:
{
action
:
{
type
:
'ADD_RATE'
,
query
:
'metric'
,
},
},
});
});
it
(
'returns no rate hint for a monotonously increasing series that already has a rate'
,
()
=>
{
const
series
=
[{
datapoints
:
[[
23
,
1000
],
[
24
,
1001
]],
query
:
'rate(metric[1m])'
,
responseIndex
:
0
}];
const
hints
=
getQueryHints
(
series
);
expect
(
hints
).
toEqual
([
null
]);
});
it
(
'returns a rate hint w/o action for a complex monotonously increasing series'
,
()
=>
{
const
series
=
[{
datapoints
:
[[
23
,
1000
],
[
24
,
1001
]],
query
:
'sum(metric)'
,
responseIndex
:
0
}];
const
hints
=
getQueryHints
(
series
);
expect
(
hints
.
length
).
toBe
(
1
);
expect
(
hints
[
0
].
label
).
toContain
(
'rate()'
);
expect
(
hints
[
0
].
fix
).
toBeUndefined
();
});
it
(
'returns a rate hint for a monotonously increasing series with missing data'
,
()
=>
{
const
series
=
[{
datapoints
:
[[
23
,
1000
],
[
null
,
1001
],
[
24
,
1002
]],
query
:
'metric'
,
responseIndex
:
0
}];
const
hints
=
getQueryHints
(
series
);
expect
(
hints
.
length
).
toBe
(
1
);
expect
(
hints
[
0
]).
toMatchObject
({
label
:
'Time series is monotonously increasing.'
,
index
:
0
,
fix
:
{
action
:
{
type
:
'ADD_RATE'
,
query
:
'metric'
,
},
},
});
});
it
(
'returns a histogram hint for a bucket series'
,
()
=>
{
const
series
=
[{
datapoints
:
[[
23
,
1000
]],
query
:
'metric_bucket'
,
responseIndex
:
0
}];
const
hints
=
getQueryHints
(
series
);
expect
(
hints
.
length
).
toBe
(
1
);
expect
(
hints
[
0
]).
toMatchObject
({
label
:
'Time series has buckets, you probably wanted a histogram.'
,
index
:
0
,
fix
:
{
action
:
{
type
:
'ADD_HISTOGRAM_QUANTILE'
,
query
:
'metric_bucket'
,
},
},
});
});
});
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