Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
339 changes: 66 additions & 273 deletions client_alert.go

Large diffs are not rendered by default.

191 changes: 191 additions & 0 deletions client_alert_func_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,191 @@
package sls

import (
"testing"

"github.com/stretchr/testify/suite"
)

type SavedSerarchTestSuite struct {
functionTestSuiteBase
projectName string
logstoreName string
}

func TestSavedSearchFunctionTest(t *testing.T) {
suite.Run(t, new(SavedSerarchTestSuite))
}

func (s *SavedSerarchTestSuite) SetupSuite() {
s.functionTestSuiteBase.init()
s.projectName, s.logstoreName = s.createProjectAndLogStore()
}

func (s *SavedSerarchTestSuite) TearDownSuite() {
s.cleanUpProject(s.projectName)
}

func (s *SavedSerarchTestSuite) TestSavedSearch() {
c := s.getClient().(*Client)
name := "test-savedsearch"
err := c.CreateSavedSearch(s.projectName, &SavedSearch{
SavedSearchName: name,
SearchQuery: "*",
DisplayName: "test-savedsearch-display",
Logstore: s.logstoreName,
})
s.Require().NoError(err)

savedSearch, err := c.GetSavedSearch(s.projectName, name)
s.Require().NoError(err)
s.Equal(name, savedSearch.SavedSearchName)
s.Equal("test-savedsearch-display", savedSearch.DisplayName)
s.Equal(s.logstoreName, savedSearch.Logstore)
s.Equal("*", savedSearch.SearchQuery)

{
searches, total, line, err := c.ListSavedSearch(s.projectName, "", 0, 10)
s.Require().NoError(err)
s.Equal(1, line)
s.Equal(1, total)
s.Equal(1, len(searches))
s.Equal(name, searches[0])
}
{
searches, total, line, err := c.ListSavedSearch(s.projectName, name, 0, 10)
s.Require().NoError(err)
s.Equal(1, line)
s.Equal(1, total)
s.Equal(1, len(searches))
s.Equal(name, searches[0])
}
{
searches, total, line, err := c.ListSavedSearch(s.projectName, name+"something", 0, 10)
s.Require().NoError(err)
s.Equal(0, line)
s.Equal(0, total)
s.Equal(0, len(searches))
}
{
searches, items, total, line, err := c.ListSavedSearchV2(s.projectName, name, 0, 10)
s.Require().NoError(err)
s.Equal(1, line)
s.Equal(1, total)
s.Equal(1, len(searches))
s.Equal(1, len(items))
s.Equal(name, searches[0])
}
err = c.UpdateSavedSearch(s.projectName, &SavedSearch{
SavedSearchName: name,
SearchQuery: "* | select count(*) as cnt",
DisplayName: "test-savedsearch-display",
Logstore: s.logstoreName,
})
s.Require().NoError(err)
savedSearch, err = c.GetSavedSearch(s.projectName, name)
s.Require().NoError(err)
s.Equal("* | select count(*) as cnt", savedSearch.SearchQuery)

err = c.DeleteSavedSearch(s.projectName, name)
s.Require().NoError(err)

_, err = c.GetSavedSearch(s.projectName, name)
s.Require().Error(err)
}

type AlertFuncTestSuite struct {
functionTestSuiteBase
projectName string
logstoreName string
}

func TestAlertFunctionTest(t *testing.T) {
suite.Run(t, new(AlertFuncTestSuite))
}

func (s *AlertFuncTestSuite) SetupSuite() {
s.functionTestSuiteBase.init()
s.projectName, s.logstoreName = s.createProjectAndLogStore()
}

func (s *AlertFuncTestSuite) TearDownSuite() {
s.cleanUpProject(s.projectName)
}

