feat(alerting): support for attached graphs in alert notifications

closes #6183
This commit is contained in:
bergquist
2016-10-20 15:06:59 +02:00
parent ded5a0a9d5
commit f77799837e
33 changed files with 2358 additions and 418 deletions

View File

@@ -1,8 +1,7 @@
package notifiers
import (
"encoding/base64"
"io/ioutil"
"os"
"strings"
"github.com/grafana/grafana/pkg/bus"
@@ -47,14 +46,6 @@ func (this *EmailNotifier) Notify(evalContext *alerting.EvalContext) error {
return err
}
imageLink := evalContext.ImagePublicUrl
if imageLink == "" {
imageBytes, err := ioutil.ReadFile(evalContext.ImageOnDiskPath)
if err == nil {
imageLink = "data:image/jpg;base64," + base64.StdEncoding.EncodeToString(imageBytes)
}
}
cmd := &m.SendEmailCommandSync{
SendEmailCommand: m.SendEmailCommand{
Data: map[string]interface{}{
@@ -64,15 +55,27 @@ func (this *EmailNotifier) Notify(evalContext *alerting.EvalContext) error {
"StateModel": evalContext.GetStateModel(),
"Message": evalContext.Rule.Message,
"RuleUrl": ruleUrl,
"ImageLink": evalContext.ImagePublicUrl,
"ImageLink": "",
"EmbededImage": "",
"AlertPageUrl": setting.AppUrl + "alerting",
"EvalMatches": evalContext.EvalMatches,
},
To: this.Addresses,
Template: "alert_notification.html",
To: this.Addresses,
Template: "alert_notification.html",
EmbededFiles: []string{},
},
}
if evalContext.ImagePublicUrl != "" {
cmd.Data["ImageLink"] = evalContext.ImagePublicUrl
} else {
file, err := os.Stat(evalContext.ImageOnDiskPath)
if err == nil {
cmd.EmbededFiles = []string{evalContext.ImageOnDiskPath}
cmd.Data["EmbededImage"] = file.Name()
}
}
err = bus.DispatchCtx(evalContext.Ctx, cmd)
if err != nil {

View File

@@ -37,9 +37,7 @@ func handleNotificationTestCommand(cmd *NotificationTestCommand) error {
return err
}
notifier.sendNotifications(createTestEvalContext(), []Notifier{notifiers})
return nil
return notifier.sendNotifications(createTestEvalContext(), []Notifier{notifiers})
}
func createTestEvalContext() *EvalContext {
@@ -53,7 +51,6 @@ func createTestEvalContext() *EvalContext {
ctx := NewEvalContext(context.TODO(), testRule)
ctx.ImagePublicUrl = "http://grafana.org/assets/img/blog/mixed_styles.png"
ctx.IsTestRun = true
ctx.Firing = true
ctx.Error = nil

View File

@@ -6,12 +6,13 @@ import (
)
type Message struct {
To []string
From string
Subject string
Body string
Massive bool
Info string
To []string
From string
Subject string
Body string
Massive bool
Info string
EmbededFiles []string
}
// create mail content

View File

@@ -14,12 +14,14 @@ import (
"net/mail"
"net/smtp"
"os"
"strconv"
"strings"
"time"
"github.com/grafana/grafana/pkg/log"
m "github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/setting"
"gopkg.in/gomail.v2"
)
var mailQueue chan *Message
@@ -154,40 +156,102 @@ func sendToSmtpServer(recipients []string, msgContent []byte) error {
}
func buildAndSend(msg *Message) (int, error) {
log.Trace("Sending mails to: %s", strings.Join(msg.To, "; "))
// get message body
content := msg.Content()
if len(msg.To) == 0 {
return 0, fmt.Errorf("empty receive emails")
} else if len(msg.Body) == 0 {
return 0, fmt.Errorf("empty email body")
m := gomail.NewMessage()
m.SetHeader("From", msg.From)
m.SetHeader("To", msg.To[0])
m.SetHeader("Subject", msg.Subject)
for _, file := range msg.EmbededFiles {
m.Embed(file)
}
if msg.Massive {
// send mail to multiple emails one by one
num := 0
for _, to := range msg.To {
body := []byte("To: " + to + "\r\n" + content)
err := sendToSmtpServer([]string{to}, body)
if err != nil {
return num, err
}
num++
}
return num, nil
} else {
body := []byte("To: " + strings.Join(msg.To, ";") + "\r\n" + content)
m.SetBody("text/html", msg.Body)
// send to multiple emails in one message
err := sendToSmtpServer(msg.To, body)
host, port, err := net.SplitHostPort(setting.Smtp.Host)
if err != nil {
return 0, err
}
iPort, err := strconv.Atoi(port)
if err != nil {
return 0, err
}
d := gomail.NewPlainDialer(host, iPort, setting.Smtp.User, setting.Smtp.Password)
tlsconfig := &tls.Config{
InsecureSkipVerify: setting.Smtp.SkipVerify,
ServerName: host,
}
if setting.Smtp.CertFile != "" {
cert, err := tls.LoadX509KeyPair(setting.Smtp.CertFile, setting.Smtp.KeyFile)
if err != nil {
return 0, err
} else {
return 1, nil
}
tlsconfig.Certificates = []tls.Certificate{cert}
}
d.TLSConfig = tlsconfig
if err := d.DialAndSend(m); err != nil {
return 0, err
}
return 0, nil
/*
m := email.NewHTMLMessage(msg.Subject, msg.Body)
m.From = mail.Address{Name: "From", Address: "alerting@grafana.org"}
m.To = msg.To
log.Info2("Attaching file", "file", msg.Attachment)
if err := m.Attach(msg.Attachment); err != nil {
return 0, err
}
// send it
host, _, _ := net.SplitHostPort(setting.Smtp.Host)
auth := smtp.PlainAuth("", setting.Smtp.User, setting.Smtp.Password, host)
if err := email.Send(setting.Smtp.Host, auth, m); err != nil {
return 0, err
}
return 0, nil
log.Trace("Sending mails to: %s", strings.Join(msg.To, "; "))
// get message body
content := msg.Content()
if len(msg.To) == 0 {
return 0, fmt.Errorf("empty receive emails")
} else if len(msg.Body) == 0 {
return 0, fmt.Errorf("empty email body")
}
if msg.Massive {
// send mail to multiple emails one by one
num := 0
for _, to := range msg.To {
body := []byte("To: " + to + "\r\n" + content)
err := sendToSmtpServer([]string{to}, body)
if err != nil {
return num, err
}
num++
}
return num, nil
} else {
body := []byte("To: " + strings.Join(msg.To, ";") + "\r\n" + content)
// send to multiple emails in one message
err := sendToSmtpServer(msg.To, body)
if err != nil {
return 0, err
} else {
return 1, nil
}
}
*/
}
func buildEmailMessage(cmd *m.SendEmailCommand) (*Message, error) {
@@ -229,9 +293,10 @@ func buildEmailMessage(cmd *m.SendEmailCommand) (*Message, error) {
}
return &Message{
To: cmd.To,
From: setting.Smtp.FromAddress,
Subject: subjectBuffer.String(),
Body: buffer.String(),
To: cmd.To,
From: setting.Smtp.FromAddress,
Subject: subjectBuffer.String(),
Body: buffer.String(),
EmbededFiles: cmd.EmbededFiles,
}, nil
}

View File

@@ -88,11 +88,12 @@ func subjectTemplateFunc(obj map[string]interface{}, value string) string {
func sendEmailCommandHandlerSync(ctx context.Context, cmd *m.SendEmailCommandSync) error {
message, err := buildEmailMessage(&m.SendEmailCommand{
Data: cmd.Data,
Info: cmd.Info,
Massive: cmd.Massive,
Template: cmd.Template,
To: cmd.To,
Data: cmd.Data,
Info: cmd.Info,
Massive: cmd.Massive,
Template: cmd.Template,
To: cmd.To,
EmbededFiles: cmd.EmbededFiles,
})
if err != nil {