Selaa lähdekoodia

Sending image

Andrzej Ressel 8 vuotta sitten
vanhempi
commit
1bf982439b

+ 9 - 0
pkg/components/null/float.go

@@ -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

+ 7 - 6
pkg/models/notifications.go

@@ -18,12 +18,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 {

+ 71 - 12
pkg/services/alerting/notifiers/discord.go

@@ -1,6 +1,10 @@
 package notifiers
 
 import (
+	"bytes"
+	"io"
+	"mime/multipart"
+	"os"
 	"strconv"
 	"strings"
 
@@ -64,9 +68,10 @@ func (this *DiscordNotifier) Notify(evalContext *alerting.EvalContext) error {
 	fields := make([]map[string]interface{}, 0)
 
 	for _, evt := range evalContext.EvalMatches {
+
 		fields = append(fields, map[string]interface{}{
 			"name":   evt.Metric,
-			"value":  evt.Value,
+			"value":  evt.Value.FullString(),
 			"inline": true,
 		})
 	}
@@ -78,10 +83,6 @@ func (this *DiscordNotifier) Notify(evalContext *alerting.EvalContext) error {
 
 	color, _ := strconv.ParseInt(strings.TrimLeft(evalContext.GetStateModel().Color, "#"), 16, 0)
 
-	image := map[string]interface{}{
-		"url": evalContext.ImagePublicUrl,
-	}
-
 	embed := simplejson.New()
 	embed.Set("title", evalContext.GetNotificationTitle())
 	//Discord takes integer for color
@@ -91,22 +92,80 @@ func (this *DiscordNotifier) Notify(evalContext *alerting.EvalContext) error {
 	embed.Set("type", "rich")
 	embed.Set("fields", fields)
 	embed.Set("footer", footer)
-	embed.Set("image", image)
+
+	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})
 
-	body, _ := bodyJSON.MarshalJSON()
+	json, _ := bodyJSON.MarshalJSON()
+
+	content_type := "application/json"
+
+	var body []byte
+
+	if embeddedImage {
+
+		var b bytes.Buffer
+
+		w := multipart.NewWriter(&b)
 
-	this.log.Info("Message", string(body))
+		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",
+		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, "body", string(body))
+		this.log.Error("Failed to send notification to Discord", "error", err)
 		return err
 	}
 

+ 7 - 6
pkg/services/notifications/notifications.go

@@ -60,12 +60,13 @@ func Init() error {
 
 func SendWebhookSync(ctx context.Context, cmd *m.SendWebhookSync) error {
 	return 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,
 	})
 }
 

+ 13 - 8
pkg/services/notifications/webhook.go

@@ -16,12 +16,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{
@@ -61,7 +62,7 @@ func processWebhookQueue() {
 }
 
 func sendWebRequestSync(ctx context.Context, webhook *Webhook) error {
-	webhookLog.Debug("Sending webhook", "url", webhook.Url, "http method", webhook.HttpMethod)
+	webhookLog.Debug("Sending webhook", "url", webhook.Url, "http method", webhook.HttpMethod, "content type", webhook.ContentType)
 
 	if webhook.HttpMethod == "" {
 		webhook.HttpMethod = http.MethodPost
@@ -72,7 +73,11 @@ func sendWebRequestSync(ctx context.Context, webhook *Webhook) error {
 		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))