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
d8736a25
Unverified
Commit
d8736a25
authored
Jun 03, 2019
by
Carl Bergquist
Committed by
GitHub
Jun 03, 2019
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Alerting: golint fixes for alerting (#17246)
parent
60ddad8f
Hide whitespace changes
Inline
Side-by-side
Showing
39 changed files
with
235 additions
and
217 deletions
+235
-217
Makefile
+6
-1
pkg/api/alerting.go
+2
-2
pkg/services/alerting/conditions/evaluator.go
+16
-11
pkg/services/alerting/conditions/query.go
+22
-17
pkg/services/alerting/conditions/query_test.go
+4
-5
pkg/services/alerting/conditions/reducer.go
+8
-8
pkg/services/alerting/conditions/reducer_test.go
+9
-9
pkg/services/alerting/engine.go
+15
-15
pkg/services/alerting/engine_integration_test.go
+1
-1
pkg/services/alerting/engine_test.go
+1
-1
pkg/services/alerting/eval_context.go
+7
-7
pkg/services/alerting/interfaces.go
+1
-1
pkg/services/alerting/notifier.go
+11
-11
pkg/services/alerting/notifiers/alertmanager.go
+5
-5
pkg/services/alerting/notifiers/base.go
+2
-2
pkg/services/alerting/notifiers/dingding.go
+2
-2
pkg/services/alerting/notifiers/discord.go
+19
-16
pkg/services/alerting/notifiers/discord_test.go
+2
-2
pkg/services/alerting/notifiers/email.go
+3
-3
pkg/services/alerting/notifiers/googlechat.go
+3
-3
pkg/services/alerting/notifiers/hipchat.go
+5
-5
pkg/services/alerting/notifiers/kafka.go
+4
-4
pkg/services/alerting/notifiers/line.go
+6
-6
pkg/services/alerting/notifiers/opsgenie.go
+7
-7
pkg/services/alerting/notifiers/pagerduty.go
+4
-4
pkg/services/alerting/notifiers/pushover.go
+1
-1
pkg/services/alerting/notifiers/sensu.go
+5
-5
pkg/services/alerting/notifiers/slack.go
+3
-3
pkg/services/alerting/notifiers/teams.go
+5
-5
pkg/services/alerting/notifiers/telegram.go
+5
-5
pkg/services/alerting/notifiers/threema.go
+3
-3
pkg/services/alerting/notifiers/victorops.go
+4
-4
pkg/services/alerting/notifiers/webhook.go
+4
-4
pkg/services/alerting/result_handler.go
+7
-7
pkg/services/alerting/rule.go
+20
-20
pkg/services/alerting/scheduler.go
+4
-4
pkg/services/alerting/test_notification.go
+3
-3
pkg/services/alerting/test_rule.go
+5
-5
scripts/backend-lint.sh
+1
-0
No files found.
Makefile
View file @
d8736a25
-include
local/Makefile
.PHONY
:
all deps-go deps-js deps build-go build-server build-cli build-js build build-docker-dev build-docker-full lint-go test-go test-js test run clean gosec revive devenv devenv-down
.PHONY
:
all deps-go deps-js deps build-go build-server build-cli build-js build build-docker-dev build-docker-full lint-go test-go test-js test run clean gosec revive devenv devenv-down
revive-alerting
GO
:=
GO111MODULE
=
on go
GO_FILES
:=
./pkg/...
...
...
@@ -84,6 +84,11 @@ revive: scripts/go/bin/revive
-config
./scripts/go/configs/revive.toml
\
$(GO_FILES)
revive-alerting
:
scripts/go/bin/revive
@
scripts/go/bin/revive
\
-formatter
stylish
\
./pkg/services/alerting/...
# create docker-compose file with provided sources and start them
# example: make devenv sources=postgres,openldap
ifeq
($(sources),)
...
...
pkg/api/alerting.go
View file @
d8736a25
...
...
@@ -131,9 +131,9 @@ func AlertTest(c *m.ReqContext, dto dtos.AlertTestCommand) Response {
}
backendCmd
:=
alerting
.
AlertTestCommand
{
OrgI
d
:
c
.
OrgId
,
OrgI
D
:
c
.
OrgId
,
Dashboard
:
dto
.
Dashboard
,
PanelI
d
:
dto
.
PanelId
,
PanelI
D
:
dto
.
PanelId
,
User
:
c
.
SignedInUser
,
}
...
...
pkg/services/alerting/conditions/evaluator.go
View file @
d8736a25
...
...
@@ -14,22 +14,25 @@ var (
rangedTypes
=
[]
string
{
"within_range"
,
"outside_range"
}
)
// AlertEvaluator evaluates the reduced value of a timeserie.
// Returning true if a timeserie is violating the condition
// ex: ThresholdEvaluator, NoValueEvaluator, RangeEvaluator
type
AlertEvaluator
interface
{
Eval
(
reducedValue
null
.
Float
)
bool
}
type
N
oValueEvaluator
struct
{}
type
n
oValueEvaluator
struct
{}
func
(
e
*
N
oValueEvaluator
)
Eval
(
reducedValue
null
.
Float
)
bool
{
func
(
e
*
n
oValueEvaluator
)
Eval
(
reducedValue
null
.
Float
)
bool
{
return
!
reducedValue
.
Valid
}
type
T
hresholdEvaluator
struct
{
type
t
hresholdEvaluator
struct
{
Type
string
Threshold
float64
}
func
newThresholdEvaluator
(
typ
string
,
model
*
simplejson
.
Json
)
(
*
T
hresholdEvaluator
,
error
)
{
func
newThresholdEvaluator
(
typ
string
,
model
*
simplejson
.
Json
)
(
*
t
hresholdEvaluator
,
error
)
{
params
:=
model
.
Get
(
"params"
)
.
MustArray
()
if
len
(
params
)
==
0
{
return
nil
,
fmt
.
Errorf
(
"Evaluator missing threshold parameter"
)
...
...
@@ -40,12 +43,12 @@ func newThresholdEvaluator(typ string, model *simplejson.Json) (*ThresholdEvalua
return
nil
,
fmt
.
Errorf
(
"Evaluator has invalid parameter"
)
}
defaultEval
:=
&
T
hresholdEvaluator
{
Type
:
typ
}
defaultEval
:=
&
t
hresholdEvaluator
{
Type
:
typ
}
defaultEval
.
Threshold
,
_
=
firstParam
.
Float64
()
return
defaultEval
,
nil
}
func
(
e
*
T
hresholdEvaluator
)
Eval
(
reducedValue
null
.
Float
)
bool
{
func
(
e
*
t
hresholdEvaluator
)
Eval
(
reducedValue
null
.
Float
)
bool
{
if
!
reducedValue
.
Valid
{
return
false
}
...
...
@@ -60,13 +63,13 @@ func (e *ThresholdEvaluator) Eval(reducedValue null.Float) bool {
return
false
}
type
R
angedEvaluator
struct
{
type
r
angedEvaluator
struct
{
Type
string
Lower
float64
Upper
float64
}
func
newRangedEvaluator
(
typ
string
,
model
*
simplejson
.
Json
)
(
*
R
angedEvaluator
,
error
)
{
func
newRangedEvaluator
(
typ
string
,
model
*
simplejson
.
Json
)
(
*
r
angedEvaluator
,
error
)
{
params
:=
model
.
Get
(
"params"
)
.
MustArray
()
if
len
(
params
)
==
0
{
return
nil
,
alerting
.
ValidationError
{
Reason
:
"Evaluator missing threshold parameter"
}
...
...
@@ -82,13 +85,13 @@ func newRangedEvaluator(typ string, model *simplejson.Json) (*RangedEvaluator, e
return
nil
,
alerting
.
ValidationError
{
Reason
:
"Evaluator has invalid second parameter"
}
}
rangedEval
:=
&
R
angedEvaluator
{
Type
:
typ
}
rangedEval
:=
&
r
angedEvaluator
{
Type
:
typ
}
rangedEval
.
Lower
,
_
=
firstParam
.
Float64
()
rangedEval
.
Upper
,
_
=
secondParam
.
Float64
()
return
rangedEval
,
nil
}
func
(
e
*
R
angedEvaluator
)
Eval
(
reducedValue
null
.
Float
)
bool
{
func
(
e
*
r
angedEvaluator
)
Eval
(
reducedValue
null
.
Float
)
bool
{
if
!
reducedValue
.
Valid
{
return
false
}
...
...
@@ -105,6 +108,8 @@ func (e *RangedEvaluator) Eval(reducedValue null.Float) bool {
return
false
}
// NewAlertEvaluator is a factory function for returning
// an `AlertEvaluator` depending on the json model.
func
NewAlertEvaluator
(
model
*
simplejson
.
Json
)
(
AlertEvaluator
,
error
)
{
typ
:=
model
.
Get
(
"type"
)
.
MustString
()
if
typ
==
""
{
...
...
@@ -120,7 +125,7 @@ func NewAlertEvaluator(model *simplejson.Json) (AlertEvaluator, error) {
}
if
typ
==
"no_value"
{
return
&
N
oValueEvaluator
{},
nil
return
&
n
oValueEvaluator
{},
nil
}
return
nil
,
fmt
.
Errorf
(
"Evaluator invalid evaluator type: %s"
,
typ
)
...
...
pkg/services/alerting/conditions/query.go
View file @
d8736a25
...
...
@@ -17,26 +17,31 @@ import (
func
init
()
{
alerting
.
RegisterCondition
(
"query"
,
func
(
model
*
simplejson
.
Json
,
index
int
)
(
alerting
.
Condition
,
error
)
{
return
N
ewQueryCondition
(
model
,
index
)
return
n
ewQueryCondition
(
model
,
index
)
})
}
// QueryCondition is responsible for issue and query, reduce the
// timeseries into single values and evaluate if they are firing or not.
type
QueryCondition
struct
{
Index
int
Query
AlertQuery
Reducer
Q
ueryReducer
Reducer
*
q
ueryReducer
Evaluator
AlertEvaluator
Operator
string
HandleRequest
tsdb
.
HandleRequestFunc
}
// AlertQuery contains information about what datasource a query
// should be sent to and the query object.
type
AlertQuery
struct
{
Model
*
simplejson
.
Json
DatasourceI
d
int64
DatasourceI
D
int64
From
string
To
string
}
// Eval evaluates the `QueryCondition`.
func
(
c
*
QueryCondition
)
Eval
(
context
*
alerting
.
EvalContext
)
(
*
alerting
.
ConditionResult
,
error
)
{
timeRange
:=
tsdb
.
NewTimeRange
(
c
.
Query
.
From
,
c
.
Query
.
To
)
...
...
@@ -101,8 +106,8 @@ func (c *QueryCondition) Eval(context *alerting.EvalContext) (*alerting.Conditio
func
(
c
*
QueryCondition
)
executeQuery
(
context
*
alerting
.
EvalContext
,
timeRange
*
tsdb
.
TimeRange
)
(
tsdb
.
TimeSeriesSlice
,
error
)
{
getDsInfo
:=
&
models
.
GetDataSourceByIdQuery
{
Id
:
c
.
Query
.
DatasourceI
d
,
OrgId
:
context
.
Rule
.
OrgI
d
,
Id
:
c
.
Query
.
DatasourceI
D
,
OrgId
:
context
.
Rule
.
OrgI
D
,
}
if
err
:=
bus
.
Dispatch
(
getDsInfo
);
err
!=
nil
{
...
...
@@ -154,16 +159,16 @@ func (c *QueryCondition) getRequestForAlertRule(datasource *models.DataSource, t
return
req
}
func
N
ewQueryCondition
(
model
*
simplejson
.
Json
,
index
int
)
(
*
QueryCondition
,
error
)
{
func
n
ewQueryCondition
(
model
*
simplejson
.
Json
,
index
int
)
(
*
QueryCondition
,
error
)
{
condition
:=
QueryCondition
{}
condition
.
Index
=
index
condition
.
HandleRequest
=
tsdb
.
HandleRequest
queryJ
son
:=
model
.
Get
(
"query"
)
queryJ
SON
:=
model
.
Get
(
"query"
)
condition
.
Query
.
Model
=
queryJ
son
.
Get
(
"model"
)
condition
.
Query
.
From
=
queryJ
son
.
Get
(
"params"
)
.
MustArray
()[
1
]
.
(
string
)
condition
.
Query
.
To
=
queryJ
son
.
Get
(
"params"
)
.
MustArray
()[
2
]
.
(
string
)
condition
.
Query
.
Model
=
queryJ
SON
.
Get
(
"model"
)
condition
.
Query
.
From
=
queryJ
SON
.
Get
(
"params"
)
.
MustArray
()[
1
]
.
(
string
)
condition
.
Query
.
To
=
queryJ
SON
.
Get
(
"params"
)
.
MustArray
()[
2
]
.
(
string
)
if
err
:=
validateFromValue
(
condition
.
Query
.
From
);
err
!=
nil
{
return
nil
,
err
...
...
@@ -173,20 +178,20 @@ func NewQueryCondition(model *simplejson.Json, index int) (*QueryCondition, erro
return
nil
,
err
}
condition
.
Query
.
DatasourceI
d
=
queryJson
.
Get
(
"datasourceId"
)
.
MustInt64
()
condition
.
Query
.
DatasourceI
D
=
queryJSON
.
Get
(
"datasourceId"
)
.
MustInt64
()
reducerJ
son
:=
model
.
Get
(
"reducer"
)
condition
.
Reducer
=
NewSimpleReducer
(
reducerJson
.
Get
(
"type"
)
.
MustString
())
reducerJ
SON
:=
model
.
Get
(
"reducer"
)
condition
.
Reducer
=
newSimpleReducer
(
reducerJSON
.
Get
(
"type"
)
.
MustString
())
evaluatorJ
son
:=
model
.
Get
(
"evaluator"
)
evaluator
,
err
:=
NewAlertEvaluator
(
evaluatorJ
son
)
evaluatorJ
SON
:=
model
.
Get
(
"evaluator"
)
evaluator
,
err
:=
NewAlertEvaluator
(
evaluatorJ
SON
)
if
err
!=
nil
{
return
nil
,
err
}
condition
.
Evaluator
=
evaluator
operatorJ
son
:=
model
.
Get
(
"operator"
)
operator
:=
operatorJ
son
.
Get
(
"type"
)
.
MustString
(
"and"
)
operatorJ
SON
:=
model
.
Get
(
"operator"
)
operator
:=
operatorJ
SON
.
Get
(
"type"
)
.
MustString
(
"and"
)
condition
.
Operator
=
operator
return
&
condition
,
nil
...
...
pkg/services/alerting/conditions/query_test.go
View file @
d8736a25
...
...
@@ -27,16 +27,15 @@ func TestQueryCondition(t *testing.T) {
So
(
ctx
.
condition
.
Query
.
From
,
ShouldEqual
,
"5m"
)
So
(
ctx
.
condition
.
Query
.
To
,
ShouldEqual
,
"now"
)
So
(
ctx
.
condition
.
Query
.
DatasourceI
d
,
ShouldEqual
,
1
)
So
(
ctx
.
condition
.
Query
.
DatasourceI
D
,
ShouldEqual
,
1
)
Convey
(
"Can read query reducer"
,
func
()
{
reducer
,
ok
:=
ctx
.
condition
.
Reducer
.
(
*
SimpleReducer
)
So
(
ok
,
ShouldBeTrue
)
reducer
:=
ctx
.
condition
.
Reducer
So
(
reducer
.
Type
,
ShouldEqual
,
"avg"
)
})
Convey
(
"Can read evaluator"
,
func
()
{
evaluator
,
ok
:=
ctx
.
condition
.
Evaluator
.
(
*
T
hresholdEvaluator
)
evaluator
,
ok
:=
ctx
.
condition
.
Evaluator
.
(
*
t
hresholdEvaluator
)
So
(
ok
,
ShouldBeTrue
)
So
(
evaluator
.
Type
,
ShouldEqual
,
"gt"
)
})
...
...
@@ -163,7 +162,7 @@ func (ctx *queryConditionTestContext) exec() (*alerting.ConditionResult, error)
}`
))
So
(
err
,
ShouldBeNil
)
condition
,
err
:=
N
ewQueryCondition
(
jsonModel
,
0
)
condition
,
err
:=
n
ewQueryCondition
(
jsonModel
,
0
)
So
(
err
,
ShouldBeNil
)
ctx
.
condition
=
condition
...
...
pkg/services/alerting/conditions/reducer.go
View file @
d8736a25
...
...
@@ -9,15 +9,15 @@ import (
"github.com/grafana/grafana/pkg/tsdb"
)
type
QueryReducer
interface
{
Reduce
(
timeSeries
*
tsdb
.
TimeSeries
)
null
.
Float
}
// queryReducer reduces an timeserie to a nullable float
type
queryReducer
struct
{
type
SimpleReducer
struct
{
// Type is how the timeserie should be reduced.
// Ex avg, sum, max, min, count
Type
string
}
func
(
s
*
Simple
Reducer
)
Reduce
(
series
*
tsdb
.
TimeSeries
)
null
.
Float
{
func
(
s
*
query
Reducer
)
Reduce
(
series
*
tsdb
.
TimeSeries
)
null
.
Float
{
if
len
(
series
.
Points
)
==
0
{
return
null
.
FloatFromPtr
(
nil
)
}
...
...
@@ -31,7 +31,7 @@ func (s *SimpleReducer) Reduce(series *tsdb.TimeSeries) null.Float {
for
_
,
point
:=
range
series
.
Points
{
if
point
[
0
]
.
Valid
{
value
+=
point
[
0
]
.
Float64
validPointsCount
+=
1
validPointsCount
++
allNull
=
false
}
}
...
...
@@ -117,8 +117,8 @@ func (s *SimpleReducer) Reduce(series *tsdb.TimeSeries) null.Float {
return
null
.
FloatFrom
(
value
)
}
func
NewSimpleReducer
(
typ
string
)
*
Simple
Reducer
{
return
&
SimpleReducer
{
Type
:
typ
}
func
newSimpleReducer
(
t
string
)
*
query
Reducer
{
return
&
queryReducer
{
Type
:
t
}
}
func
calculateDiff
(
series
*
tsdb
.
TimeSeries
,
allNull
bool
,
value
float64
,
fn
func
(
float64
,
float64
)
float64
)
(
bool
,
float64
)
{
...
...
pkg/services/alerting/conditions/reducer_test.go
View file @
d8736a25
...
...
@@ -53,7 +53,7 @@ func TestSimpleReducer(t *testing.T) {
})
Convey
(
"median should ignore null values"
,
func
()
{
reducer
:=
N
ewSimpleReducer
(
"median"
)
reducer
:=
n
ewSimpleReducer
(
"median"
)
series
:=
&
tsdb
.
TimeSeries
{
Name
:
"test time serie"
,
}
...
...
@@ -76,7 +76,7 @@ func TestSimpleReducer(t *testing.T) {
})
Convey
(
"avg with only nulls"
,
func
()
{
reducer
:=
N
ewSimpleReducer
(
"avg"
)
reducer
:=
n
ewSimpleReducer
(
"avg"
)
series
:=
&
tsdb
.
TimeSeries
{
Name
:
"test time serie"
,
}
...
...
@@ -87,7 +87,7 @@ func TestSimpleReducer(t *testing.T) {
Convey
(
"count_non_null"
,
func
()
{
Convey
(
"with null values and real values"
,
func
()
{
reducer
:=
N
ewSimpleReducer
(
"count_non_null"
)
reducer
:=
n
ewSimpleReducer
(
"count_non_null"
)
series
:=
&
tsdb
.
TimeSeries
{
Name
:
"test time serie"
,
}
...
...
@@ -102,7 +102,7 @@ func TestSimpleReducer(t *testing.T) {
})
Convey
(
"with null values"
,
func
()
{
reducer
:=
N
ewSimpleReducer
(
"count_non_null"
)
reducer
:=
n
ewSimpleReducer
(
"count_non_null"
)
series
:=
&
tsdb
.
TimeSeries
{
Name
:
"test time serie"
,
}
...
...
@@ -115,7 +115,7 @@ func TestSimpleReducer(t *testing.T) {
})
Convey
(
"avg of number values and null values should ignore nulls"
,
func
()
{
reducer
:=
N
ewSimpleReducer
(
"avg"
)
reducer
:=
n
ewSimpleReducer
(
"avg"
)
series
:=
&
tsdb
.
TimeSeries
{
Name
:
"test time serie"
,
}
...
...
@@ -144,7 +144,7 @@ func TestSimpleReducer(t *testing.T) {
})
Convey
(
"diff with only nulls"
,
func
()
{
reducer
:=
N
ewSimpleReducer
(
"diff"
)
reducer
:=
n
ewSimpleReducer
(
"diff"
)
series
:=
&
tsdb
.
TimeSeries
{
Name
:
"test time serie"
,
}
...
...
@@ -171,7 +171,7 @@ func TestSimpleReducer(t *testing.T) {
})
Convey
(
"percent_diff with only nulls"
,
func
()
{
reducer
:=
N
ewSimpleReducer
(
"percent_diff"
)
reducer
:=
n
ewSimpleReducer
(
"percent_diff"
)
series
:=
&
tsdb
.
TimeSeries
{
Name
:
"test time serie"
,
}
...
...
@@ -184,8 +184,8 @@ func TestSimpleReducer(t *testing.T) {
})
}
func
testReducer
(
typ
string
,
datapoints
...
float64
)
float64
{
reducer
:=
NewSimpleReducer
(
typ
)
func
testReducer
(
reducerType
string
,
datapoints
...
float64
)
float64
{
reducer
:=
newSimpleReducer
(
reducerType
)
series
:=
&
tsdb
.
TimeSeries
{
Name
:
"test time serie"
,
}
...
...
pkg/services/alerting/engine.go
View file @
d8736a25
...
...
@@ -17,10 +17,10 @@ import (
"golang.org/x/sync/errgroup"
)
// Alert
ingServic
e is the background process that
// Alert
Engin
e is the background process that
// schedules alert evaluations and makes sure notifications
// are sent.
type
Alert
ingServic
e
struct
{
type
Alert
Engin
e
struct
{
RenderService
rendering
.
Service
`inject:""`
execQueue
chan
*
Job
...
...
@@ -33,16 +33,16 @@ type AlertingService struct {
}
func
init
()
{
registry
.
RegisterService
(
&
Alert
ingServic
e
{})
registry
.
RegisterService
(
&
Alert
Engin
e
{})
}
// IsDisabled returns true if the alerting service is disable for this instance.
func
(
e
*
Alert
ingServic
e
)
IsDisabled
()
bool
{
func
(
e
*
Alert
Engin
e
)
IsDisabled
()
bool
{
return
!
setting
.
AlertingEnabled
||
!
setting
.
ExecuteAlerts
}
// Init initalizes the AlertingService.
func
(
e
*
Alert
ingServic
e
)
Init
()
error
{
func
(
e
*
Alert
Engin
e
)
Init
()
error
{
e
.
ticker
=
NewTicker
(
time
.
Now
(),
time
.
Second
*
0
,
clock
.
New
())
e
.
execQueue
=
make
(
chan
*
Job
,
1000
)
e
.
scheduler
=
newScheduler
()
...
...
@@ -54,7 +54,7 @@ func (e *AlertingService) Init() error {
}
// Run starts the alerting service background process.
func
(
e
*
Alert
ingServic
e
)
Run
(
ctx
context
.
Context
)
error
{
func
(
e
*
Alert
Engin
e
)
Run
(
ctx
context
.
Context
)
error
{
alertGroup
,
ctx
:=
errgroup
.
WithContext
(
ctx
)
alertGroup
.
Go
(
func
()
error
{
return
e
.
alertingTicker
(
ctx
)
})
alertGroup
.
Go
(
func
()
error
{
return
e
.
runJobDispatcher
(
ctx
)
})
...
...
@@ -63,7 +63,7 @@ func (e *AlertingService) Run(ctx context.Context) error {
return
err
}
func
(
e
*
Alert
ingServic
e
)
alertingTicker
(
grafanaCtx
context
.
Context
)
error
{
func
(
e
*
Alert
Engin
e
)
alertingTicker
(
grafanaCtx
context
.
Context
)
error
{
defer
func
()
{
if
err
:=
recover
();
err
!=
nil
{
e
.
log
.
Error
(
"Scheduler Panic: stopping alertingTicker"
,
"error"
,
err
,
"stack"
,
log
.
Stack
(
1
))
...
...
@@ -88,7 +88,7 @@ func (e *AlertingService) alertingTicker(grafanaCtx context.Context) error {
}
}
func
(
e
*
Alert
ingServic
e
)
runJobDispatcher
(
grafanaCtx
context
.
Context
)
error
{
func
(
e
*
Alert
Engin
e
)
runJobDispatcher
(
grafanaCtx
context
.
Context
)
error
{
dispatcherGroup
,
alertCtx
:=
errgroup
.
WithContext
(
grafanaCtx
)
for
{
...
...
@@ -105,7 +105,7 @@ var (
unfinishedWorkTimeout
=
time
.
Second
*
5
)
func
(
e
*
Alert
ingServic
e
)
processJobWithRetry
(
grafanaCtx
context
.
Context
,
job
*
Job
)
error
{
func
(
e
*
Alert
Engin
e
)
processJobWithRetry
(
grafanaCtx
context
.
Context
,
job
*
Job
)
error
{
defer
func
()
{
if
err
:=
recover
();
err
!=
nil
{
e
.
log
.
Error
(
"Alert Panic"
,
"error"
,
err
,
"stack"
,
log
.
Stack
(
1
))
...
...
@@ -140,7 +140,7 @@ func (e *AlertingService) processJobWithRetry(grafanaCtx context.Context, job *J
}
}
func
(
e
*
Alert
ingServic
e
)
endJob
(
err
error
,
cancelChan
chan
context
.
CancelFunc
,
job
*
Job
)
error
{
func
(
e
*
Alert
Engin
e
)
endJob
(
err
error
,
cancelChan
chan
context
.
CancelFunc
,
job
*
Job
)
error
{
job
.
Running
=
false
close
(
cancelChan
)
for
cancelFn
:=
range
cancelChan
{
...
...
@@ -149,7 +149,7 @@ func (e *AlertingService) endJob(err error, cancelChan chan context.CancelFunc,
return
err
}
func
(
e
*
Alert
ingServic
e
)
processJob
(
attemptID
int
,
attemptChan
chan
int
,
cancelChan
chan
context
.
CancelFunc
,
job
*
Job
)
{
func
(
e
*
Alert
Engin
e
)
processJob
(
attemptID
int
,
attemptChan
chan
int
,
cancelChan
chan
context
.
CancelFunc
,
job
*
Job
)
{
defer
func
()
{
if
err
:=
recover
();
err
!=
nil
{
e
.
log
.
Error
(
"Alert Panic"
,
"error"
,
err
,
"stack"
,
log
.
Stack
(
1
))
...
...
@@ -180,8 +180,8 @@ func (e *AlertingService) processJob(attemptID int, attemptChan chan int, cancel
e
.
evalHandler
.
Eval
(
evalContext
)
span
.
SetTag
(
"alertId"
,
evalContext
.
Rule
.
I
d
)
span
.
SetTag
(
"dashboardId"
,
evalContext
.
Rule
.
DashboardI
d
)
span
.
SetTag
(
"alertId"
,
evalContext
.
Rule
.
I
D
)
span
.
SetTag
(
"dashboardId"
,
evalContext
.
Rule
.
DashboardI
D
)
span
.
SetTag
(
"firing"
,
evalContext
.
Firing
)
span
.
SetTag
(
"nodatapoints"
,
evalContext
.
NoDataFound
)
span
.
SetTag
(
"attemptID"
,
attemptID
)
...
...
@@ -194,7 +194,7 @@ func (e *AlertingService) processJob(attemptID int, attemptChan chan int, cancel
)
if
attemptID
<
setting
.
AlertingMaxAttempts
{
span
.
Finish
()
e
.
log
.
Debug
(
"Job Execution attempt triggered retry"
,
"timeMs"
,
evalContext
.
GetDurationMs
(),
"alertId"
,
evalContext
.
Rule
.
I
d
,
"name"
,
evalContext
.
Rule
.
Name
,
"firing"
,
evalContext
.
Firing
,
"attemptID"
,
attemptID
)
e
.
log
.
Debug
(
"Job Execution attempt triggered retry"
,
"timeMs"
,
evalContext
.
GetDurationMs
(),
"alertId"
,
evalContext
.
Rule
.
I
D
,
"name"
,
evalContext
.
Rule
.
Name
,
"firing"
,
evalContext
.
Firing
,
"attemptID"
,
attemptID
)
attemptChan
<-
(
attemptID
+
1
)
return
}
...
...
@@ -212,7 +212,7 @@ func (e *AlertingService) processJob(attemptID int, attemptChan chan int, cancel
evalContext
.
Rule
.
State
=
evalContext
.
GetNewState
()
e
.
resultHandler
.
handle
(
evalContext
)
span
.
Finish
()
e
.
log
.
Debug
(
"Job Execution completed"
,
"timeMs"
,
evalContext
.
GetDurationMs
(),
"alertId"
,
evalContext
.
Rule
.
I
d
,
"name"
,
evalContext
.
Rule
.
Name
,
"firing"
,
evalContext
.
Firing
,
"attemptID"
,
attemptID
)
e
.
log
.
Debug
(
"Job Execution completed"
,
"timeMs"
,
evalContext
.
GetDurationMs
(),
"alertId"
,
evalContext
.
Rule
.
I
D
,
"name"
,
evalContext
.
Rule
.
Name
,
"firing"
,
evalContext
.
Firing
,
"attemptID"
,
attemptID
)
close
(
attemptChan
)
}()
}
pkg/services/alerting/engine_integration_test.go
View file @
d8736a25
...
...
@@ -17,7 +17,7 @@ import (
func
TestEngineTimeouts
(
t
*
testing
.
T
)
{
Convey
(
"Alerting engine timeout tests"
,
t
,
func
()
{
engine
:=
&
Alert
ingServic
e
{}
engine
:=
&
Alert
Engin
e
{}
engine
.
Init
()
setting
.
AlertingNotificationTimeout
=
30
*
time
.
Second
setting
.
AlertingMaxAttempts
=
3
...
...
pkg/services/alerting/engine_test.go
View file @
d8736a25
...
...
@@ -39,7 +39,7 @@ func (handler *FakeResultHandler) handle(evalContext *EvalContext) error {
func
TestEngineProcessJob
(
t
*
testing
.
T
)
{
Convey
(
"Alerting engine job processing"
,
t
,
func
()
{
engine
:=
&
Alert
ingServic
e
{}
engine
:=
&
Alert
Engin
e
{}
engine
.
Init
()
setting
.
AlertingEvaluationTimeout
=
30
*
time
.
Second
setting
.
AlertingNotificationTimeout
=
30
*
time
.
Second
...
...
pkg/services/alerting/eval_context.go
View file @
d8736a25
...
...
@@ -26,7 +26,7 @@ type EvalContext struct {
dashboardRef
*
models
.
DashboardRef
ImagePublicU
rl
string
ImagePublicU
RL
string
ImageOnDiskPath
string
NoDataFound
bool
PrevAlertState
models
.
AlertStateType
...
...
@@ -102,7 +102,7 @@ func (c *EvalContext) GetDashboardUID() (*models.DashboardRef, error) {
return
c
.
dashboardRef
,
nil
}
uidQuery
:=
&
models
.
GetDashboardRefByIdQuery
{
Id
:
c
.
Rule
.
DashboardI
d
}
uidQuery
:=
&
models
.
GetDashboardRefByIdQuery
{
Id
:
c
.
Rule
.
DashboardI
D
}
if
err
:=
bus
.
Dispatch
(
uidQuery
);
err
!=
nil
{
return
nil
,
err
}
...
...
@@ -113,8 +113,8 @@ func (c *EvalContext) GetDashboardUID() (*models.DashboardRef, error) {
const
urlFormat
=
"%s?fullscreen&edit&tab=alert&panelId=%d&orgId=%d"
// GetRuleU
rl
returns the url to the dashboard containing the alert.
func
(
c
*
EvalContext
)
GetRuleU
rl
()
(
string
,
error
)
{
// GetRuleU
RL
returns the url to the dashboard containing the alert.
func
(
c
*
EvalContext
)
GetRuleU
RL
()
(
string
,
error
)
{
if
c
.
IsTestRun
{
return
setting
.
AppUrl
,
nil
}
...
...
@@ -123,7 +123,7 @@ func (c *EvalContext) GetRuleUrl() (string, error) {
if
err
!=
nil
{
return
""
,
err
}
return
fmt
.
Sprintf
(
urlFormat
,
models
.
GetFullDashboardUrl
(
ref
.
Uid
,
ref
.
Slug
),
c
.
Rule
.
PanelI
d
,
c
.
Rule
.
OrgId
),
nil
return
fmt
.
Sprintf
(
urlFormat
,
models
.
GetFullDashboardUrl
(
ref
.
Uid
,
ref
.
Slug
),
c
.
Rule
.
PanelI
D
,
c
.
Rule
.
OrgID
),
nil
}
// GetNewState returns the new state from the alert rule evaluation.
...
...
@@ -148,7 +148,7 @@ func (c *EvalContext) GetNewState() models.AlertStateType {
func
getNewStateInternal
(
c
*
EvalContext
)
models
.
AlertStateType
{
if
c
.
Error
!=
nil
{
c
.
log
.
Error
(
"Alert Rule Result Error"
,
"ruleId"
,
c
.
Rule
.
I
d
,
"ruleId"
,
c
.
Rule
.
I
D
,
"name"
,
c
.
Rule
.
Name
,
"error"
,
c
.
Error
,
"changing state to"
,
c
.
Rule
.
ExecutionErrorState
.
ToAlertState
())
...
...
@@ -165,7 +165,7 @@ func getNewStateInternal(c *EvalContext) models.AlertStateType {
if
c
.
NoDataFound
{
c
.
log
.
Info
(
"Alert Rule returned no data"
,
"ruleId"
,
c
.
Rule
.
I
d
,
"ruleId"
,
c
.
Rule
.
I
D
,
"name"
,
c
.
Rule
.
Name
,
"changing state to"
,
c
.
Rule
.
NoDataState
.
ToAlertState
())
...
...
pkg/services/alerting/interfaces.go
View file @
d8736a25
...
...
@@ -25,7 +25,7 @@ type Notifier interface {
// ShouldNotify checks this evaluation should send an alert notification
ShouldNotify
(
ctx
context
.
Context
,
evalContext
*
EvalContext
,
notificationState
*
models
.
AlertNotificationState
)
bool
GetNotifierU
id
()
string
GetNotifierU
ID
()
string
GetIsDefault
()
bool
GetSendReminder
()
bool
GetDisableResolveMessage
()
bool
...
...
pkg/services/alerting/notifier.go
View file @
d8736a25
...
...
@@ -35,7 +35,7 @@ type notificationService struct {
}
func
(
n
*
notificationService
)
SendIfNeeded
(
context
*
EvalContext
)
error
{
notifierStates
,
err
:=
n
.
getNeededNotifiers
(
context
.
Rule
.
OrgI
d
,
context
.
Rule
.
Notifications
,
context
)
notifierStates
,
err
:=
n
.
getNeededNotifiers
(
context
.
Rule
.
OrgI
D
,
context
.
Rule
.
Notifications
,
context
)
if
err
!=
nil
{
return
err
}
...
...
@@ -56,13 +56,13 @@ func (n *notificationService) SendIfNeeded(context *EvalContext) error {
func
(
n
*
notificationService
)
sendAndMarkAsComplete
(
evalContext
*
EvalContext
,
notifierState
*
notifierState
)
error
{
notifier
:=
notifierState
.
notifier
n
.
log
.
Debug
(
"Sending notification"
,
"type"
,
notifier
.
GetType
(),
"uid"
,
notifier
.
GetNotifierU
id
(),
"isDefault"
,
notifier
.
GetIsDefault
())
n
.
log
.
Debug
(
"Sending notification"
,
"type"
,
notifier
.
GetType
(),
"uid"
,
notifier
.
GetNotifierU
ID
(),
"isDefault"
,
notifier
.
GetIsDefault
())
metrics
.
M_Alerting_Notification_Sent
.
WithLabelValues
(
notifier
.
GetType
())
.
Inc
()
err
:=
notifier
.
Notify
(
evalContext
)
if
err
!=
nil
{
n
.
log
.
Error
(
"failed to send notification"
,
"uid"
,
notifier
.
GetNotifierU
id
(),
"error"
,
err
)
n
.
log
.
Error
(
"failed to send notification"
,
"uid"
,
notifier
.
GetNotifierU
ID
(),
"error"
,
err
)
}
if
evalContext
.
IsTestRun
{
...
...
@@ -106,7 +106,7 @@ func (n *notificationService) sendNotifications(evalContext *EvalContext, notifi
for
_
,
notifierState
:=
range
notifierStates
{
err
:=
n
.
sendNotification
(
evalContext
,
notifierState
)
if
err
!=
nil
{
n
.
log
.
Error
(
"failed to send notification"
,
"uid"
,
notifierState
.
notifier
.
GetNotifierU
id
(),
"error"
,
err
)
n
.
log
.
Error
(
"failed to send notification"
,
"uid"
,
notifierState
.
notifier
.
GetNotifierU
ID
(),
"error"
,
err
)
}
}
...
...
@@ -123,7 +123,7 @@ func (n *notificationService) uploadImage(context *EvalContext) (err error) {
Width
:
1000
,
Height
:
500
,
Timeout
:
setting
.
AlertingEvaluationTimeout
,
OrgId
:
context
.
Rule
.
OrgI
d
,
OrgId
:
context
.
Rule
.
OrgI
D
,
OrgRole
:
models
.
ROLE_ADMIN
,
ConcurrentLimit
:
setting
.
AlertingRenderLimit
,
}
...
...
@@ -133,7 +133,7 @@ func (n *notificationService) uploadImage(context *EvalContext) (err error) {
return
err
}
renderOpts
.
Path
=
fmt
.
Sprintf
(
"d-solo/%s/%s?orgId=%d&panelId=%d"
,
ref
.
Uid
,
ref
.
Slug
,
context
.
Rule
.
OrgI
d
,
context
.
Rule
.
PanelId
)
renderOpts
.
Path
=
fmt
.
Sprintf
(
"d-solo/%s/%s?orgId=%d&panelId=%d"
,
ref
.
Uid
,
ref
.
Slug
,
context
.
Rule
.
OrgI
D
,
context
.
Rule
.
PanelID
)
result
,
err
:=
n
.
renderService
.
Render
(
context
.
Ctx
,
renderOpts
)
if
err
!=
nil
{
...
...
@@ -141,13 +141,13 @@ func (n *notificationService) uploadImage(context *EvalContext) (err error) {
}
context
.
ImageOnDiskPath
=
result
.
FilePath
context
.
ImagePublicU
rl
,
err
=
uploader
.
Upload
(
context
.
Ctx
,
context
.
ImageOnDiskPath
)
context
.
ImagePublicU
RL
,
err
=
uploader
.
Upload
(
context
.
Ctx
,
context
.
ImageOnDiskPath
)
if
err
!=
nil
{
return
err
}
if
context
.
ImagePublicU
rl
!=
""
{
n
.
log
.
Info
(
"uploaded screenshot of alert to external image store"
,
"url"
,
context
.
ImagePublicU
rl
)
if
context
.
ImagePublicU
RL
!=
""
{
n
.
log
.
Info
(
"uploaded screenshot of alert to external image store"
,
"url"
,
context
.
ImagePublicU
RL
)
}
return
nil
...
...
@@ -170,8 +170,8 @@ func (n *notificationService) getNeededNotifiers(orgID int64, notificationUids [
query
:=
&
models
.
GetOrCreateNotificationStateQuery
{
NotifierId
:
notification
.
Id
,
AlertId
:
evalContext
.
Rule
.
I
d
,
OrgId
:
evalContext
.
Rule
.
OrgI
d
,
AlertId
:
evalContext
.
Rule
.
I
D
,
OrgId
:
evalContext
.
Rule
.
OrgI
D
,
}
err
=
bus
.
DispatchCtx
(
evalContext
.
Ctx
,
query
)
...
...
pkg/services/alerting/notifiers/alertmanager.go
View file @
d8736a25
...
...
@@ -51,7 +51,7 @@ type AlertmanagerNotifier struct {
// ShouldNotify returns true if the notifiers should be used depending on state
func
(
am
*
AlertmanagerNotifier
)
ShouldNotify
(
ctx
context
.
Context
,
evalContext
*
alerting
.
EvalContext
,
notificationState
*
models
.
AlertNotificationState
)
bool
{
am
.
log
.
Debug
(
"Should notify"
,
"ruleId"
,
evalContext
.
Rule
.
I
d
,
"state"
,
evalContext
.
Rule
.
State
,
"previousState"
,
evalContext
.
PrevAlertState
)
am
.
log
.
Debug
(
"Should notify"
,
"ruleId"
,
evalContext
.
Rule
.
I
D
,
"state"
,
evalContext
.
Rule
.
State
,
"previousState"
,
evalContext
.
PrevAlertState
)
// Do not notify when we become OK for the first time.
if
(
evalContext
.
PrevAlertState
==
models
.
AlertStatePending
)
&&
(
evalContext
.
Rule
.
State
==
models
.
AlertStateOK
)
{
...
...
@@ -89,8 +89,8 @@ func (am *AlertmanagerNotifier) createAlert(evalContext *alerting.EvalContext, m
if
description
!=
""
{
alertJSON
.
SetPath
([]
string
{
"annotations"
,
"description"
},
description
)
}
if
evalContext
.
ImagePublicU
rl
!=
""
{
alertJSON
.
SetPath
([]
string
{
"annotations"
,
"image"
},
evalContext
.
ImagePublicU
rl
)
if
evalContext
.
ImagePublicU
RL
!=
""
{
alertJSON
.
SetPath
([]
string
{
"annotations"
,
"image"
},
evalContext
.
ImagePublicU
RL
)
}
// Labels (from metrics tags + mandatory alertname).
...
...
@@ -111,9 +111,9 @@ func (am *AlertmanagerNotifier) createAlert(evalContext *alerting.EvalContext, m
// Notify sends alert notifications to the alert manager
func
(
am
*
AlertmanagerNotifier
)
Notify
(
evalContext
*
alerting
.
EvalContext
)
error
{
am
.
log
.
Info
(
"Sending Alertmanager alert"
,
"ruleId"
,
evalContext
.
Rule
.
I
d
,
"notification"
,
am
.
Name
)
am
.
log
.
Info
(
"Sending Alertmanager alert"
,
"ruleId"
,
evalContext
.
Rule
.
I
D
,
"notification"
,
am
.
Name
)
ruleURL
,
err
:=
evalContext
.
GetRuleU
rl
()
ruleURL
,
err
:=
evalContext
.
GetRuleU
RL
()
if
err
!=
nil
{
am
.
log
.
Error
(
"Failed get rule link"
,
"error"
,
err
)
return
err
...
...
pkg/services/alerting/notifiers/base.go
View file @
d8736a25
...
...
@@ -120,8 +120,8 @@ func (n *NotifierBase) NeedsImage() bool {
return
n
.
UploadImage
}
// GetNotifierU
id
returns the notifier `uid`.
func
(
n
*
NotifierBase
)
GetNotifierU
id
()
string
{
// GetNotifierU
ID
returns the notifier `uid`.
func
(
n
*
NotifierBase
)
GetNotifierU
ID
()
string
{
return
n
.
UID
}
...
...
pkg/services/alerting/notifiers/dingding.go
View file @
d8736a25
...
...
@@ -64,7 +64,7 @@ type DingDingNotifier struct {
func
(
dd
*
DingDingNotifier
)
Notify
(
evalContext
*
alerting
.
EvalContext
)
error
{
dd
.
log
.
Info
(
"Sending dingding"
)
messageURL
,
err
:=
evalContext
.
GetRuleU
rl
()
messageURL
,
err
:=
evalContext
.
GetRuleU
RL
()
if
err
!=
nil
{
dd
.
log
.
Error
(
"Failed to get messageUrl"
,
"error"
,
err
,
"dingding"
,
dd
.
Name
)
messageURL
=
""
...
...
@@ -82,7 +82,7 @@ func (dd *DingDingNotifier) Notify(evalContext *alerting.EvalContext) error {
dd
.
log
.
Info
(
"messageUrl:"
+
messageURL
)
message
:=
evalContext
.
Rule
.
Message
picURL
:=
evalContext
.
ImagePublicU
rl
picURL
:=
evalContext
.
ImagePublicU
RL
title
:=
evalContext
.
GetNotificationTitle
()
if
message
==
""
{
message
=
title
...
...
pkg/services/alerting/notifiers/discord.go
View file @
d8736a25
...
...
@@ -21,7 +21,7 @@ func init() {
Type
:
"discord"
,
Name
:
"Discord"
,
Description
:
"Sends notifications to Discord"
,
Factory
:
N
ewDiscordNotifier
,
Factory
:
n
ewDiscordNotifier
,
OptionsTemplate
:
`
<h3 class="page-heading">Discord settings</h3>
<div class="gf-form max-width-30">
...
...
@@ -43,7 +43,7 @@ func init() {
})
}
func
N
ewDiscordNotifier
(
model
*
models
.
AlertNotification
)
(
alerting
.
Notifier
,
error
)
{
func
n
ewDiscordNotifier
(
model
*
models
.
AlertNotification
)
(
alerting
.
Notifier
,
error
)
{
content
:=
model
.
Settings
.
Get
(
"content"
)
.
MustString
()
url
:=
model
.
Settings
.
Get
(
"url"
)
.
MustString
()
if
url
==
""
{
...
...
@@ -58,6 +58,8 @@ func NewDiscordNotifier(model *models.AlertNotification) (alerting.Notifier, err
},
nil
}
// DiscordNotifier is responsible for sending alert
// notifications to discord.
type
DiscordNotifier
struct
{
NotifierBase
Content
string
...
...
@@ -65,20 +67,21 @@ type DiscordNotifier struct {
log
log
.
Logger
}
func
(
this
*
DiscordNotifier
)
Notify
(
evalContext
*
alerting
.
EvalContext
)
error
{
this
.
log
.
Info
(
"Sending alert notification to"
,
"webhook_url"
,
this
.
WebhookURL
)
// Notify send an alert notification to Discord.
func
(
dn
*
DiscordNotifier
)
Notify
(
evalContext
*
alerting
.
EvalContext
)
error
{
dn
.
log
.
Info
(
"Sending alert notification to"
,
"webhook_url"
,
dn
.
WebhookURL
)
ruleU
rl
,
err
:=
evalContext
.
GetRuleUrl
()
ruleU
RL
,
err
:=
evalContext
.
GetRuleURL
()
if
err
!=
nil
{
this
.
log
.
Error
(
"Failed get rule link"
,
"error"
,
err
)
dn
.
log
.
Error
(
"Failed get rule link"
,
"error"
,
err
)
return
err
}
bodyJSON
:=
simplejson
.
New
()
bodyJSON
.
Set
(
"username"
,
"Grafana"
)
if
this
.
Content
!=
""
{
bodyJSON
.
Set
(
"content"
,
this
.
Content
)
if
dn
.
Content
!=
""
{
bodyJSON
.
Set
(
"content"
,
dn
.
Content
)
}
fields
:=
make
([]
map
[
string
]
interface
{},
0
)
...
...
@@ -103,7 +106,7 @@ func (this *DiscordNotifier) Notify(evalContext *alerting.EvalContext) error {
embed
.
Set
(
"title"
,
evalContext
.
GetNotificationTitle
())
//Discord takes integer for color
embed
.
Set
(
"color"
,
color
)
embed
.
Set
(
"url"
,
ruleU
rl
)
embed
.
Set
(
"url"
,
ruleU
RL
)
embed
.
Set
(
"description"
,
evalContext
.
Rule
.
Message
)
embed
.
Set
(
"type"
,
"rich"
)
embed
.
Set
(
"fields"
,
fields
)
...
...
@@ -112,9 +115,9 @@ func (this *DiscordNotifier) Notify(evalContext *alerting.EvalContext) error {
var
image
map
[
string
]
interface
{}
var
embeddedImage
=
false
if
evalContext
.
ImagePublicU
rl
!=
""
{
if
evalContext
.
ImagePublicU
RL
!=
""
{
image
=
map
[
string
]
interface
{}{
"url"
:
evalContext
.
ImagePublicU
rl
,
"url"
:
evalContext
.
ImagePublicU
RL
,
}
embed
.
Set
(
"image"
,
image
)
}
else
{
...
...
@@ -130,7 +133,7 @@ func (this *DiscordNotifier) Notify(evalContext *alerting.EvalContext) error {
json
,
_
:=
bodyJSON
.
MarshalJSON
()
cmd
:=
&
models
.
SendWebhookSync
{
Url
:
this
.
WebhookURL
,
Url
:
dn
.
WebhookURL
,
HttpMethod
:
"POST"
,
ContentType
:
"application/json"
,
}
...
...
@@ -138,22 +141,22 @@ func (this *DiscordNotifier) Notify(evalContext *alerting.EvalContext) error {
if
!
embeddedImage
{
cmd
.
Body
=
string
(
json
)
}
else
{
err
:=
this
.
embedImage
(
cmd
,
evalContext
.
ImageOnDiskPath
,
json
)
err
:=
dn
.
embedImage
(
cmd
,
evalContext
.
ImageOnDiskPath
,
json
)
if
err
!=
nil
{
this
.
log
.
Error
(
"failed to embed image"
,
"error"
,
err
)
dn
.
log
.
Error
(
"failed to embed image"
,
"error"
,
err
)
return
err
}
}
if
err
:=
bus
.
DispatchCtx
(
evalContext
.
Ctx
,
cmd
);
err
!=
nil
{
this
.
log
.
Error
(
"Failed to send notification to Discord"
,
"error"
,
err
)
dn
.
log
.
Error
(
"Failed to send notification to Discord"
,
"error"
,
err
)
return
err
}
return
nil
}
func
(
this
*
DiscordNotifier
)
embedImage
(
cmd
*
models
.
SendWebhookSync
,
imagePath
string
,
existingJSONBody
[]
byte
)
error
{
func
(
dn
*
DiscordNotifier
)
embedImage
(
cmd
*
models
.
SendWebhookSync
,
imagePath
string
,
existingJSONBody
[]
byte
)
error
{
f
,
err
:=
os
.
Open
(
imagePath
)
defer
f
.
Close
()
if
err
!=
nil
{
...
...
pkg/services/alerting/notifiers/discord_test.go
View file @
d8736a25
...
...
@@ -22,7 +22,7 @@ func TestDiscordNotifier(t *testing.T) {
Settings
:
settingsJSON
,
}
_
,
err
:=
N
ewDiscordNotifier
(
model
)
_
,
err
:=
n
ewDiscordNotifier
(
model
)
So
(
err
,
ShouldNotBeNil
)
})
...
...
@@ -40,7 +40,7 @@ func TestDiscordNotifier(t *testing.T) {
Settings
:
settingsJSON
,
}
not
,
err
:=
N
ewDiscordNotifier
(
model
)
not
,
err
:=
n
ewDiscordNotifier
(
model
)
discordNotifier
:=
not
.
(
*
DiscordNotifier
)
So
(
err
,
ShouldBeNil
)
...
...
pkg/services/alerting/notifiers/email.go
View file @
d8736a25
...
...
@@ -67,7 +67,7 @@ func NewEmailNotifier(model *models.AlertNotification) (alerting.Notifier, error
func
(
en
*
EmailNotifier
)
Notify
(
evalContext
*
alerting
.
EvalContext
)
error
{
en
.
log
.
Info
(
"Sending alert notification to"
,
"addresses"
,
en
.
Addresses
)
ruleURL
,
err
:=
evalContext
.
GetRuleU
rl
()
ruleURL
,
err
:=
evalContext
.
GetRuleU
RL
()
if
err
!=
nil
{
en
.
log
.
Error
(
"Failed get rule link"
,
"error"
,
err
)
return
err
...
...
@@ -100,8 +100,8 @@ func (en *EmailNotifier) Notify(evalContext *alerting.EvalContext) error {
},
}
if
evalContext
.
ImagePublicU
rl
!=
""
{
cmd
.
Data
[
"ImageLink"
]
=
evalContext
.
ImagePublicU
rl
if
evalContext
.
ImagePublicU
RL
!=
""
{
cmd
.
Data
[
"ImageLink"
]
=
evalContext
.
ImagePublicU
RL
}
else
{
file
,
err
:=
os
.
Stat
(
evalContext
.
ImageOnDiskPath
)
if
err
==
nil
{
...
...
pkg/services/alerting/notifiers/googlechat.go
View file @
d8736a25
...
...
@@ -120,7 +120,7 @@ func (gcn *GoogleChatNotifier) Notify(evalContext *alerting.EvalContext) error {
"Content-Type"
:
"application/json; charset=UTF-8"
,
}
ruleURL
,
err
:=
evalContext
.
GetRuleU
rl
()
ruleURL
,
err
:=
evalContext
.
GetRuleU
RL
()
if
err
!=
nil
{
gcn
.
log
.
Error
(
"evalContext returned an invalid rule URL"
)
}
...
...
@@ -152,10 +152,10 @@ func (gcn *GoogleChatNotifier) Notify(evalContext *alerting.EvalContext) error {
widgets
=
append
(
widgets
,
fields
)
// if an image exists, add it as an image widget
if
evalContext
.
ImagePublicU
rl
!=
""
{
if
evalContext
.
ImagePublicU
RL
!=
""
{
widgets
=
append
(
widgets
,
imageWidget
{
Image
:
image
{
ImageURL
:
evalContext
.
ImagePublicU
rl
,
ImageURL
:
evalContext
.
ImagePublicU
RL
,
},
})
}
else
{
...
...
pkg/services/alerting/notifiers/hipchat.go
View file @
d8736a25
...
...
@@ -81,9 +81,9 @@ type HipChatNotifier struct {
// Notify sends an alert notification to HipChat
func
(
hc
*
HipChatNotifier
)
Notify
(
evalContext
*
alerting
.
EvalContext
)
error
{
hc
.
log
.
Info
(
"Executing hipchat notification"
,
"ruleId"
,
evalContext
.
Rule
.
I
d
,
"notification"
,
hc
.
Name
)
hc
.
log
.
Info
(
"Executing hipchat notification"
,
"ruleId"
,
evalContext
.
Rule
.
I
D
,
"notification"
,
hc
.
Name
)
ruleURL
,
err
:=
evalContext
.
GetRuleU
rl
()
ruleURL
,
err
:=
evalContext
.
GetRuleU
RL
()
if
err
!=
nil
{
hc
.
log
.
Error
(
"Failed get rule link"
,
"error"
,
err
)
return
err
...
...
@@ -148,10 +148,10 @@ func (hc *HipChatNotifier) Notify(evalContext *alerting.EvalContext) error {
"date"
:
evalContext
.
EndTime
.
Unix
(),
"attributes"
:
attributes
,
}
if
evalContext
.
ImagePublicU
rl
!=
""
{
if
evalContext
.
ImagePublicU
RL
!=
""
{
card
[
"thumbnail"
]
=
map
[
string
]
interface
{}{
"url"
:
evalContext
.
ImagePublicU
rl
,
"url@2x"
:
evalContext
.
ImagePublicU
rl
,
"url"
:
evalContext
.
ImagePublicU
RL
,
"url@2x"
:
evalContext
.
ImagePublicU
RL
,
"width"
:
1193
,
"height"
:
564
,
}
...
...
pkg/services/alerting/notifiers/kafka.go
View file @
d8736a25
...
...
@@ -78,20 +78,20 @@ func (kn *KafkaNotifier) Notify(evalContext *alerting.EvalContext) error {
bodyJSON
.
Set
(
"description"
,
evalContext
.
Rule
.
Name
+
" - "
+
evalContext
.
Rule
.
Message
)
bodyJSON
.
Set
(
"client"
,
"Grafana"
)
bodyJSON
.
Set
(
"details"
,
customData
)
bodyJSON
.
Set
(
"incident_key"
,
"alertId-"
+
strconv
.
FormatInt
(
evalContext
.
Rule
.
I
d
,
10
))
bodyJSON
.
Set
(
"incident_key"
,
"alertId-"
+
strconv
.
FormatInt
(
evalContext
.
Rule
.
I
D
,
10
))
ruleURL
,
err
:=
evalContext
.
GetRuleU
rl
()
ruleURL
,
err
:=
evalContext
.
GetRuleU
RL
()
if
err
!=
nil
{
kn
.
log
.
Error
(
"Failed get rule link"
,
"error"
,
err
)
return
err
}
bodyJSON
.
Set
(
"client_url"
,
ruleURL
)
if
evalContext
.
ImagePublicU
rl
!=
""
{
if
evalContext
.
ImagePublicU
RL
!=
""
{
contexts
:=
make
([]
interface
{},
1
)
imageJSON
:=
simplejson
.
New
()
imageJSON
.
Set
(
"type"
,
"image"
)
imageJSON
.
Set
(
"src"
,
evalContext
.
ImagePublicU
rl
)
imageJSON
.
Set
(
"src"
,
evalContext
.
ImagePublicU
RL
)
contexts
[
0
]
=
imageJSON
bodyJSON
.
Set
(
"contexts"
,
contexts
)
}
...
...
pkg/services/alerting/notifiers/line.go
View file @
d8736a25
...
...
@@ -56,7 +56,7 @@ type LineNotifier struct {
// Notify send an alert notification to LINE
func
(
ln
*
LineNotifier
)
Notify
(
evalContext
*
alerting
.
EvalContext
)
error
{
ln
.
log
.
Info
(
"Executing line notification"
,
"ruleId"
,
evalContext
.
Rule
.
I
d
,
"notification"
,
ln
.
Name
)
ln
.
log
.
Info
(
"Executing line notification"
,
"ruleId"
,
evalContext
.
Rule
.
I
D
,
"notification"
,
ln
.
Name
)
var
err
error
switch
evalContext
.
Rule
.
State
{
...
...
@@ -67,8 +67,8 @@ func (ln *LineNotifier) Notify(evalContext *alerting.EvalContext) error {
}
func
(
ln
*
LineNotifier
)
createAlert
(
evalContext
*
alerting
.
EvalContext
)
error
{
ln
.
log
.
Info
(
"Creating Line notify"
,
"ruleId"
,
evalContext
.
Rule
.
I
d
,
"notification"
,
ln
.
Name
)
ruleURL
,
err
:=
evalContext
.
GetRuleU
rl
()
ln
.
log
.
Info
(
"Creating Line notify"
,
"ruleId"
,
evalContext
.
Rule
.
I
D
,
"notification"
,
ln
.
Name
)
ruleURL
,
err
:=
evalContext
.
GetRuleU
RL
()
if
err
!=
nil
{
ln
.
log
.
Error
(
"Failed get rule link"
,
"error"
,
err
)
return
err
...
...
@@ -78,9 +78,9 @@ func (ln *LineNotifier) createAlert(evalContext *alerting.EvalContext) error {
body
:=
fmt
.
Sprintf
(
"%s - %s
\n
%s"
,
evalContext
.
Rule
.
Name
,
ruleURL
,
evalContext
.
Rule
.
Message
)
form
.
Add
(
"message"
,
body
)
if
evalContext
.
ImagePublicU
rl
!=
""
{
form
.
Add
(
"imageThumbnail"
,
evalContext
.
ImagePublicU
rl
)
form
.
Add
(
"imageFullsize"
,
evalContext
.
ImagePublicU
rl
)
if
evalContext
.
ImagePublicU
RL
!=
""
{
form
.
Add
(
"imageThumbnail"
,
evalContext
.
ImagePublicU
RL
)
form
.
Add
(
"imageFullsize"
,
evalContext
.
ImagePublicU
RL
)
}
cmd
:=
&
models
.
SendWebhookSync
{
...
...
pkg/services/alerting/notifiers/opsgenie.go
View file @
d8736a25
...
...
@@ -90,9 +90,9 @@ func (on *OpsGenieNotifier) Notify(evalContext *alerting.EvalContext) error {
}
func
(
on
*
OpsGenieNotifier
)
createAlert
(
evalContext
*
alerting
.
EvalContext
)
error
{
on
.
log
.
Info
(
"Creating OpsGenie alert"
,
"ruleId"
,
evalContext
.
Rule
.
I
d
,
"notification"
,
on
.
Name
)
on
.
log
.
Info
(
"Creating OpsGenie alert"
,
"ruleId"
,
evalContext
.
Rule
.
I
D
,
"notification"
,
on
.
Name
)
ruleURL
,
err
:=
evalContext
.
GetRuleU
rl
()
ruleURL
,
err
:=
evalContext
.
GetRuleU
RL
()
if
err
!=
nil
{
on
.
log
.
Error
(
"Failed get rule link"
,
"error"
,
err
)
return
err
...
...
@@ -106,13 +106,13 @@ func (on *OpsGenieNotifier) createAlert(evalContext *alerting.EvalContext) error
bodyJSON
:=
simplejson
.
New
()
bodyJSON
.
Set
(
"message"
,
evalContext
.
Rule
.
Name
)
bodyJSON
.
Set
(
"source"
,
"Grafana"
)
bodyJSON
.
Set
(
"alias"
,
"alertId-"
+
strconv
.
FormatInt
(
evalContext
.
Rule
.
I
d
,
10
))
bodyJSON
.
Set
(
"alias"
,
"alertId-"
+
strconv
.
FormatInt
(
evalContext
.
Rule
.
I
D
,
10
))
bodyJSON
.
Set
(
"description"
,
fmt
.
Sprintf
(
"%s - %s
\n
%s
\n
%s"
,
evalContext
.
Rule
.
Name
,
ruleURL
,
evalContext
.
Rule
.
Message
,
customData
))
details
:=
simplejson
.
New
()
details
.
Set
(
"url"
,
ruleURL
)
if
evalContext
.
ImagePublicU
rl
!=
""
{
details
.
Set
(
"image"
,
evalContext
.
ImagePublicU
rl
)
if
evalContext
.
ImagePublicU
RL
!=
""
{
details
.
Set
(
"image"
,
evalContext
.
ImagePublicU
RL
)
}
bodyJSON
.
Set
(
"details"
,
details
)
...
...
@@ -136,14 +136,14 @@ func (on *OpsGenieNotifier) createAlert(evalContext *alerting.EvalContext) error
}
func
(
on
*
OpsGenieNotifier
)
closeAlert
(
evalContext
*
alerting
.
EvalContext
)
error
{
on
.
log
.
Info
(
"Closing OpsGenie alert"
,
"ruleId"
,
evalContext
.
Rule
.
I
d
,
"notification"
,
on
.
Name
)
on
.
log
.
Info
(
"Closing OpsGenie alert"
,
"ruleId"
,
evalContext
.
Rule
.
I
D
,
"notification"
,
on
.
Name
)
bodyJSON
:=
simplejson
.
New
()
bodyJSON
.
Set
(
"source"
,
"Grafana"
)
body
,
_
:=
bodyJSON
.
MarshalJSON
()
cmd
:=
&
models
.
SendWebhookSync
{
Url
:
fmt
.
Sprintf
(
"%s/alertId-%d/close?identifierType=alias"
,
on
.
APIUrl
,
evalContext
.
Rule
.
I
d
),
Url
:
fmt
.
Sprintf
(
"%s/alertId-%d/close?identifierType=alias"
,
on
.
APIUrl
,
evalContext
.
Rule
.
I
D
),
Body
:
string
(
body
),
HttpMethod
:
"POST"
,
HttpHeader
:
map
[
string
]
string
{
...
...
pkg/services/alerting/notifiers/pagerduty.go
View file @
d8736a25
...
...
@@ -100,10 +100,10 @@ func (pn *PagerdutyNotifier) Notify(evalContext *alerting.EvalContext) error {
bodyJSON
:=
simplejson
.
New
()
bodyJSON
.
Set
(
"routing_key"
,
pn
.
Key
)
bodyJSON
.
Set
(
"event_action"
,
eventType
)
bodyJSON
.
Set
(
"dedup_key"
,
"alertId-"
+
strconv
.
FormatInt
(
evalContext
.
Rule
.
I
d
,
10
))
bodyJSON
.
Set
(
"dedup_key"
,
"alertId-"
+
strconv
.
FormatInt
(
evalContext
.
Rule
.
I
D
,
10
))
bodyJSON
.
Set
(
"payload"
,
payloadJSON
)
ruleURL
,
err
:=
evalContext
.
GetRuleU
rl
()
ruleURL
,
err
:=
evalContext
.
GetRuleU
RL
()
if
err
!=
nil
{
pn
.
log
.
Error
(
"Failed get rule link"
,
"error"
,
err
)
return
err
...
...
@@ -116,10 +116,10 @@ func (pn *PagerdutyNotifier) Notify(evalContext *alerting.EvalContext) error {
links
[
0
]
=
linkJSON
bodyJSON
.
Set
(
"links"
,
links
)
if
evalContext
.
ImagePublicU
rl
!=
""
{
if
evalContext
.
ImagePublicU
RL
!=
""
{
contexts
:=
make
([]
interface
{},
1
)
imageJSON
:=
simplejson
.
New
()
imageJSON
.
Set
(
"src"
,
evalContext
.
ImagePublicU
rl
)
imageJSON
.
Set
(
"src"
,
evalContext
.
ImagePublicU
RL
)
contexts
[
0
]
=
imageJSON
bodyJSON
.
Set
(
"images"
,
contexts
)
}
...
...
pkg/services/alerting/notifiers/pushover.go
View file @
d8736a25
...
...
@@ -146,7 +146,7 @@ type PushoverNotifier struct {
// Notify sends a alert notification to Pushover
func
(
pn
*
PushoverNotifier
)
Notify
(
evalContext
*
alerting
.
EvalContext
)
error
{
ruleURL
,
err
:=
evalContext
.
GetRuleU
rl
()
ruleURL
,
err
:=
evalContext
.
GetRuleU
RL
()
if
err
!=
nil
{
pn
.
log
.
Error
(
"Failed get rule link"
,
"error"
,
err
)
return
err
...
...
pkg/services/alerting/notifiers/sensu.go
View file @
d8736a25
...
...
@@ -79,7 +79,7 @@ func (sn *SensuNotifier) Notify(evalContext *alerting.EvalContext) error {
sn
.
log
.
Info
(
"Sending sensu result"
)
bodyJSON
:=
simplejson
.
New
()
bodyJSON
.
Set
(
"ruleId"
,
evalContext
.
Rule
.
I
d
)
bodyJSON
.
Set
(
"ruleId"
,
evalContext
.
Rule
.
I
D
)
// Sensu alerts cannot have spaces in them
bodyJSON
.
Set
(
"name"
,
strings
.
Replace
(
evalContext
.
Rule
.
Name
,
" "
,
"_"
,
-
1
))
// Sensu alerts require a source. We set it to the user-specified value (optional),
...
...
@@ -87,7 +87,7 @@ func (sn *SensuNotifier) Notify(evalContext *alerting.EvalContext) error {
if
sn
.
Source
!=
""
{
bodyJSON
.
Set
(
"source"
,
sn
.
Source
)
}
else
{
bodyJSON
.
Set
(
"source"
,
"grafana_rule_"
+
strconv
.
FormatInt
(
evalContext
.
Rule
.
I
d
,
10
))
bodyJSON
.
Set
(
"source"
,
"grafana_rule_"
+
strconv
.
FormatInt
(
evalContext
.
Rule
.
I
D
,
10
))
}
// Finally, sensu expects an output
// We set it to a default output
...
...
@@ -106,13 +106,13 @@ func (sn *SensuNotifier) Notify(evalContext *alerting.EvalContext) error {
bodyJSON
.
Set
(
"handler"
,
sn
.
Handler
)
}
ruleURL
,
err
:=
evalContext
.
GetRuleU
rl
()
ruleURL
,
err
:=
evalContext
.
GetRuleU
RL
()
if
err
==
nil
{
bodyJSON
.
Set
(
"ruleUrl"
,
ruleURL
)
}
if
evalContext
.
ImagePublicU
rl
!=
""
{
bodyJSON
.
Set
(
"imageUrl"
,
evalContext
.
ImagePublicU
rl
)
if
evalContext
.
ImagePublicU
RL
!=
""
{
bodyJSON
.
Set
(
"imageUrl"
,
evalContext
.
ImagePublicU
RL
)
}
if
evalContext
.
Rule
.
Message
!=
""
{
...
...
pkg/services/alerting/notifiers/slack.go
View file @
d8736a25
...
...
@@ -145,9 +145,9 @@ type SlackNotifier struct {
// Notify send alert notification to Slack.
func
(
sn
*
SlackNotifier
)
Notify
(
evalContext
*
alerting
.
EvalContext
)
error
{
sn
.
log
.
Info
(
"Executing slack notification"
,
"ruleId"
,
evalContext
.
Rule
.
I
d
,
"notification"
,
sn
.
Name
)
sn
.
log
.
Info
(
"Executing slack notification"
,
"ruleId"
,
evalContext
.
Rule
.
I
D
,
"notification"
,
sn
.
Name
)
ruleURL
,
err
:=
evalContext
.
GetRuleU
rl
()
ruleURL
,
err
:=
evalContext
.
GetRuleU
RL
()
if
err
!=
nil
{
sn
.
log
.
Error
(
"Failed get rule link"
,
"error"
,
err
)
return
err
...
...
@@ -181,7 +181,7 @@ func (sn *SlackNotifier) Notify(evalContext *alerting.EvalContext) error {
imageURL
:=
""
// default to file.upload API method if a token is provided
if
sn
.
Token
==
""
{
imageURL
=
evalContext
.
ImagePublicU
rl
imageURL
=
evalContext
.
ImagePublicU
RL
}
body
:=
map
[
string
]
interface
{}{
...
...
pkg/services/alerting/notifiers/teams.go
View file @
d8736a25
...
...
@@ -50,9 +50,9 @@ type TeamsNotifier struct {
// Notify send an alert notification to Microsoft teams.
func
(
tn
*
TeamsNotifier
)
Notify
(
evalContext
*
alerting
.
EvalContext
)
error
{
tn
.
log
.
Info
(
"Executing teams notification"
,
"ruleId"
,
evalContext
.
Rule
.
I
d
,
"notification"
,
tn
.
Name
)
tn
.
log
.
Info
(
"Executing teams notification"
,
"ruleId"
,
evalContext
.
Rule
.
I
D
,
"notification"
,
tn
.
Name
)
ruleURL
,
err
:=
evalContext
.
GetRuleU
rl
()
ruleURL
,
err
:=
evalContext
.
GetRuleU
RL
()
if
err
!=
nil
{
tn
.
log
.
Error
(
"Failed get rule link"
,
"error"
,
err
)
return
err
...
...
@@ -83,9 +83,9 @@ func (tn *TeamsNotifier) Notify(evalContext *alerting.EvalContext) error {
}
images
:=
make
([]
map
[
string
]
interface
{},
0
)
if
evalContext
.
ImagePublicU
rl
!=
""
{
if
evalContext
.
ImagePublicU
RL
!=
""
{
images
=
append
(
images
,
map
[
string
]
interface
{}{
"image"
:
evalContext
.
ImagePublicU
rl
,
"image"
:
evalContext
.
ImagePublicU
RL
,
})
}
...
...
@@ -122,7 +122,7 @@ func (tn *TeamsNotifier) Notify(evalContext *alerting.EvalContext) error {
"name"
:
"View Graph"
,
"targets"
:
[]
map
[
string
]
interface
{}{
{
"os"
:
"default"
,
"uri"
:
evalContext
.
ImagePublicU
rl
,
"os"
:
"default"
,
"uri"
:
evalContext
.
ImagePublicU
RL
,
},
},
},
...
...
pkg/services/alerting/notifiers/telegram.go
View file @
d8736a25
...
...
@@ -104,13 +104,13 @@ func (tn *TelegramNotifier) buildMessage(evalContext *alerting.EvalContext, send
func
(
tn
*
TelegramNotifier
)
buildMessageLinkedImage
(
evalContext
*
alerting
.
EvalContext
)
*
models
.
SendWebhookSync
{
message
:=
fmt
.
Sprintf
(
"<b>%s</b>
\n
State: %s
\n
Message: %s
\n
"
,
evalContext
.
GetNotificationTitle
(),
evalContext
.
Rule
.
Name
,
evalContext
.
Rule
.
Message
)
ruleURL
,
err
:=
evalContext
.
GetRuleU
rl
()
ruleURL
,
err
:=
evalContext
.
GetRuleU
RL
()
if
err
==
nil
{
message
=
message
+
fmt
.
Sprintf
(
"URL: %s
\n
"
,
ruleURL
)
}
if
evalContext
.
ImagePublicU
rl
!=
""
{
message
=
message
+
fmt
.
Sprintf
(
"Image: %s
\n
"
,
evalContext
.
ImagePublicU
rl
)
if
evalContext
.
ImagePublicU
RL
!=
""
{
message
=
message
+
fmt
.
Sprintf
(
"Image: %s
\n
"
,
evalContext
.
ImagePublicU
RL
)
}
metrics
:=
generateMetricsMessage
(
evalContext
)
...
...
@@ -141,7 +141,7 @@ func (tn *TelegramNotifier) buildMessageInlineImage(evalContext *alerting.EvalCo
return
nil
,
err
}
ruleURL
,
err
:=
evalContext
.
GetRuleU
rl
()
ruleURL
,
err
:=
evalContext
.
GetRuleU
RL
()
if
err
!=
nil
{
return
nil
,
err
}
...
...
@@ -232,7 +232,7 @@ func appendIfPossible(message string, extra string, sizeLimit int) string {
// Notify send an alert notification to Telegram.
func
(
tn
*
TelegramNotifier
)
Notify
(
evalContext
*
alerting
.
EvalContext
)
error
{
var
cmd
*
models
.
SendWebhookSync
if
evalContext
.
ImagePublicU
rl
==
""
&&
tn
.
UploadImage
{
if
evalContext
.
ImagePublicU
RL
==
""
&&
tn
.
UploadImage
{
cmd
=
tn
.
buildMessage
(
evalContext
,
true
)
}
else
{
cmd
=
tn
.
buildMessage
(
evalContext
,
false
)
...
...
pkg/services/alerting/notifiers/threema.go
View file @
d8736a25
...
...
@@ -143,12 +143,12 @@ func (notifier *ThreemaNotifier) Notify(evalContext *alerting.EvalContext) error
message
:=
fmt
.
Sprintf
(
"%s%s
\n\n
*State:* %s
\n
*Message:* %s
\n
"
,
stateEmoji
,
evalContext
.
GetNotificationTitle
(),
evalContext
.
Rule
.
Name
,
evalContext
.
Rule
.
Message
)
ruleURL
,
err
:=
evalContext
.
GetRuleU
rl
()
ruleURL
,
err
:=
evalContext
.
GetRuleU
RL
()
if
err
==
nil
{
message
=
message
+
fmt
.
Sprintf
(
"*URL:* %s
\n
"
,
ruleURL
)
}
if
evalContext
.
ImagePublicU
rl
!=
""
{
message
=
message
+
fmt
.
Sprintf
(
"*Image:* %s
\n
"
,
evalContext
.
ImagePublicU
rl
)
if
evalContext
.
ImagePublicU
RL
!=
""
{
message
=
message
+
fmt
.
Sprintf
(
"*Image:* %s
\n
"
,
evalContext
.
ImagePublicU
RL
)
}
data
.
Set
(
"text"
,
message
)
...
...
pkg/services/alerting/notifiers/victorops.go
View file @
d8736a25
...
...
@@ -70,9 +70,9 @@ type VictoropsNotifier struct {
// Notify sends notification to Victorops via POST to URL endpoint
func
(
vn
*
VictoropsNotifier
)
Notify
(
evalContext
*
alerting
.
EvalContext
)
error
{
vn
.
log
.
Info
(
"Executing victorops notification"
,
"ruleId"
,
evalContext
.
Rule
.
I
d
,
"notification"
,
vn
.
Name
)
vn
.
log
.
Info
(
"Executing victorops notification"
,
"ruleId"
,
evalContext
.
Rule
.
I
D
,
"notification"
,
vn
.
Name
)
ruleURL
,
err
:=
evalContext
.
GetRuleU
rl
()
ruleURL
,
err
:=
evalContext
.
GetRuleU
RL
()
if
err
!=
nil
{
vn
.
log
.
Error
(
"Failed get rule link"
,
"error"
,
err
)
return
err
...
...
@@ -116,8 +116,8 @@ func (vn *VictoropsNotifier) Notify(evalContext *alerting.EvalContext) error {
bodyJSON
.
Set
(
"error_message"
,
evalContext
.
Error
.
Error
())
}
if
evalContext
.
ImagePublicU
rl
!=
""
{
bodyJSON
.
Set
(
"image_url"
,
evalContext
.
ImagePublicU
rl
)
if
evalContext
.
ImagePublicU
RL
!=
""
{
bodyJSON
.
Set
(
"image_url"
,
evalContext
.
ImagePublicU
RL
)
}
data
,
_
:=
bodyJSON
.
MarshalJSON
()
...
...
pkg/services/alerting/notifiers/webhook.go
View file @
d8736a25
...
...
@@ -76,18 +76,18 @@ func (wn *WebhookNotifier) Notify(evalContext *alerting.EvalContext) error {
bodyJSON
:=
simplejson
.
New
()
bodyJSON
.
Set
(
"title"
,
evalContext
.
GetNotificationTitle
())
bodyJSON
.
Set
(
"ruleId"
,
evalContext
.
Rule
.
I
d
)
bodyJSON
.
Set
(
"ruleId"
,
evalContext
.
Rule
.
I
D
)
bodyJSON
.
Set
(
"ruleName"
,
evalContext
.
Rule
.
Name
)
bodyJSON
.
Set
(
"state"
,
evalContext
.
Rule
.
State
)
bodyJSON
.
Set
(
"evalMatches"
,
evalContext
.
EvalMatches
)
ruleURL
,
err
:=
evalContext
.
GetRuleU
rl
()
ruleURL
,
err
:=
evalContext
.
GetRuleU
RL
()
if
err
==
nil
{
bodyJSON
.
Set
(
"ruleUrl"
,
ruleURL
)
}
if
evalContext
.
ImagePublicU
rl
!=
""
{
bodyJSON
.
Set
(
"imageUrl"
,
evalContext
.
ImagePublicU
rl
)
if
evalContext
.
ImagePublicU
RL
!=
""
{
bodyJSON
.
Set
(
"imageUrl"
,
evalContext
.
ImagePublicU
RL
)
}
if
evalContext
.
Rule
.
Message
!=
""
{
...
...
pkg/services/alerting/result_handler.go
View file @
d8736a25
...
...
@@ -46,11 +46,11 @@ func (handler *defaultResultHandler) handle(evalContext *EvalContext) error {
metrics
.
M_Alerting_Result_State
.
WithLabelValues
(
string
(
evalContext
.
Rule
.
State
))
.
Inc
()
if
evalContext
.
shouldUpdateAlertState
()
{
handler
.
log
.
Info
(
"New state change"
,
"alertId"
,
evalContext
.
Rule
.
I
d
,
"newState"
,
evalContext
.
Rule
.
State
,
"prev state"
,
evalContext
.
PrevAlertState
)
handler
.
log
.
Info
(
"New state change"
,
"alertId"
,
evalContext
.
Rule
.
I
D
,
"newState"
,
evalContext
.
Rule
.
State
,
"prev state"
,
evalContext
.
PrevAlertState
)
cmd
:=
&
models
.
SetAlertStateCommand
{
AlertId
:
evalContext
.
Rule
.
I
d
,
OrgId
:
evalContext
.
Rule
.
OrgI
d
,
AlertId
:
evalContext
.
Rule
.
I
D
,
OrgId
:
evalContext
.
Rule
.
OrgI
D
,
State
:
evalContext
.
Rule
.
State
,
Error
:
executionError
,
EvalData
:
annotationData
,
...
...
@@ -81,10 +81,10 @@ func (handler *defaultResultHandler) handle(evalContext *EvalContext) error {
// save annotation
item
:=
annotations
.
Item
{
OrgId
:
evalContext
.
Rule
.
OrgI
d
,
DashboardId
:
evalContext
.
Rule
.
DashboardI
d
,
PanelId
:
evalContext
.
Rule
.
PanelI
d
,
AlertId
:
evalContext
.
Rule
.
I
d
,
OrgId
:
evalContext
.
Rule
.
OrgI
D
,
DashboardId
:
evalContext
.
Rule
.
DashboardI
D
,
PanelId
:
evalContext
.
Rule
.
PanelI
D
,
AlertId
:
evalContext
.
Rule
.
I
D
,
Text
:
""
,
NewState
:
string
(
evalContext
.
Rule
.
State
),
PrevState
:
string
(
evalContext
.
PrevAlertState
),
...
...
pkg/services/alerting/rule.go
View file @
d8736a25
...
...
@@ -21,10 +21,10 @@ var (
// Rule is the in-memory version of an alert rule.
type
Rule
struct
{
I
d
int64
OrgI
d
int64
DashboardI
d
int64
PanelI
d
int64
I
D
int64
OrgI
D
int64
DashboardI
D
int64
PanelI
D
int64
Frequency
int64
Name
string
Message
string
...
...
@@ -44,23 +44,23 @@ type Rule struct {
type
ValidationError
struct
{
Reason
string
Err
error
Alert
id
int64
DashboardI
d
int64
PanelI
d
int64
Alert
ID
int64
DashboardI
D
int64
PanelI
D
int64
}
func
(
e
ValidationError
)
Error
()
string
{
extraInfo
:=
e
.
Reason
if
e
.
Alert
id
!=
0
{
extraInfo
=
fmt
.
Sprintf
(
"%s AlertId: %v"
,
extraInfo
,
e
.
Alert
id
)
if
e
.
Alert
ID
!=
0
{
extraInfo
=
fmt
.
Sprintf
(
"%s AlertId: %v"
,
extraInfo
,
e
.
Alert
ID
)
}
if
e
.
PanelI
d
!=
0
{
extraInfo
=
fmt
.
Sprintf
(
"%s PanelId: %v"
,
extraInfo
,
e
.
PanelI
d
)
if
e
.
PanelI
D
!=
0
{
extraInfo
=
fmt
.
Sprintf
(
"%s PanelId: %v"
,
extraInfo
,
e
.
PanelI
D
)
}
if
e
.
DashboardI
d
!=
0
{
extraInfo
=
fmt
.
Sprintf
(
"%s DashboardId: %v"
,
extraInfo
,
e
.
DashboardI
d
)
if
e
.
DashboardI
D
!=
0
{
extraInfo
=
fmt
.
Sprintf
(
"%s DashboardId: %v"
,
extraInfo
,
e
.
DashboardI
D
)
}
if
e
.
Err
!=
nil
{
...
...
@@ -113,10 +113,10 @@ func getTimeDurationStringToSeconds(str string) (int64, error) {
// alert to an in-memory version.
func
NewRuleFromDBAlert
(
ruleDef
*
models
.
Alert
)
(
*
Rule
,
error
)
{
model
:=
&
Rule
{}
model
.
I
d
=
ruleDef
.
Id
model
.
OrgI
d
=
ruleDef
.
OrgId
model
.
DashboardI
d
=
ruleDef
.
DashboardId
model
.
PanelI
d
=
ruleDef
.
PanelId
model
.
I
D
=
ruleDef
.
Id
model
.
OrgI
D
=
ruleDef
.
OrgId
model
.
DashboardI
D
=
ruleDef
.
DashboardId
model
.
PanelI
D
=
ruleDef
.
PanelId
model
.
Name
=
ruleDef
.
Name
model
.
Message
=
ruleDef
.
Message
model
.
State
=
ruleDef
.
State
...
...
@@ -140,7 +140,7 @@ func NewRuleFromDBAlert(ruleDef *models.Alert) (*Rule, error) {
}
else
{
uid
,
err
:=
jsonModel
.
Get
(
"uid"
)
.
String
()
if
err
!=
nil
{
return
nil
,
ValidationError
{
Reason
:
"Neither id nor uid is specified, "
+
err
.
Error
(),
DashboardI
d
:
model
.
DashboardId
,
Alertid
:
model
.
Id
,
PanelId
:
model
.
PanelId
}
return
nil
,
ValidationError
{
Reason
:
"Neither id nor uid is specified, "
+
err
.
Error
(),
DashboardI
D
:
model
.
DashboardID
,
AlertID
:
model
.
ID
,
PanelID
:
model
.
PanelID
}
}
model
.
Notifications
=
append
(
model
.
Notifications
,
uid
)
}
...
...
@@ -151,11 +151,11 @@ func NewRuleFromDBAlert(ruleDef *models.Alert) (*Rule, error) {
conditionType
:=
conditionModel
.
Get
(
"type"
)
.
MustString
()
factory
,
exist
:=
conditionFactories
[
conditionType
]
if
!
exist
{
return
nil
,
ValidationError
{
Reason
:
"Unknown alert condition: "
+
conditionType
,
DashboardI
d
:
model
.
DashboardId
,
Alertid
:
model
.
Id
,
PanelId
:
model
.
PanelId
}
return
nil
,
ValidationError
{
Reason
:
"Unknown alert condition: "
+
conditionType
,
DashboardI
D
:
model
.
DashboardID
,
AlertID
:
model
.
ID
,
PanelID
:
model
.
PanelID
}
}
queryCondition
,
err
:=
factory
(
conditionModel
,
index
)
if
err
!=
nil
{
return
nil
,
ValidationError
{
Err
:
err
,
DashboardI
d
:
model
.
DashboardId
,
Alertid
:
model
.
Id
,
PanelId
:
model
.
PanelId
}
return
nil
,
ValidationError
{
Err
:
err
,
DashboardI
D
:
model
.
DashboardID
,
AlertID
:
model
.
ID
,
PanelID
:
model
.
PanelID
}
}
model
.
Conditions
=
append
(
model
.
Conditions
,
queryCondition
)
}
...
...
pkg/services/alerting/scheduler.go
View file @
d8736a25
...
...
@@ -27,8 +27,8 @@ func (s *schedulerImpl) Update(rules []*Rule) {
for
i
,
rule
:=
range
rules
{
var
job
*
Job
if
s
.
jobs
[
rule
.
I
d
]
!=
nil
{
job
=
s
.
jobs
[
rule
.
I
d
]
if
s
.
jobs
[
rule
.
I
D
]
!=
nil
{
job
=
s
.
jobs
[
rule
.
I
D
]
}
else
{
job
=
&
Job
{
Running
:
false
,
...
...
@@ -42,7 +42,7 @@ func (s *schedulerImpl) Update(rules []*Rule) {
if
job
.
Offset
==
0
{
//zero offset causes division with 0 panics.
job
.
Offset
=
1
}
jobs
[
rule
.
I
d
]
=
job
jobs
[
rule
.
I
D
]
=
job
}
s
.
jobs
=
jobs
...
...
@@ -73,6 +73,6 @@ func (s *schedulerImpl) Tick(tickTime time.Time, execQueue chan *Job) {
}
func
(
s
*
schedulerImpl
)
enqueue
(
job
*
Job
,
execQueue
chan
*
Job
)
{
s
.
log
.
Debug
(
"Scheduler: Putting job on to exec queue"
,
"name"
,
job
.
Rule
.
Name
,
"id"
,
job
.
Rule
.
I
d
)
s
.
log
.
Debug
(
"Scheduler: Putting job on to exec queue"
,
"name"
,
job
.
Rule
.
Name
,
"id"
,
job
.
Rule
.
I
D
)
execQueue
<-
job
}
pkg/services/alerting/test_notification.go
View file @
d8736a25
...
...
@@ -49,8 +49,8 @@ func handleNotificationTestCommand(cmd *NotificationTestCommand) error {
func
createTestEvalContext
(
cmd
*
NotificationTestCommand
)
*
EvalContext
{
testRule
:=
&
Rule
{
DashboardI
d
:
1
,
PanelI
d
:
1
,
DashboardI
D
:
1
,
PanelI
D
:
1
,
Name
:
"Test notification"
,
Message
:
"Someone is testing the alert notification within grafana."
,
State
:
models
.
AlertStateAlerting
,
...
...
@@ -58,7 +58,7 @@ func createTestEvalContext(cmd *NotificationTestCommand) *EvalContext {
ctx
:=
NewEvalContext
(
context
.
Background
(),
testRule
)
if
cmd
.
Settings
.
Get
(
"uploadImage"
)
.
MustBool
(
true
)
{
ctx
.
ImagePublicU
rl
=
"https://grafana.com/assets/img/blog/mixed_styles.png"
ctx
.
ImagePublicU
RL
=
"https://grafana.com/assets/img/blog/mixed_styles.png"
}
ctx
.
IsTestRun
=
true
ctx
.
Firing
=
true
...
...
pkg/services/alerting/test_rule.go
View file @
d8736a25
...
...
@@ -13,8 +13,8 @@ import (
// of an alert rule.
type
AlertTestCommand
struct
{
Dashboard
*
simplejson
.
Json
PanelI
d
int64
OrgI
d
int64
PanelI
D
int64
OrgI
D
int64
User
*
models
.
SignedInUser
Result
*
EvalContext
...
...
@@ -28,14 +28,14 @@ func handleAlertTestCommand(cmd *AlertTestCommand) error {
dash
:=
models
.
NewDashboardFromJson
(
cmd
.
Dashboard
)
extractor
:=
NewDashAlertExtractor
(
dash
,
cmd
.
OrgI
d
,
cmd
.
User
)
extractor
:=
NewDashAlertExtractor
(
dash
,
cmd
.
OrgI
D
,
cmd
.
User
)
alerts
,
err
:=
extractor
.
GetAlerts
()
if
err
!=
nil
{
return
err
}
for
_
,
alert
:=
range
alerts
{
if
alert
.
PanelId
==
cmd
.
PanelI
d
{
if
alert
.
PanelId
==
cmd
.
PanelI
D
{
rule
,
err
:=
NewRuleFromDBAlert
(
alert
)
if
err
!=
nil
{
return
err
...
...
@@ -46,7 +46,7 @@ func handleAlertTestCommand(cmd *AlertTestCommand) error {
}
}
return
fmt
.
Errorf
(
"Could not find alert with panel id %d"
,
cmd
.
PanelI
d
)
return
fmt
.
Errorf
(
"Could not find alert with panel id %d"
,
cmd
.
PanelI
D
)
}
func
testAlertRule
(
rule
*
Rule
)
*
EvalContext
{
...
...
scripts/backend-lint.sh
View file @
d8736a25
...
...
@@ -36,4 +36,5 @@ exit_if_fail golangci-lint run --deadline 10m --disable-all \
exit_if_fail go vet ./pkg/...
exit_if_fail make revive
exit_if_fail make revive-alerting
exit_if_fail make gosec
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