From 35e88fda15c58cfffbb06d0e2caaefbe432bfe17 Mon Sep 17 00:00:00 2001 From: arshia Date: Sun, 27 Apr 2025 17:25:01 +0330 Subject: [PATCH 1/3] added http notify --- notify/http/header.go | 6 +++++ notify/http/http.go | 61 +++++++++++++++++++++++++++++++++++++++++++ notify/notify.go | 2 ++ 3 files changed, 69 insertions(+) create mode 100644 notify/http/header.go create mode 100644 notify/http/http.go diff --git a/notify/http/header.go b/notify/http/header.go new file mode 100644 index 00000000..6b256f26 --- /dev/null +++ b/notify/http/header.go @@ -0,0 +1,6 @@ +package http + +type Header struct { + Name string `yaml:"name" json:"name,omitempty" jsonschema:"title=Header Name,description=The name of the header to send"` + Value string `yaml:"value" json:"value,omitempty" jsonschema:"title=Header Value,description=The value of the header to send"` +} diff --git a/notify/http/http.go b/notify/http/http.go new file mode 100644 index 00000000..e251d559 --- /dev/null +++ b/notify/http/http.go @@ -0,0 +1,61 @@ +package http + +import ( + "bytes" + "fmt" + "io" + "net/http" + + "github.com/megaease/easeprobe/global" + "github.com/megaease/easeprobe/notify/base" + "github.com/megaease/easeprobe/report" + log "github.com/sirupsen/logrus" +) + +// NotifyConfig is the HTTP notification configuration +type NotifyConfig struct { + base.DefaultNotify `yaml:",inline"` + + URL string `yaml:"url" json:"url,omitempty" jsonschema:"title=HTTP URL,description=The HTTP endpoint to send notifications"` + SuccessStatus int `yaml:"success_status" json:"success_status,omitempty" jsonschema:"title=Success Status,description=The success status code of the HTTP request"` + Headers []Header `yaml:"headers" json:"headers,omitempty" jsonschema:"title=HTTP Headers,description=Custom headers for the HTTP request"` +} + +func (c *NotifyConfig) Config(gConf global.NotifySettings) error { + c.NotifyKind = "http" + c.NotifyFormat = report.Markdown + c.NotifySendFunc = c.SendHTTP + c.DefaultNotify.Config(gConf) + log.Debugf("Notification [%s] - [%s] configuration: %+v", c.NotifyKind, c.NotifyName, c) + return nil +} + +func (c *NotifyConfig) SendHTTP(title, text string) error { + req, err := http.NewRequest(http.MethodPost, c.URL, bytes.NewBuffer([]byte(text))) + if err != nil { + return err + } + req.Close = true + for _, h := range c.Headers { + req.Header.Set(h.Name, h.Value) + } + req.Header.Set("User-Agent", "EaseProbe") + + client := &http.Client{Timeout: c.Timeout} + resp, err := client.Do(req) + if err != nil { + return err + } + defer resp.Body.Close() + + log.Debugf("[%s] - [%s] sending notification to %s", c.Kind(), c.Name(), c.URL) + + buf, err := io.ReadAll(resp.Body) + if err != nil { + return err + } + if resp.StatusCode != c.SuccessStatus { + return fmt.Errorf("Error response from HTTP - code [%d] - msg [%s]", resp.StatusCode, string(buf)) + } + return nil +} diff --git a/notify/notify.go b/notify/notify.go index 9b0fabc5..7073d73a 100644 --- a/notify/notify.go +++ b/notify/notify.go @@ -24,6 +24,7 @@ import ( "github.com/megaease/easeprobe/notify/dingtalk" "github.com/megaease/easeprobe/notify/discord" "github.com/megaease/easeprobe/notify/email" + "github.com/megaease/easeprobe/notify/http" "github.com/megaease/easeprobe/notify/lark" "github.com/megaease/easeprobe/notify/log" "github.com/megaease/easeprobe/notify/ringcentral" @@ -51,6 +52,7 @@ type Config struct { Teams []teams.NotifyConfig `yaml:"teams,omitempty" json:"teams,omitempty" jsonschema:"title=Teams Notification,description=Teams Notification Configuration"` Shell []shell.NotifyConfig `yaml:"shell,omitempty" json:"shell,omitempty" jsonschema:"title=Shell Notification,description=Shell Notification Configuration"` RingCentral []ringcentral.NotifyConfig `yaml:"ringcentral,omitempty" json:"ringcentral,omitempty" jsonschema:"title=RingCentral Notification,description=RingCentral Notification Configuration"` + HTTP []http.NotifyConfig `yaml:"http,omitempty" json:"http,omitempty" jsonschema:"title=HTTP Notification,description=HTTP Notification Configuration"` } // Notify is the configuration of the Notify From 4b50fa4677295c47823d5751d6b67f333b1fa04c Mon Sep 17 00:00:00 2001 From: arshia Date: Mon, 28 Apr 2025 10:53:12 +0330 Subject: [PATCH 2/3] added http notify test --- notify/http/header.go | 18 ++++++++ notify/http/http.go | 20 +++++++++ notify/http/http_test.go | 93 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 131 insertions(+) create mode 100644 notify/http/http_test.go diff --git a/notify/http/header.go b/notify/http/header.go index 6b256f26..111f414a 100644 --- a/notify/http/header.go +++ b/notify/http/header.go @@ -1,5 +1,23 @@ +/* + * Copyright (c) 2022, MegaEase + * All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package http +// Header represents HTTP header for HTTP notification type Header struct { Name string `yaml:"name" json:"name,omitempty" jsonschema:"title=Header Name,description=The name of the header to send"` Value string `yaml:"value" json:"value,omitempty" jsonschema:"title=Header Value,description=The value of the header to send"` diff --git a/notify/http/http.go b/notify/http/http.go index e251d559..52988a75 100644 --- a/notify/http/http.go +++ b/notify/http/http.go @@ -1,3 +1,21 @@ +/* + * Copyright (c) 2022, MegaEase + * All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +// Package http is the HTTP notification package http import ( @@ -21,6 +39,7 @@ type NotifyConfig struct { Headers []Header `yaml:"headers" json:"headers,omitempty" jsonschema:"title=HTTP Headers,description=Custom headers for the HTTP request"` } +// Config configures the HTTP notification func (c *NotifyConfig) Config(gConf global.NotifySettings) error { c.NotifyKind = "http" c.NotifyFormat = report.Markdown @@ -30,6 +49,7 @@ func (c *NotifyConfig) Config(gConf global.NotifySettings) error { return nil } +// SendHTTP sends the HTTP notification func (c *NotifyConfig) SendHTTP(title, text string) error { req, err := http.NewRequest(http.MethodPost, c.URL, bytes.NewBuffer([]byte(text))) if err != nil { diff --git a/notify/http/http_test.go b/notify/http/http_test.go new file mode 100644 index 00000000..01f19313 --- /dev/null +++ b/notify/http/http_test.go @@ -0,0 +1,93 @@ +/* + * Copyright (c) 2022, MegaEase + * All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package http + +import ( + "errors" + "io" + "net/http" + "reflect" + "strings" + "testing" + + "github.com/megaease/easeprobe/global" + "github.com/megaease/easeprobe/monkey" + "github.com/stretchr/testify/assert" +) + +func assertError(t *testing.T, err error, msg string) { + t.Helper() + assert.Error(t, err) + assert.Equal(t, msg, err.Error()) +} + +func TestHTTPNotify(t *testing.T) { + conf := &NotifyConfig{ + URL: "http://example.com/notify", + SuccessStatus: 200, + Headers: []Header{ + {Name: "Content-Type", Value: "application/json"}, + }, + } + conf.NotifyName = "dummy" + err := conf.Config(global.NotifySettings{}) + assert.NoError(t, err) + assert.Equal(t, "http", conf.Kind()) + assert.Equal(t, "application/json", conf.Headers[0].Value) + + var client http.Client + monkey.PatchInstanceMethod(reflect.TypeOf(&client), "Do", func(_ *http.Client, req *http.Request) (*http.Response, error) { + r := io.NopCloser(strings.NewReader(`ok`)) + return &http.Response{ + StatusCode: 200, + Body: r, + }, nil + }) + err = conf.SendHTTP("title", "message") + assert.NoError(t, err) + + monkey.PatchInstanceMethod(reflect.TypeOf(&client), "Do", func(_ *http.Client, req *http.Request) (*http.Response, error) { + r := io.NopCloser(strings.NewReader(`error`)) + return &http.Response{ + StatusCode: 500, + Body: r, + }, nil + }) + err = conf.SendHTTP("title", "message") + assertError(t, err, "Error response from HTTP - code [500] - msg [error]") + + monkey.Patch(io.ReadAll, func(_ io.Reader) ([]byte, error) { + return nil, errors.New("read error") + }) + err = conf.SendHTTP("title", "message") + assertError(t, err, "read error") + + monkey.PatchInstanceMethod(reflect.TypeOf(&client), "Do", func(_ *http.Client, req *http.Request) (*http.Response, error) { + return nil, errors.New("http do error") + }) + err = conf.SendHTTP("title", "message") + assertError(t, err, "http do error") + + monkey.Patch(http.NewRequest, func(method string, url string, body io.Reader) (*http.Request, error) { + return nil, errors.New("new request error") + }) + err = conf.SendHTTP("title", "message") + assertError(t, err, "new request error") + + monkey.UnpatchAll() +} From d788bdc8574ca004d12017c6b4a58fc90d12778a Mon Sep 17 00:00:00 2001 From: arshia Date: Sun, 11 May 2025 13:28:23 +0330 Subject: [PATCH 3/3] add http notify docs to the user manual file --- docs/Manual.md | 27 +++++++++++++++++++++++++++ notify/http/header.go | 24 ------------------------ notify/http/http.go | 6 ++++++ 3 files changed, 33 insertions(+), 24 deletions(-) delete mode 100644 notify/http/header.go diff --git a/docs/Manual.md b/docs/Manual.md index f25d3fa4..96b600e3 100644 --- a/docs/Manual.md +++ b/docs/Manual.md @@ -56,6 +56,7 @@ EaseProbe has the following major modules: - [2.11 Log](#211-log) - [2.12 Shell](#212-shell) - [2.13 RingCentral](#213-ringcentral) + - [2.14 HTTP](#214-http) - [3. Report](#3-report) - [3.1 SLA Report Notification](#31-sla-report-notification) - [3.2 SLA Live Report](#32-sla-live-report) @@ -1194,6 +1195,32 @@ notify: webhook: "https://hooks.ringcentral.com/webhook/v2/.........." ``` +## 2.14 HTTP +This notification method sends notifications as HTTP POST requests to a specified endpoint. + +The plugin supports the following parameters: +- `name`: A unique name for this notification endpoint +- `url`: The HTTP endpoint URL to send notifications to +- `success_status`: The expected HTTP status code for successful delivery +- `headers`: Optional headers to include in the request (see example below) + +`Note`: The http method is always `POST`, and the body of the request will contain the notification data + +Example: +```YAML +# Notification Configuration +notify: + http: + - name: "Custom HTTP Notify" + url: "https://api.example.com/notify" + success_status: 201 + headers: + - name: "Content-Type" + value: "application/json" + - name: "Authorization" + value: "Bearer token123" +``` + # 3. Report ## 3.1 SLA Report Notification diff --git a/notify/http/header.go b/notify/http/header.go deleted file mode 100644 index 111f414a..00000000 --- a/notify/http/header.go +++ /dev/null @@ -1,24 +0,0 @@ -/* - * Copyright (c) 2022, MegaEase - * All rights reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package http - -// Header represents HTTP header for HTTP notification -type Header struct { - Name string `yaml:"name" json:"name,omitempty" jsonschema:"title=Header Name,description=The name of the header to send"` - Value string `yaml:"value" json:"value,omitempty" jsonschema:"title=Header Value,description=The value of the header to send"` -} diff --git a/notify/http/http.go b/notify/http/http.go index 52988a75..4a29d9ed 100644 --- a/notify/http/http.go +++ b/notify/http/http.go @@ -39,6 +39,12 @@ type NotifyConfig struct { Headers []Header `yaml:"headers" json:"headers,omitempty" jsonschema:"title=HTTP Headers,description=Custom headers for the HTTP request"` } +// Header represents HTTP header for HTTP notification +type Header struct { + Name string `yaml:"name" json:"name,omitempty" jsonschema:"title=Header Name,description=The name of the header to send"` + Value string `yaml:"value" json:"value,omitempty" jsonschema:"title=Header Value,description=The value of the header to send"` +} + // Config configures the HTTP notification func (c *NotifyConfig) Config(gConf global.NotifySettings) error { c.NotifyKind = "http"