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
1500c0e9
Commit
1500c0e9
authored
Jun 11, 2016
by
Torkel Ödegaard
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
feat(alerting): alert threshold handles progress
parent
f387e39b
Hide whitespace changes
Inline
Side-by-side
Showing
14 changed files
with
217 additions
and
167 deletions
+217
-167
pkg/services/alerting/alert_rule.go
+6
-2
pkg/services/alerting/commands.go
+0
-56
pkg/services/alerting/extractor_test.go
+2
-2
pkg/services/alerting/reader.go
+1
-1
pkg/services/sqlstore/alert_rule_parser_test.go
+0
-55
public/app/features/dashboard/viewStateSrv.js
+13
-10
public/app/features/panel/panel_ctrl.ts
+2
-2
public/app/plugins/panel/graph/alert_tab_ctrl.ts
+29
-17
public/app/plugins/panel/graph/graph.js
+56
-0
public/app/plugins/panel/graph/jquery.flot.alerts.ts
+47
-8
public/app/plugins/panel/graph/partials/tab_alerting.html
+3
-3
public/sass/_variables.dark.scss
+1
-1
public/sass/components/_panel_graph.scss
+57
-4
public/sass/pages/_dashboard.scss
+0
-6
No files found.
pkg/services/alerting/alert_rule.go
View file @
1500c0e9
...
...
@@ -25,6 +25,10 @@ type AlertRule struct {
Transformer
Transformer
}
func
getTimeDurationStringToSeconds
(
str
string
)
int64
{
return
60
}
func
NewAlertRuleFromDBModel
(
ruleDef
*
m
.
Alert
)
(
*
AlertRule
,
error
)
{
model
:=
&
AlertRule
{}
model
.
Id
=
ruleDef
.
Id
...
...
@@ -39,13 +43,13 @@ func NewAlertRuleFromDBModel(ruleDef *m.Alert) (*AlertRule, error) {
Level
:
critical
.
Get
(
"level"
)
.
MustFloat64
(),
}
warning
:=
ruleDef
.
Expression
.
Get
(
"warn
ing
"
)
warning
:=
ruleDef
.
Expression
.
Get
(
"warn"
)
model
.
Warning
=
Level
{
Operator
:
warning
.
Get
(
"op"
)
.
MustString
(),
Level
:
warning
.
Get
(
"level"
)
.
MustFloat64
(),
}
model
.
Frequency
=
ruleDef
.
Expression
.
Get
(
"frequency"
)
.
MustInt64
(
)
model
.
Frequency
=
getTimeDurationStringToSeconds
(
ruleDef
.
Expression
.
Get
(
"frequency"
)
.
MustString
()
)
model
.
Transform
=
ruleDef
.
Expression
.
Get
(
"transform"
)
.
Get
(
"type"
)
.
MustString
()
model
.
TransformParams
=
*
ruleDef
.
Expression
.
Get
(
"transform"
)
...
...
pkg/services/alerting/commands.go
View file @
1500c0e9
package
alerting
import
(
"fmt"
"github.com/grafana/grafana/pkg/bus"
m
"github.com/grafana/grafana/pkg/models"
)
...
...
@@ -38,57 +36,3 @@ func updateDashboardAlerts(cmd *UpdateDashboardAlertsCommand) error {
return
nil
}
func
getTimeDurationStringToSeconds
(
str
string
)
int64
{
return
60
}
func
ConvetAlertModelToAlertRule
(
ruleDef
*
m
.
Alert
)
(
*
AlertRule
,
error
)
{
model
:=
&
AlertRule
{}
model
.
Id
=
ruleDef
.
Id
model
.
OrgId
=
ruleDef
.
OrgId
model
.
Name
=
ruleDef
.
Name
model
.
Description
=
ruleDef
.
Description
model
.
State
=
ruleDef
.
State
critical
:=
ruleDef
.
Expression
.
Get
(
"critical"
)
model
.
Critical
=
Level
{
Operator
:
critical
.
Get
(
"op"
)
.
MustString
(),
Level
:
critical
.
Get
(
"level"
)
.
MustFloat64
(),
}
warning
:=
ruleDef
.
Expression
.
Get
(
"warning"
)
model
.
Warning
=
Level
{
Operator
:
warning
.
Get
(
"op"
)
.
MustString
(),
Level
:
warning
.
Get
(
"level"
)
.
MustFloat64
(),
}
model
.
Frequency
=
getTimeDurationStringToSeconds
(
ruleDef
.
Expression
.
Get
(
"frequency"
)
.
MustString
())
model
.
Transform
=
ruleDef
.
Expression
.
Get
(
"transform"
)
.
Get
(
"type"
)
.
MustString
()
model
.
TransformParams
=
*
ruleDef
.
Expression
.
Get
(
"transform"
)
if
model
.
Transform
==
"aggregation"
{
model
.
Transformer
=
&
AggregationTransformer
{
Method
:
ruleDef
.
Expression
.
Get
(
"transform"
)
.
Get
(
"method"
)
.
MustString
(),
}
}
query
:=
ruleDef
.
Expression
.
Get
(
"query"
)
model
.
Query
=
AlertQuery
{
Query
:
query
.
Get
(
"query"
)
.
MustString
(),
DatasourceId
:
query
.
Get
(
"datasourceId"
)
.
MustInt64
(),
From
:
query
.
Get
(
"from"
)
.
MustString
(),
To
:
query
.
Get
(
"to"
)
.
MustString
(),
Aggregator
:
query
.
Get
(
"agg"
)
.
MustString
(),
}
if
model
.
Query
.
Query
==
""
{
return
nil
,
fmt
.
Errorf
(
"missing query.query"
)
}
if
model
.
Query
.
DatasourceId
==
0
{
return
nil
,
fmt
.
Errorf
(
"missing query.datasourceId"
)
}
return
model
,
nil
}
pkg/services/alerting/extractor_test.go
View file @
1500c0e9
...
...
@@ -55,7 +55,7 @@ func TestAlertRuleExtraction(t *testing.T) {
"method": "avg",
"type": "aggregation"
},
"warn
ing
": {
"warn": {
"level": 10,
"op": ">"
}
...
...
@@ -90,7 +90,7 @@ func TestAlertRuleExtraction(t *testing.T) {
"method": "avg",
"name": "aggregation"
},
"warn
ing
": {
"warn": {
"level": 10,
"op": ">"
}
...
...
pkg/services/alerting/reader.go
View file @
1500c0e9
...
...
@@ -49,7 +49,7 @@ func (arr *AlertRuleReader) Fetch() []*AlertRule {
res
:=
make
([]
*
AlertRule
,
len
(
cmd
.
Result
))
for
i
,
ruleDef
:=
range
cmd
.
Result
{
model
,
_
:=
ConvetAlertModelToAlertRule
(
ruleDef
)
model
,
_
:=
NewAlertRuleFromDBModel
(
ruleDef
)
res
[
i
]
=
model
}
...
...
pkg/services/sqlstore/alert_rule_parser_test.go
deleted
100644 → 0
View file @
f387e39b
package
sqlstore
import
(
"testing"
"github.com/grafana/grafana/pkg/components/simplejson"
m
"github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/services/alerting"
.
"github.com/smartystreets/goconvey/convey"
)
func
TestAlertRuleModelParsing
(
t
*
testing
.
T
)
{
Convey
(
"Parsing alertRule from expression"
,
t
,
func
()
{
alertRuleDAO
:=
&
m
.
Alert
{}
json
,
_
:=
simplejson
.
NewJson
([]
byte
(
`
{
"frequency": 10,
"warning": {
"op": ">",
"level": 10
},
"critical": {
"op": ">",
"level": 20
},
"query": {
"refId": "A",
"from": "5m",
"to": "now",
"datasourceId": 1,
"query": "aliasByNode(statsd.fakesite.counters.session_start.*.count, 4)"
},
"transform": {
"type": "aggregation",
"method": "avg"
}
}`
))
alertRuleDAO
.
Name
=
"Test"
alertRuleDAO
.
Expression
=
json
rule
,
_
:=
alerting
.
ConvetAlertModelToAlertRule
(
alertRuleDAO
)
Convey
(
"Confirm that all properties are set"
,
func
()
{
So
(
rule
.
Query
.
Query
,
ShouldEqual
,
"aliasByNode(statsd.fakesite.counters.session_start.*.count, 4)"
)
So
(
rule
.
Query
.
From
,
ShouldEqual
,
"5m"
)
So
(
rule
.
Query
.
To
,
ShouldEqual
,
"now"
)
So
(
rule
.
Query
.
DatasourceId
,
ShouldEqual
,
1
)
So
(
rule
.
Warning
.
Level
,
ShouldEqual
,
10
)
So
(
rule
.
Warning
.
Operator
,
ShouldEqual
,
">"
)
So
(
rule
.
Critical
.
Level
,
ShouldEqual
,
20
)
So
(
rule
.
Critical
.
Operator
,
ShouldEqual
,
">"
)
})
})
}
public/app/features/dashboard/viewStateSrv.js
View file @
1500c0e9
...
...
@@ -120,25 +120,28 @@ function (angular, _, $) {
if
(
this
.
panelScopes
.
length
===
0
)
{
return
;
}
if
(
this
.
dashboard
.
meta
.
fullscreen
)
{
if
(
this
.
fullscreenPanel
)
{
this
.
leaveFullscreen
(
false
);
}
var
panelScope
=
this
.
getPanelScope
(
this
.
state
.
panelId
);
// panel could be about to be created/added and scope does
// not exist yet
if
(
!
panelScope
)
{
return
;
}
if
(
this
.
fullscreenPanel
)
{
// if already fullscreen
if
(
this
.
fullscreenPanel
===
panelScope
)
{
return
;
}
else
{
this
.
leaveFullscreen
(
false
);
}
}
if
(
!
panelScope
.
ctrl
.
editModeInitiated
)
{
panelScope
.
ctrl
.
initEditMode
();
}
this
.
enterFullscreen
(
panelScope
);
return
;
}
if
(
this
.
fullscreenPanel
)
{
if
(
!
panelScope
.
ctrl
.
fullscreen
)
{
this
.
enterFullscreen
(
panelScope
);
}
}
else
if
(
this
.
fullscreenPanel
)
{
this
.
leaveFullscreen
(
true
);
}
};
...
...
public/app/features/panel/panel_ctrl.ts
View file @
1500c0e9
...
...
@@ -152,8 +152,8 @@ export class PanelCtrl {
calculatePanelHeight
()
{
if
(
this
.
fullscreen
)
{
var
docHeight
=
$
(
window
).
height
();
var
editHeight
=
Math
.
floor
(
docHeight
*
0.
3
);
var
fullscreenHeight
=
Math
.
floor
(
docHeight
*
0.
7
);
var
editHeight
=
Math
.
floor
(
docHeight
*
0.
4
);
var
fullscreenHeight
=
Math
.
floor
(
docHeight
*
0.
6
);
this
.
containerHeight
=
this
.
editMode
?
editHeight
:
fullscreenHeight
;
}
else
{
this
.
containerHeight
=
this
.
panel
.
height
||
this
.
row
.
height
;
...
...
public/app/plugins/panel/graph/alert_tab_ctrl.ts
View file @
1500c0e9
...
...
@@ -50,7 +50,7 @@ export class AlertTabCtrl {
notify
:
[],
enabled
:
false
,
scheduler
:
1
,
warn
ing
:
{
op
:
'>'
,
level
:
undefined
},
warn
:
{
op
:
'>'
,
level
:
undefined
},
critical
:
{
op
:
'>'
,
level
:
undefined
},
query
:
{
refId
:
'A'
,
...
...
@@ -70,8 +70,16 @@ export class AlertTabCtrl {
$scope
.
ctrl
=
this
;
this
.
metricTargets
=
this
.
panel
.
targets
.
map
(
val
=>
val
);
this
.
initAlertModel
();
// set panel alert edit mode
this
.
panelCtrl
.
editingAlert
=
true
;
this
.
panelCtrl
.
render
();
$scope
.
$on
(
"$destroy"
,
()
=>
{
this
.
panelCtrl
.
editingAlert
=
false
;
this
.
panelCtrl
.
render
();
});
}
initAlertModel
()
{
...
...
@@ -125,21 +133,21 @@ export class AlertTabCtrl {
}
convertThresholdsToAlertThresholds
()
{
if
(
this
.
panel
.
grid
&&
this
.
panel
.
grid
.
threshold1
&&
this
.
alert
.
warnLevel
===
undefined
)
{
this
.
alert
.
warning
.
op
=
'>'
;
this
.
alert
.
warning
.
level
=
this
.
panel
.
grid
.
threshold1
;
}
if
(
this
.
panel
.
grid
&&
this
.
panel
.
grid
.
threshold2
&&
this
.
alert
.
critical
.
level
===
undefined
)
{
this
.
alert
.
critical
.
op
=
'>'
;
this
.
alert
.
critical
.
level
=
this
.
panel
.
grid
.
threshold2
;
}
//
if (this.panel.grid
//
&& this.panel.grid.threshold1
//
&& this.alert.warnLevel === undefined
//
) {
//
this.alert.warning.op = '>';
//
this.alert.warning.level = this.panel.grid.threshold1;
//
}
//
//
if (this.panel.grid
//
&& this.panel.grid.threshold2
//
&& this.alert.critical.level === undefined
//
) {
//
this.alert.critical.op = '>';
//
this.alert.critical.level = this.panel.grid.threshold2;
//
}
}
delete
()
{
...
...
@@ -156,6 +164,10 @@ export class AlertTabCtrl {
disable
()
{
this
.
alert
.
enabled
=
false
;
}
levelsUpdated
()
{
this
.
panelCtrl
.
render
();
}
}
/** @ngInject */
...
...
public/app/plugins/panel/graph/graph.js
View file @
1500c0e9
...
...
@@ -169,6 +169,7 @@ function (angular, $, moment, _, kbn, GraphTooltip) {
var
right
=
panel
.
yaxes
[
1
];
if
(
left
.
show
&&
left
.
label
)
{
gridMargin
.
left
=
20
;
}
if
(
right
.
show
&&
right
.
label
)
{
gridMargin
.
right
=
20
;
}
}
// Function for rendering panel
...
...
@@ -178,6 +179,12 @@ function (angular, $, moment, _, kbn, GraphTooltip) {
panelWidth
=
panelWidthCache
[
panel
.
span
]
=
elem
.
width
();
}
if
(
ctrl
.
editingAlert
)
{
elem
.
css
(
'margin-right'
,
'220px'
);
}
else
{
elem
.
css
(
'margin-right'
,
''
);
}
if
(
shouldAbortRender
())
{
return
;
}
...
...
@@ -186,6 +193,10 @@ function (angular, $, moment, _, kbn, GraphTooltip) {
// Populate element
var
options
=
{
alerting
:
{
editing
:
ctrl
.
editingAlert
,
alert
:
panel
.
alert
,
},
hooks
:
{
draw
:
[
drawHook
],
processOffset
:
[
processOffsetHook
],
...
...
@@ -260,6 +271,7 @@ function (angular, $, moment, _, kbn, GraphTooltip) {
function
callPlot
(
incrementRenderCounter
)
{
try
{
console
.
log
(
'rendering'
);
$
.
plot
(
elem
,
sortedSeries
,
options
);
}
catch
(
e
)
{
console
.
log
(
'flotcharts error'
,
e
);
...
...
@@ -312,6 +324,50 @@ function (angular, $, moment, _, kbn, GraphTooltip) {
}
function
addGridThresholds
(
options
,
panel
)
{
if
(
panel
.
alert
&&
panel
.
alert
.
enabled
)
{
var
crit
=
panel
.
alert
.
critical
;
var
warn
=
panel
.
alert
.
warn
;
var
critEdge
=
Infinity
;
var
warnEdge
=
crit
.
level
;
if
(
_
.
isNumber
(
crit
.
level
))
{
if
(
crit
.
op
===
'<'
)
{
critEdge
=
-
Infinity
;
}
// fill
options
.
grid
.
markings
.
push
({
yaxis
:
{
from
:
crit
.
level
,
to
:
critEdge
},
color
:
'rgba(234, 112, 112, 0.10)'
,
});
// line
options
.
grid
.
markings
.
push
({
yaxis
:
{
from
:
crit
.
level
,
to
:
crit
.
level
},
color
:
'#ed2e18'
});
}
if
(
_
.
isNumber
(
warn
.
level
))
{
// if (warn.op === '<') {
// }
// fill
options
.
grid
.
markings
.
push
({
yaxis
:
{
from
:
warn
.
level
,
to
:
warnEdge
},
color
:
'rgba(216, 200, 27, 0.10)'
,
});
// line
options
.
grid
.
markings
.
push
({
yaxis
:
{
from
:
warn
.
level
,
to
:
warn
.
level
},
color
:
'#F79520'
});
}
return
;
}
if
(
_
.
isNumber
(
panel
.
grid
.
threshold1
))
{
var
limit1
=
panel
.
grid
.
thresholdLine
?
panel
.
grid
.
threshold1
:
(
panel
.
grid
.
threshold2
||
null
);
options
.
grid
.
markings
.
push
({
...
...
public/app/plugins/panel/graph/jquery.flot.alerts.ts
View file @
1500c0e9
...
...
@@ -2,24 +2,63 @@
import
'jquery.flot'
;
import
$
from
'jquery'
;
import
_
from
'lodash'
;
var
options
=
{};
function
getHandleTemplate
(
type
)
{
function
getHandleTemplate
(
type
,
op
,
value
)
{
if
(
op
===
'>'
)
{
op
=
'>'
;
}
if
(
op
===
'<'
)
{
op
=
'<'
;
}
return
`
<div class="alert-handle" style="position: absolute; top: 100px; right: -50px;">
<i class="icon-gf icon-gf-
${
type
}
alert-icon-
${
type
}
"></i>
> 100
<div class="alert-handle-wrapper alert-handle-wrapper--
${
type
}
">
<div class="alert-handle-line">
</div>
<div class="alert-handle">
<i class="icon-gf icon-gf-
${
type
}
alert-icon-
${
type
}
"></i>
${
op
}
${
value
}
</div>
</div>
`
;
}
function
drawAlertHandles
(
plot
,
canvascontext
)
{
var
$warnHandle
=
$
(
getHandleTemplate
(
'warn'
));
function
drawAlertHandles
(
plot
)
{
var
options
=
plot
.
getOptions
();
var
$placeholder
=
plot
.
getPlaceholder
();
$placeholder
.
find
(
".alert-warn-handle"
).
remove
();
$placeholder
.
append
(
$warnHandle
);
if
(
!
options
.
alerting
.
editing
)
{
$placeholder
.
find
(
".alert-handle"
).
remove
();
return
;
}
var
alert
=
options
.
alerting
.
alert
;
var
height
=
plot
.
height
();
function
renderHandle
(
type
,
model
)
{
var
$handle
=
$placeholder
.
find
(
`.alert-handle-
${
type
}
`
);
if
(
!
_
.
isNumber
(
model
.
level
))
{
$handle
.
remove
();
return
;
}
if
(
$handle
.
length
===
0
)
{
$handle
=
$
(
getHandleTemplate
(
type
,
model
.
op
,
model
.
level
));
$placeholder
.
append
(
$handle
);
}
else
{
$handle
.
html
(
getHandleTemplate
(
type
,
model
.
op
,
model
.
level
));
}
var
levelCanvasPos
=
plot
.
p2c
({
x
:
0
,
y
:
model
.
level
});
console
.
log
(
'canvas level pos'
,
levelCanvasPos
.
top
);
var
levelTopPos
=
Math
.
min
(
Math
.
max
(
levelCanvasPos
.
top
,
0
),
height
)
-
6
;
$handle
.
css
({
top
:
levelTopPos
});
}
renderHandle
(
'critical'
,
alert
.
critical
);
renderHandle
(
'warn'
,
alert
.
warn
);
}
function
shutdown
()
{
...
...
public/app/plugins/panel/graph/partials/tab_alerting.html
View file @
1500c0e9
...
...
@@ -44,8 +44,8 @@
<i
class=
"icon-gf icon-gf-warn alert-icon-warn"
></i>
Warn if
</span>
<metric-segment-model
property=
"ctrl.alert.warn
ing
.op"
options=
"ctrl.levelOpList"
custom=
"false"
css-class=
"query-segment-operator"
></metric-segment-model>
<input
class=
"gf-form-input max-width-7"
type=
"number"
ng-model=
"ctrl.alert.warn
Level"
ng-change=
"ctrl.threshold
sUpdated()"
></input>
<metric-segment-model
property=
"ctrl.alert.warn.op"
options=
"ctrl.levelOpList"
custom=
"false"
css-class=
"query-segment-operator"
></metric-segment-model>
<input
class=
"gf-form-input max-width-7"
type=
"number"
ng-model=
"ctrl.alert.warn
.level"
ng-change=
"ctrl.level
sUpdated()"
></input>
</div>
<div
class=
"gf-form"
>
<span
class=
"gf-form-label"
>
...
...
@@ -53,7 +53,7 @@
Critcal if
</span>
<metric-segment-model
property=
"ctrl.alert.critical.op"
options=
"ctrl.levelOpList"
custom=
"false"
css-class=
"query-segment-operator"
></metric-segment-model>
<input
class=
"gf-form-input max-width-7"
type=
"number"
ng-model=
"ctrl.alert.crit
Level"
ng-change=
"ctrl.threshold
sUpdated()"
></input>
<input
class=
"gf-form-input max-width-7"
type=
"number"
ng-model=
"ctrl.alert.crit
ical.level"
ng-change=
"ctrl.level
sUpdated()"
></input>
</div>
</div>
</div>
...
...
public/sass/_variables.dark.scss
View file @
1500c0e9
...
...
@@ -44,7 +44,7 @@ $brand-text-highlight: #f7941d;
// Status colors
// -------------------------
$online
:
#10a345
;
$warn
:
#
ffc03c
;
$warn
:
#
F79520
;
$critical
:
#ed2e18
;
// Scaffolding
...
...
public/sass/components/_panel_graph.scss
View file @
1500c0e9
...
...
@@ -315,8 +315,61 @@
font-size
:
12px
;
}
.alert-handle
{
padding
:
0
.4rem
;;
background-color
:
$dark-4
;
box-shadow
:
$search-shadow
;
.alert-handle-wrapper
{
position
:
absolute
;
&
--warn
{
right
:
-221px
;
width
:
238px
;
.alert-handle-line
{
float
:
left
;
height
:
2px
;
width
:
138px
;
margin-top
:
14px
;
background-color
:
$warn
;
z-index
:
0
;
position
:
relative
;
}
}
&
--critical
{
right
:
-105px
;
width
:
123px
;
.alert-handle-line
{
float
:
left
;
height
:
2px
;
width
:
23px
;
margin-top
:
14px
;
background-color
:
$critical
;
z-index
:
0
;
position
:
relative
;
}
}
.alert-handle
{
z-index
:
10
;
position
:
relative
;
float
:
right
;
padding
:
0
.4rem
;;
background-color
:
$btn-inverse-bg
;
box-shadow
:
$search-shadow
;
cursor
:
pointer
;
width
:
100px
;
font-size
:
$font-size-sm
;
box-shadow
:
4px
4px
3px
0px
$body-bg
;
border-radius
:
4px
;
border-width
:
0
1px
1px
0
;
border-style
:
solid
;
border-color
:
$black
;
.icon-gf
{
font-size
:
17px
;
position
:
relative
;
top
:
2px
;
}
}
}
public/sass/pages/_dashboard.scss
View file @
1500c0e9
...
...
@@ -197,12 +197,6 @@ div.flot-text {
bottom
:
0
;
}
.panel-fullscreen
{
.panel-title-container
{
padding
:
8px
;
}
}
.panel-full-edit
{
margin-top
:
20px
;
margin-bottom
:
20px
;
...
...
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