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
4cf76583
Unverified
Commit
4cf76583
authored
Feb 18, 2020
by
Sebastian Poxhofer
Committed by
GitHub
Feb 18, 2020
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Prometheus: Implement region annotation (#22225)
parent
6ad83752
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
124 additions
and
25 deletions
+124
-25
public/app/plugins/datasource/prometheus/datasource.test.ts
+78
-1
public/app/plugins/datasource/prometheus/datasource.ts
+46
-24
No files found.
public/app/plugins/datasource/prometheus/datasource.test.ts
View file @
4cf76583
...
...
@@ -735,7 +735,7 @@ describe('PrometheusDatasource', () => {
});
});
describe('
When
performing
annotationQuery
', () => {
describe('
annotationQuery
', () => {
let results: any;
const options: any = {
annotation: {
...
...
@@ -905,6 +905,83 @@ describe('PrometheusDatasource', () => {
expect(req.url).toContain(`step=${step}`);
});
});
describe('
region
annotations
for
sectors
', () => {
const options: any = {
annotation: {
expr: '
ALERTS
{
alertstate
=
"firing"
}
',
tagKeys: '
job
',
titleFormat: '
{{
alertname
}}
',
textFormat: '
{{
instance
}}
',
},
range: {
from: time({ seconds: 63 }),
to: time({ seconds: 900 }),
},
};
async function runAnnotationQuery(resultValues: Array<[number, string]>) {
const response = {
status: '
success
',
data: {
data: {
resultType: '
matrix
',
result: [
{
metric: { __name__: '
test
', job: '
testjob
' },
values: resultValues,
},
],
},
},
};
options.annotation.useValueForTime = false;
datasourceRequestMock.mockImplementation(() => Promise.resolve(response));
return ds.annotationQuery(options);
}
it('
should
handle
gaps
and
inactive
values
', async () => {
const results = await runAnnotationQuery([
[2 * 60, '
1
'],
[3 * 60, '
1
'],
// gap
[5 * 60, '
1
'],
[6 * 60, '
1
'],
[7 * 60, '
1
'],
[8 * 60, '
0
'], // false --> create new block
[9 * 60, '
1
'],
]);
expect(results.map(result => [result.time, result.timeEnd])).toEqual([
[120000, 180000],
[300000, 420000],
[540000, 540000],
]);
});
it('
should
handle
single
region
', async () => {
const results = await runAnnotationQuery([
[2 * 60, '
1
'],
[3 * 60, '
1
'],
]);
expect(results.map(result => [result.time, result.timeEnd])).toEqual([[120000, 180000]]);
});
it('
should
handle
0
active
regions
', async () => {
const results = await runAnnotationQuery([
[2 * 60, '
0
'],
[3 * 60, '
0
'],
[5 * 60, '
0
'],
]);
expect(results.length).toBe(0);
});
it('
should
handle
single
active
value
', async () => {
const results = await runAnnotationQuery([[2 * 60, '
1
']]);
expect(results.map(result => [result.time, result.timeEnd])).toEqual([[120000, 120000]]);
});
});
});
describe('
createAnnotationQueryOptions
', () => {
...
...
public/app/plugins/datasource/prometheus/datasource.ts
View file @
4cf76583
...
...
@@ -538,7 +538,7 @@ export class PrometheusDatasource extends DataSourceApi<PromQuery, PromOptions>
};
};
async
annotationQuery
(
options
:
any
)
{
async
annotationQuery
(
options
:
any
)
:
Promise
<
AnnotationEvent
[]
>
{
const
annotation
=
options
.
annotation
;
const
{
expr
=
''
,
tagKeys
=
''
,
titleFormat
=
''
,
textFormat
=
''
}
=
annotation
;
...
...
@@ -570,35 +570,57 @@ export class PrometheusDatasource extends DataSourceApi<PromQuery, PromOptions>
return
[];
}
const
step
=
Math
.
floor
(
query
.
step
)
*
1000
;
response
?.
data
?.
data
?.
result
?.
forEach
(
series
=>
{
const
tags
=
Object
.
entries
(
series
.
metric
)
.
filter
(([
k
])
=>
splitKeys
.
includes
(
k
))
.
map
(([
_k
,
v
]:
[
string
,
string
])
=>
v
);
const
dupCheck
:
Record
<
number
,
boolean
>
=
{};
for
(
const
value
of
series
.
values
)
{
const
valueIsTrue
=
value
[
1
]
===
'1'
;
// e.g. ALERTS
if
(
valueIsTrue
||
annotation
.
useValueForTime
)
{
const
event
:
AnnotationEvent
=
{
annotation
,
title
:
self
.
resultTransformer
.
renderTemplate
(
titleFormat
,
series
.
metric
),
tags
,
text
:
self
.
resultTransformer
.
renderTemplate
(
textFormat
,
series
.
metric
),
};
if
(
annotation
.
useValueForTime
)
{
const
timestampValue
=
Math
.
floor
(
parseFloat
(
value
[
1
]));
if
(
dupCheck
[
timestampValue
])
{
continue
;
}
dupCheck
[
timestampValue
]
=
true
;
event
.
time
=
timestampValue
;
}
else
{
event
.
time
=
Math
.
floor
(
parseFloat
(
value
[
0
]))
*
1000
;
}
eventList
.
push
(
event
);
series
.
values
.
forEach
((
value
:
any
[])
=>
{
let
timestampValue
;
// rewrite timeseries to a common format
if
(
annotation
.
useValueForTime
)
{
timestampValue
=
Math
.
floor
(
parseFloat
(
value
[
1
]));
value
[
1
]
=
1
;
}
else
{
timestampValue
=
Math
.
floor
(
parseFloat
(
value
[
0
]))
*
1000
;
}
value
[
0
]
=
timestampValue
;
});
const
activeValues
=
series
.
values
.
filter
((
value
:
Record
<
number
,
string
>
)
=>
parseFloat
(
value
[
1
])
>=
1
);
const
activeValuesTimestamps
=
activeValues
.
map
((
value
:
number
[])
=>
value
[
0
]);
// Instead of creating singular annotation for each active event we group events into region if they are less
// then `step` apart.
let
latestEvent
:
AnnotationEvent
=
null
;
activeValuesTimestamps
.
forEach
((
timestamp
:
number
)
=>
{
// We already have event `open` and we have new event that is inside the `step` so we just update the end.
if
(
latestEvent
&&
latestEvent
.
timeEnd
+
step
>=
timestamp
)
{
latestEvent
.
timeEnd
=
timestamp
;
return
;
}
// Event exists but new one is outside of the `step` so we "finish" the current region.
if
(
latestEvent
)
{
eventList
.
push
(
latestEvent
);
}
// We start a new region.
latestEvent
=
{
time
:
timestamp
,
timeEnd
:
timestamp
,
annotation
,
title
:
self
.
resultTransformer
.
renderTemplate
(
titleFormat
,
series
.
metric
),
tags
,
text
:
self
.
resultTransformer
.
renderTemplate
(
textFormat
,
series
.
metric
),
};
});
if
(
latestEvent
)
{
// finish up last point if we have one
latestEvent
.
timeEnd
=
activeValuesTimestamps
[
activeValuesTimestamps
.
length
-
1
];
eventList
.
push
(
latestEvent
);
}
});
...
...
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