func (s *AlertFuncTestSuite) TestAlertFunc() {
c := s.getClient().(*Client)
name := "test-alert"
alert := &Alert{
Name: name,
DisplayName: name,
Description: "test",
Schedule: &Schedule{
Type: ScheduleTypeHourly,
RunImmediately: false,
},
Configuration: &AlertConfiguration{
QueryList: []*AlertQuery{
{
ChartTitle: "chart-abc",
Query: "* | select count(1) as count",
Start: "-120s",
End: "now",
TimeSpanType: "Custom",
LogStore: "test-logstore",
},
},
Condition: "count > 0",
Dashboard: "test-dashboard",
NotificationList: []*Notification{
{
Type: NotificationTypeEmail,
Content: "${alertName} triggered at ${firetime}",
EmailList: []string{"test@abc.com"},
},
},
},
}
err := c.CreateAlert(s.projectName, alert)
s.Require().NoError(err)

alertResp, err := c.GetAlert(s.projectName, name)
s.Require().NoError(err)
s.Equal(alert.Description, alertResp.Description)
s.Equal(alert.Schedule.Type, alertResp.Schedule.Type)

s.True(alertResp.IsEnabled())

alertString, err := c.GetAlertString(s.projectName, name)
s.Require().NoError(err)
s.Greater(len(alertString), 0)

err = c.UpdateAlertString(s.projectName, name, alertString)
s.Require().NoError(err)

listResp, total, count, err := c.ListAlert(s.projectName, name, "", 0, 10)
s.Require().NoError(err)
s.Equal(1, total)
s.Equal(1, count)
s.Equal(1, len(listResp))
s.Equal(name, listResp[0].Name)

err = c.DisableAlert(s.projectName, name)
s.Require().NoError(err)

{
getResp, err := c.GetAlert(s.projectName, name)
s.Require().NoError(err)
s.False(getResp.IsEnabled())
}

err = c.EnableAlert(s.projectName, name)
s.Require().NoError(err)
{
getResp, err := c.GetAlert(s.projectName, name)
s.Require().NoError(err)
s.True(getResp.IsEnabled())
}

err = c.DeleteAlert(s.projectName, name)
s.Require().NoError(err)
}
91 changes: 86 additions & 5 deletions client_request.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,24 +3,83 @@ package sls
// request sends a request to SLS.
import (
"bytes"
"encoding/json"
"fmt"
"strconv"

"io/ioutil"
"net/http"
"net/http/httputil"
"net/url"
"strings"

"github.com/go-kit/kit/log/level"
)

// request sends a request to alibaba cloud Log Service.
// @note if error is nil, you must call http.Response.Body.Close() to finalize reader
func (c *Client) request(project, method, uri string, headers map[string]string, body []byte) (*http.Response, error) {
// The caller should provide 'x-log-bodyrawsize' header
// response must be nil or a pointer to a struct which is json unmarshalable
// @param reqBody if nil, it will be ignored, if is a []byte, use it, otherwise, it will be json marshaled
func (c *Client) doRequest(project, method, path string, queryParams, headers map[string]string, reqBody any, response any) error {
buf, respHeader, statusCode, err := c.doRequestInner(project, method, path, queryParams, headers, reqBody)
if err != nil {
return err
}
if response == nil {
return nil
}
if err := json.Unmarshal(buf, response); err != nil {
return invalidJsonRespError(string(buf), respHeader, statusCode)
}
return nil
}

// get raw bytes of http response body
func (c *Client) doRequestRaw(project, method, path string, queryParams, headers map[string]string, reqBody any) (respBody []byte, err error) {
buf, _, _, err := c.doRequestInner(project, method, path, queryParams, headers, reqBody)
if err != nil {
return nil, err
}
return buf, nil
}

// do not use this directly outside this file
func (c *Client) doRequestInner(project, method, path string, queryParams, headers map[string]string, reqBody any) (respBody []byte, respHeader http.Header, statusCode int, err error) {
// body
body, isJson, err := getRequestBody(reqBody)
if err != nil {
return nil, nil, 0, err
}
// headers
if headers == nil {
headers = make(map[string]string)
}
if isJson {
headers[HTTPHeaderContentType] = "application/json"
}
if _, ok := headers[HTTPHeaderBodyRawSize]; !ok {
return nil, fmt.Errorf("Can't find 'x-log-bodyrawsize' header")
headers[HTTPHeaderBodyRawSize] = strconv.Itoa(len(body))
}

r, err := c.request(project, method, getRequestUrl(path, queryParams), headers, body)
if err != nil {
return nil, nil, 0, err
}

// response
defer r.Body.Close()
buf, err := ioutil.ReadAll(r.Body)
if err != nil {
return nil, nil, 0, readResponseError(err)
}
if r.StatusCode != http.StatusOK {
// should not reach here, but we keep checking it
return nil, nil, 0, httpStatusNotOkError(buf, r.Header, r.StatusCode)
}
return buf, r.Header, r.StatusCode, nil
}

// request sends a request to alibaba cloud Log Service.
// @note if error is nil, you must call http.Response.Body.Close() to finalize reader
func (c *Client) request(project, method, uri string, headers map[string]string, body []byte) (*http.Response, error) {
var endpoint string
var usingHTTPS bool
if strings.HasPrefix(c.Endpoint, "https://") {
Expand Down Expand Up @@ -148,3 +207,25 @@ func (c *Client) request(project, method, uri string, headers map[string]string,

return resp, nil
}

func getRequestBody(reqBody any) (body []byte, isJson bool, err error) {
if reqBody == nil {
return nil, false, nil
}
if b, ok := reqBody.([]byte); ok {
return b, false, nil
}
body, err = json.Marshal(reqBody)
return body, true, err
}

func getRequestUrl(path string, queryParams map[string]string) string {
if queryParams == nil {
return path
}
urlVal := url.Values{}
for k, v := range queryParams {
urlVal.Add(k, v)
}
return path + "?" + urlVal.Encode()
}
Loading
Loading