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
c46a3c86
Commit
c46a3c86
authored
May 07, 2018
by
Torkel Ödegaard
Browse files
Options
Browse Files
Download
Plain Diff
Merge branch 'jereksel-feature/discord'
parents
23c88a3b
e5e8b980
Hide whitespace changes
Inline
Side-by-side
Showing
6 changed files
with
259 additions
and
19 deletions
+259
-19
pkg/components/null/float.go
+9
-0
pkg/models/notifications.go
+7
-6
pkg/services/alerting/notifiers/discord.go
+171
-0
pkg/services/alerting/notifiers/discord_test.go
+52
-0
pkg/services/notifications/notifications.go
+7
-6
pkg/services/notifications/webhook.go
+13
-7
No files found.
pkg/components/null/float.go
View file @
c46a3c86
...
...
@@ -106,6 +106,15 @@ func (f Float) String() string {
return
fmt
.
Sprintf
(
"%1.3f"
,
f
.
Float64
)
}
// FullString returns float as string in full precision
func
(
f
Float
)
FullString
()
string
{
if
!
f
.
Valid
{
return
"null"
}
return
fmt
.
Sprintf
(
"%f"
,
f
.
Float64
)
}
// SetValid changes this Float's value and also sets it to be non-null.
func
(
f
*
Float
)
SetValid
(
n
float64
)
{
f
.
Float64
=
n
...
...
pkg/models/notifications.go
View file @
c46a3c86
...
...
@@ -19,12 +19,13 @@ type SendEmailCommandSync struct {
}
type
SendWebhookSync
struct
{
Url
string
User
string
Password
string
Body
string
HttpMethod
string
HttpHeader
map
[
string
]
string
Url
string
User
string
Password
string
Body
string
HttpMethod
string
HttpHeader
map
[
string
]
string
ContentType
string
}
type
SendResetPasswordEmailCommand
struct
{
...
...
pkg/services/alerting/notifiers/discord.go
0 → 100644
View file @
c46a3c86
package
notifiers
import
(
"bytes"
"io"
"mime/multipart"
"os"
"strconv"
"strings"
"github.com/grafana/grafana/pkg/bus"
"github.com/grafana/grafana/pkg/components/simplejson"
"github.com/grafana/grafana/pkg/log"
m
"github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/services/alerting"
"github.com/grafana/grafana/pkg/setting"
)
func
init
()
{
alerting
.
RegisterNotifier
(
&
alerting
.
NotifierPlugin
{
Type
:
"discord"
,
Name
:
"Discord"
,
Description
:
"Sends notifications to Discord"
,
Factory
:
NewDiscordNotifier
,
OptionsTemplate
:
`
<h3 class="page-heading">Discord settings</h3>
<div class="gf-form">
<span class="gf-form-label width-14">Webhook URL</span>
<input type="text" required class="gf-form-input max-width-22" ng-model="ctrl.model.settings.url" placeholder="Discord webhook URL"></input>
</div>
`
,
})
}
func
NewDiscordNotifier
(
model
*
m
.
AlertNotification
)
(
alerting
.
Notifier
,
error
)
{
url
:=
model
.
Settings
.
Get
(
"url"
)
.
MustString
()
if
url
==
""
{
return
nil
,
alerting
.
ValidationError
{
Reason
:
"Could not find webhook url property in settings"
}
}
return
&
DiscordNotifier
{
NotifierBase
:
NewNotifierBase
(
model
.
Id
,
model
.
IsDefault
,
model
.
Name
,
model
.
Type
,
model
.
Settings
),
WebhookURL
:
url
,
log
:
log
.
New
(
"alerting.notifier.discord"
),
},
nil
}
type
DiscordNotifier
struct
{
NotifierBase
WebhookURL
string
log
log
.
Logger
}
func
(
this
*
DiscordNotifier
)
Notify
(
evalContext
*
alerting
.
EvalContext
)
error
{
this
.
log
.
Info
(
"Sending alert notification to"
,
"webhook_url"
,
this
.
WebhookURL
)
ruleUrl
,
err
:=
evalContext
.
GetRuleUrl
()
if
err
!=
nil
{
this
.
log
.
Error
(
"Failed get rule link"
,
"error"
,
err
)
return
err
}
bodyJSON
:=
simplejson
.
New
()
bodyJSON
.
Set
(
"username"
,
"Grafana"
)
fields
:=
make
([]
map
[
string
]
interface
{},
0
)
for
_
,
evt
:=
range
evalContext
.
EvalMatches
{
fields
=
append
(
fields
,
map
[
string
]
interface
{}{
"name"
:
evt
.
Metric
,
"value"
:
evt
.
Value
.
FullString
(),
"inline"
:
true
,
})
}
footer
:=
map
[
string
]
interface
{}{
"text"
:
"Grafana v"
+
setting
.
BuildVersion
,
"icon_url"
:
"https://grafana.com/assets/img/fav32.png"
,
}
color
,
_
:=
strconv
.
ParseInt
(
strings
.
TrimLeft
(
evalContext
.
GetStateModel
()
.
Color
,
"#"
),
16
,
0
)
embed
:=
simplejson
.
New
()
embed
.
Set
(
"title"
,
evalContext
.
GetNotificationTitle
())
//Discord takes integer for color
embed
.
Set
(
"color"
,
color
)
embed
.
Set
(
"url"
,
ruleUrl
)
embed
.
Set
(
"description"
,
evalContext
.
Rule
.
Message
)
embed
.
Set
(
"type"
,
"rich"
)
embed
.
Set
(
"fields"
,
fields
)
embed
.
Set
(
"footer"
,
footer
)
var
image
=
make
(
map
[
string
]
interface
{})
var
embeddedImage
=
false
if
evalContext
.
ImagePublicUrl
!=
""
{
image
=
map
[
string
]
interface
{}{
"url"
:
evalContext
.
ImagePublicUrl
,
}
embed
.
Set
(
"image"
,
image
)
}
else
{
image
=
map
[
string
]
interface
{}{
"url"
:
"attachment://graph.png"
,
}
embed
.
Set
(
"image"
,
image
)
embeddedImage
=
true
}
bodyJSON
.
Set
(
"embeds"
,
[]
interface
{}{
embed
})
json
,
_
:=
bodyJSON
.
MarshalJSON
()
content_type
:=
"application/json"
var
body
[]
byte
if
embeddedImage
{
var
b
bytes
.
Buffer
w
:=
multipart
.
NewWriter
(
&
b
)
f
,
err
:=
os
.
Open
(
evalContext
.
ImageOnDiskPath
)
if
err
!=
nil
{
this
.
log
.
Error
(
"Can't open graph file"
,
err
)
return
err
}
defer
f
.
Close
()
fw
,
err
:=
w
.
CreateFormField
(
"payload_json"
)
if
err
!=
nil
{
return
err
}
if
_
,
err
=
fw
.
Write
([]
byte
(
string
(
json
)));
err
!=
nil
{
return
err
}
fw
,
err
=
w
.
CreateFormFile
(
"file"
,
"graph.png"
)
if
_
,
err
=
io
.
Copy
(
fw
,
f
);
err
!=
nil
{
return
err
}
w
.
Close
()
body
=
b
.
Bytes
()
content_type
=
w
.
FormDataContentType
()
}
else
{
body
=
json
}
cmd
:=
&
m
.
SendWebhookSync
{
Url
:
this
.
WebhookURL
,
Body
:
string
(
body
),
HttpMethod
:
"POST"
,
ContentType
:
content_type
,
}
if
err
:=
bus
.
DispatchCtx
(
evalContext
.
Ctx
,
cmd
);
err
!=
nil
{
this
.
log
.
Error
(
"Failed to send notification to Discord"
,
"error"
,
err
)
return
err
}
return
nil
}
pkg/services/alerting/notifiers/discord_test.go
0 → 100644
View file @
c46a3c86
package
notifiers
import
(
"testing"
"github.com/grafana/grafana/pkg/components/simplejson"
m
"github.com/grafana/grafana/pkg/models"
.
"github.com/smartystreets/goconvey/convey"
)
func
TestDiscordNotifier
(
t
*
testing
.
T
)
{
Convey
(
"Telegram notifier tests"
,
t
,
func
()
{
Convey
(
"Parsing alert notification from settings"
,
func
()
{
Convey
(
"empty settings should return error"
,
func
()
{
json
:=
`{ }`
settingsJSON
,
_
:=
simplejson
.
NewJson
([]
byte
(
json
))
model
:=
&
m
.
AlertNotification
{
Name
:
"discord_testing"
,
Type
:
"discord"
,
Settings
:
settingsJSON
,
}
_
,
err
:=
NewDiscordNotifier
(
model
)
So
(
err
,
ShouldNotBeNil
)
})
Convey
(
"settings should trigger incident"
,
func
()
{
json
:=
`
{
"url": "https://web.hook/"
}`
settingsJSON
,
_
:=
simplejson
.
NewJson
([]
byte
(
json
))
model
:=
&
m
.
AlertNotification
{
Name
:
"discord_testing"
,
Type
:
"discord"
,
Settings
:
settingsJSON
,
}
not
,
err
:=
NewDiscordNotifier
(
model
)
discordNotifier
:=
not
.
(
*
DiscordNotifier
)
So
(
err
,
ShouldBeNil
)
So
(
discordNotifier
.
Name
,
ShouldEqual
,
"discord_testing"
)
So
(
discordNotifier
.
Type
,
ShouldEqual
,
"discord"
)
So
(
discordNotifier
.
WebhookURL
,
ShouldEqual
,
"https://web.hook/"
)
})
})
})
}
pkg/services/notifications/notifications.go
View file @
c46a3c86
...
...
@@ -104,12 +104,13 @@ func (ns *NotificationService) Run(ctx context.Context) error {
func
(
ns
*
NotificationService
)
SendWebhookSync
(
ctx
context
.
Context
,
cmd
*
m
.
SendWebhookSync
)
error
{
return
ns
.
sendWebRequestSync
(
ctx
,
&
Webhook
{
Url
:
cmd
.
Url
,
User
:
cmd
.
User
,
Password
:
cmd
.
Password
,
Body
:
cmd
.
Body
,
HttpMethod
:
cmd
.
HttpMethod
,
HttpHeader
:
cmd
.
HttpHeader
,
Url
:
cmd
.
Url
,
User
:
cmd
.
User
,
Password
:
cmd
.
Password
,
Body
:
cmd
.
Body
,
HttpMethod
:
cmd
.
HttpMethod
,
HttpHeader
:
cmd
.
HttpHeader
,
ContentType
:
cmd
.
ContentType
,
})
}
...
...
pkg/services/notifications/webhook.go
View file @
c46a3c86
...
...
@@ -15,12 +15,13 @@ import (
)
type
Webhook
struct
{
Url
string
User
string
Password
string
Body
string
HttpMethod
string
HttpHeader
map
[
string
]
string
Url
string
User
string
Password
string
Body
string
HttpMethod
string
HttpHeader
map
[
string
]
string
ContentType
string
}
var
netTransport
=
&
http
.
Transport
{
...
...
@@ -48,8 +49,13 @@ func (ns *NotificationService) sendWebRequestSync(ctx context.Context, webhook *
return
err
}
request
.
Header
.
Add
(
"Content-Type"
,
"application/json"
)
if
webhook
.
ContentType
==
""
{
webhook
.
ContentType
=
"application/json"
}
request
.
Header
.
Add
(
"Content-Type"
,
webhook
.
ContentType
)
request
.
Header
.
Add
(
"User-Agent"
,
"Grafana"
)
if
webhook
.
User
!=
""
&&
webhook
.
Password
!=
""
{
request
.
Header
.
Add
(
"Authorization"
,
util
.
GetBasicAuthHeader
(
webhook
.
User
,
webhook
.
Password
))
}
...
...
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