diff --git a/README.md b/README.md index 8b89ee1..437f37c 100644 --- a/README.md +++ b/README.md @@ -10,24 +10,26 @@ ## Server Setup ### API Service API service for getting the results of ping service. -Use `APIServer: Enabled: true` to turn on in in config-{cluster}.yaml. The default is true for mainnet but false for other clusters. +Use `APIServer: Enabled: true` to turn on in in config-{cluster}.yaml. ### PingService This is similar to "solana ping" tool in solana tool but can do concurrent rpc query. It send transactions to rpc endpoint and wait for transactions is confirmed. -Use `PingServiceEnabled: true` to turn on in config-{cluster}.yaml. The default is On. - +Use `PingServiceEnabled: true` to turn on in config-{cluster}.yaml. ### RetensionService Use `Retension: Enabled: true` in config.yaml to turn on. Default is Off. Clean database data periodically. -### SlackReportService -Use `SlackReport: Enabled:true` in config-{cluster}.yaml to turn on. Default is On. -send summary of ping result to a slack channel periodically. +### ReportService +Use `Report: Enabled:true` in config-{cluster}.yaml to turn on. +ping-api service supports sedning report & alert to both slack and discord. +Use `Report: Slack: Report: Enabled:true` to turn on Slack Report. +This sends summary of ping result to a slack channel periodically. +Use `Report: Slack: Alert: Enabled:true` to turn on Slack Alert. +This will send alert when a event is triggered. See **Alert Spam Filter** for more info. +Use `Report: Discord: Report: Enabled:true` to turn on Discord Report. +Use `Report: Discord: Alert: Enabled:true` to turn on Discord Alert. -### SlackAlertService -Use `SlackReport: SlackAlert: Enabled: true` in config-{cluster}.yaml to turn on. Default is On. -If confirmation loss is greater than a thredhold, send an alert to a channel + Example:Run only API Query Server In config.yaml ServerSetup: @@ -38,10 +40,19 @@ Retension: Enabled: false (config-{cluster}.yaml) PingEnabled: true -SlackReport: +Report: Enabled: true - SlackAlert: - Enabled: true + Slack: + Report: + Enabled: true + Alert: + Enabled: true + Discord: + Enabled: true + Report: + Enabled: false + Alert: + Enabled: true ``` ## Installation - download executable file diff --git a/alert.go b/alert.go index 4560c78..ffd783a 100644 --- a/alert.go +++ b/alert.go @@ -17,11 +17,10 @@ type AlertTrigger struct { func NewAlertTrigger(conf ClusterConfig) AlertTrigger { s := AlertTrigger{} - s.FilePath = conf.SlackReport.SlackAlert.LevelFilePath + s.FilePath = conf.Report.LevelFilePath s.CurrentLoss = 0 s.LastLoss = 0 - s.ThresholdLevels = []float64{float64(conf.SlackReport.SlackAlert.LossThreshold), float64(50), float64(75), float64(100)} - s.FilePath = conf.SlackReport.SlackAlert.LevelFilePath + s.ThresholdLevels = []float64{float64(conf.Report.LossThreshold), float64(50), float64(75), float64(100)} s.ThresholdIndex = s.ReadIndexFromFile() return s } @@ -73,10 +72,13 @@ func (s *AlertTrigger) ReadIndexFromFile() int { // Doing rule here func (s *AlertTrigger) ShouldAlertSend() bool { + if s.ThresholdLevels[0] == 0 { + return true + } if s.CurrentLoss < s.ThresholdLevels[0] { s.ThresholdIndex = 0 s.WritIndexToFile(0) - log.Println("Loss < 20 :", s.CurrentLoss, "Index:", s.ThresholdIndex) + log.Println("Loss = ", s.CurrentLoss, " < ", s.ThresholdLevels[0], "Index:", s.ThresholdIndex) return false } // adjust threshold up, include index = 0 @@ -98,12 +100,3 @@ func (s *AlertTrigger) ShouldAlertSend() bool { log.Println("ThresholdLevel NOT change. Loss:", s.CurrentLoss, "Index:", s.ThresholdIndex) return false } - -func AlertSend(conf ClusterConfig, globalStat *GlobalStatistic, globalErrorStatistic map[string]int, threadhold float64) { - payload := SlackPayload{} - payload.AlertPayload(conf, globalStat, globalErrorStatistic, threadhold) - err := SlackSend(conf.SlackReport.SlackAlert.WebHook, &payload) - if err != nil { - log.Println("SlackSend Error:", err) - } -} diff --git a/config-devnet.yaml.sample b/config-devnet.yaml.sample index 3be0bef..296e975 100644 --- a/config-devnet.yaml.sample +++ b/config-devnet.yaml.sample @@ -19,6 +19,9 @@ AlternativeEnpoint: SlackAlert: # failover alert Enabled: true Webhook: + DiscordAlert: + Enabled: true + Webhook: PingConfig: Receiver: 9qT3WeLV5o3t3GVgCk9A3mpTRjSb9qBvnfrAsVKLhmU5 # change your receive account here NumWorkers: 3 #change number of concurent run here @@ -30,12 +33,24 @@ PingConfig: MinPerPingTime: 10 RequestUnits: 200000 # change RequestUnits ComputeUnitPrice: 1000 # change ComputeUnitPrice -SlackReport: - Enabled: false - WebHook: - ReportInterval: 600 - SlackAlert: - Enabled: true - WebHook: - LossThreshold: 20 - LevelFilePath: /yourpath/level-mainnet.env +Report: + Interval: 600 + LossThreshold: 20 + LevelFilePath: /yourpath/level-devnet.env + Slack: + Report: + Enabled: true + Webhook: + Alert: + Enabled: true + Webhook: + Discord: + BotName: ping-service + BotAvatarURL: + Report: + Enabled: true + Webhook: + Alert: + Enabled: true + Webhook: + diff --git a/config-mainnet-beta.yaml.sample b/config-mainnet-beta.yaml.sample index 4b83736..7cfb40b 100644 --- a/config-mainnet-beta.yaml.sample +++ b/config-mainnet-beta.yaml.sample @@ -19,6 +19,9 @@ AlternativeEnpoint: SlackAlert: # failover alert Enabled: true Webhook: + DiscordAlert: + Enabled: true + Webhook: PingConfig: Receiver: 9qT3WeLV5o3t3GVgCk9A3mpTRjSb9qBvnfrAsVKLhmU5 # change your receive account here NumWorkers: 3 #change number of concurent run here @@ -30,12 +33,23 @@ PingConfig: MinPerPingTime: 10 RequestUnits: 200000 # change RequestUnits ComputeUnitPrice: 1000 # change ComputeUnitPrice -SlackReport: - Enabled: false - WebHook: - ReportInterval: 600 - SlackAlert: - Enabled: true - WebHook: - LossThreshold: 20 - LevelFilePath: /yourpath/level-mainnet.env +Report: + Interval: 600 + LossThreshold: 20 + LevelFilePath: /yourpath/level-mainnet.env + Slack: + Report: + Enabled: true + Webhook: + Alert: + Enabled: true + Webhook: + Discord: + BotName: ping-service + BotAvatarURL: + Report: + Enabled: false + Webhook: + Alert: + Enabled: true + Webhook: \ No newline at end of file diff --git a/config-testnet.yaml.sample b/config-testnet.yaml.sample index 94f20bd..4a288ac 100644 --- a/config-testnet.yaml.sample +++ b/config-testnet.yaml.sample @@ -19,6 +19,9 @@ AlternativeEnpoint: SlackAlert: # failover alert Enabled: true Webhook: + DiscordAlert: + Enabled: true + Webhook: PingConfig: Receiver: 9qT3WeLV5o3t3GVgCk9A3mpTRjSb9qBvnfrAsVKLhmU5 # change your receive account here NumWorkers: 3 #change number of concurent run here @@ -30,12 +33,23 @@ PingConfig: MinPerPingTime: 10 RequestUnits: 200000 # change RequestUnits ComputeUnitPrice: 1000 # change ComputeUnitPrice -SlackReport: - Enabled: false - WebHook: - ReportInterval: 600 - SlackAlert: - Enabled: true - WebHook: - LossThreshold: 20 - LevelFilePath: /yourpath/level-mainnet.env +Report: + Interval: 600 + LossThreshold: 20 + LevelFilePath: /yourpath/level-testnet.env + Slack: + Report: + Enabled: false + Webhook: + Alert: + Enabled: true + Webhook: + Discord: + BotName: ping-service + BotAvatarURL: + Report: + Enabled: false + Webhook: + Alert: + Enabled: true + Webhook: diff --git a/config.go b/config.go index 543a820..f073f92 100644 --- a/config.go +++ b/config.go @@ -31,18 +31,27 @@ type PingConfig struct { RequestUnits uint32 ComputeUnitPrice uint64 } - +type WebHookConfig struct { + Enabled bool + Webhook string +} type SlackReport struct { - Enabled bool - WebHook string - ReportInterval int - SlackAlert + Report WebHookConfig + Alert WebHookConfig } -type SlackAlert struct { +type DiscordReport struct { + BotName string + BotAvatarURL string + Report WebHookConfig + Alert WebHookConfig +} +type Report struct { Enabled bool - WebHook string - LossThreshold int + Interval int + LossThreshold float64 LevelFilePath string + Slack SlackReport + Discord DiscordReport } type APIServer struct { Enabled bool @@ -86,9 +95,14 @@ type RPCEndpoint struct { Piority int MaxRetry int } +type EndpointAlert struct { + Enabled bool + Webhook string +} type AlternativeEnpoint struct { - HostList []RPCEndpoint - SlackAlert + HostList []RPCEndpoint + SlackAlert EndpointAlert + DiscordAlert EndpointAlert } type ClusterPing struct { @@ -96,7 +110,7 @@ type ClusterPing struct { PingServiceEnabled bool AlternativeEnpoint PingConfig - SlackReport + Report } type ClusterConfig struct { diff --git a/main.go b/main.go index a8b208b..274e03b 100644 --- a/main.go +++ b/main.go @@ -15,7 +15,7 @@ import ( var config Config -//Cluster enum +// Cluster enum type Cluster string var database *gorm.DB @@ -25,7 +25,7 @@ const useGCloudDB = true type ClustersToRun string -//Cluster enum +// Cluster enum const ( MainnetBeta Cluster = "MainnetBeta" Testnet = "Testnet" @@ -60,19 +60,20 @@ func init() { log.Println("Mainnet.ClusterPing.PingServiceEnabled", config.Mainnet.ClusterPing.PingServiceEnabled) log.Println("Mainnet.ClusterPing.AlternativeEnpoint.HostList", config.Mainnet.ClusterPing.AlternativeEnpoint.HostList) log.Println("Mainnet.ClusterPing.PingConfig", config.Mainnet.ClusterPing.PingConfig) - log.Println("Mainnet.ClusterPing.SlackReport", config.Mainnet.ClusterPing.SlackReport) + log.Println("Mainnet.ClusterPing.Report", config.Mainnet.ClusterPing.Report) log.Println("--- Testnet Ping --- ") log.Println("Mainnet.ClusterPing.APIServer", config.Testnet.ClusterPing.APIServer) log.Println("Mainnet.ClusterPing.PingServiceEnabled", config.Mainnet.ClusterPing.PingServiceEnabled) log.Println("Testnet.ClusterPing.AlternativeEnpoint.HostList", config.Testnet.ClusterPing.AlternativeEnpoint.HostList) log.Println("Testnet.ClusterPing.PingConfig", config.Testnet.ClusterPing.PingConfig) - log.Println("Testnet.ClusterPing.SlackReport", config.Testnet.ClusterPing.SlackReport) + log.Println("Testnet.ClusterPing.Report", config.Testnet.ClusterPing.Report) log.Println("--- Devnet Ping --- ") log.Println("Devnet.ClusterPing.APIServer", config.Devnet.ClusterPing.APIServer) log.Println("Devnet.ClusterPing.Enabled", config.Devnet.ClusterPing.PingServiceEnabled) log.Println("Devnet.ClusterPing.AlternativeEnpoint.HostList", config.Devnet.ClusterPing.AlternativeEnpoint.HostList) log.Println("Devnet.ClusterPing.PingConfig", config.Devnet.ClusterPing.PingConfig) - log.Println("Devnet.ClusterPing.SlackReport", config.Devnet.ClusterPing.SlackReport) + log.Println("Devnet.ClusterPing.Report", config.Devnet.ClusterPing.Report) + log.Println(" *** Config End *** ") ResponseErrIdentifierInit() diff --git a/output.go b/output.go index 142b906..599dc0e 100644 --- a/output.go +++ b/output.go @@ -5,7 +5,7 @@ import ( "time" ) -//ReportPingResultJSON is a struct convert from PingResult to desire json output struct +// ReportPingResultJSON is a struct convert from PingResult to desire json output struct type DataPoint1MinResultJSON struct { Submitted int `json:"submitted"` Confirmed int `json:"confirmed"` @@ -16,23 +16,30 @@ type DataPoint1MinResultJSON struct { Error string `json:"error"` } -//SlackText slack structure +// SlackText slack structure type SlackText struct { SText string `json:"text"` SType string `json:"type"` } -//Block slack structure +// Block slack structure type Block struct { BlockType string `json:"type"` BlockText SlackText `json:"text"` } -//SlackPayload slack structure +// SlackPayload slack structure type SlackPayload struct { Blocks []Block `json:"blocks"` } +// DiscordPayload slack structure +type DiscordPayload struct { + BotName string `json:"username"` + BotAvatarURL string `json:"avatar_url"` + Content string `json:"content"` +} + func ErrorsToString(errs []string) (errsString string) { for i, e := range errs { if i == 0 { @@ -160,6 +167,46 @@ func reportRecordBlock(data *GroupsAllStatistic) string { return text } +// ReportPayload get the report within specified minutes +func (s *DiscordPayload) ReportPayload(c Cluster, data *GroupsAllStatistic, globalSatistic GlobalStatistic) { + summary := fmt.Sprintf("**total-submitted: %3.0f total-confirmed: %3.0f average-loss: %3.1f%s**", + globalSatistic.Submitted, + globalSatistic.Confirmed, + globalSatistic.Loss*100, "%") + header := "( Submitted, Confirmed, Loss, min/mean/max/stddev ms )" + records := reportRecordBlock(data) + memo := "*BlockhashNotFound do not count as a transaction\n" + errorRecords := reportErrorBlock(data) + s.Content = fmt.Sprintf("%s\n```%s\n%s\n%s\n%s```", summary, header, records, memo, errorRecords) +} + +// AlertPayload get the report within specified minutes +func (s *DiscordPayload) AlertPayload(conf ClusterConfig, gStat *GlobalStatistic, errorStistic map[string]int, thresholdAdj float64) { + var timeStatis string + if gStat.TimeStatistic.Stddev <= 0 { + timeStatis = fmt.Sprintf(" %d/%3.0f/%d/%s ", gStat.TimeStatistic.Min, gStat.TimeStatistic.Mean, gStat.TimeStatistic.Max, "NaN") + } else { + timeStatis = fmt.Sprintf(" %d/%3.0f/%d/%3.0f ", gStat.TimeStatistic.Min, gStat.TimeStatistic.Mean, gStat.TimeStatistic.Max, gStat.TimeStatistic.Stddev) + } + errsorStatis := "" + for k, v := range errorStistic { + if !PingResultError(k).IsInErrorList(AlertErrorExceptionList) { + errsorStatis = fmt.Sprintf("%s%s(%d)", errsorStatis, PingResultError(k).Short(), v) + } + } + + text := fmt.Sprintf("```{ hostname: %s, submitted: %3.0f, confirmed:%3.0f, loss: %3.1f%s, confirmation: min/mean/max/stddev = %s, next_threshold:%3.0f%s, error: %s}```", + conf.HostName, gStat.Submitted, gStat.Confirmed, gStat.Loss*100, "%", timeStatis, thresholdAdj, "%", errsorStatis) + s.Content = text +} + +// FailoverAlertPayload get the report within specified minutes +func (s *DiscordPayload) FailoverAlertPayload(conf ClusterConfig, endpoint FailoverEndpoint, workerNum int) { + s.Content = fmt.Sprintf("```{ hostname: %s, cluster:%s, worker:%d, msg:%s}```", + conf.HostName, conf.Cluster, workerNum, + fmt.Sprintf("failover to %s", endpoint.Endpoint)) + +} func reportErrorBlock(data *GroupsAllStatistic) string { var exceededText, errorText, blackHashText string if len(data.GlobalErrorStatistic) == 0 { diff --git a/report-post.go b/report-post.go new file mode 100644 index 0000000..c455004 --- /dev/null +++ b/report-post.go @@ -0,0 +1,50 @@ +package main + +import ( + "encoding/json" + "fmt" + "log" + + "github.com/parnurzeal/gorequest" +) + +// SlackSend send the payload to then Slack Channel +func SlackSend(webhookURL string, payload *SlackPayload) []error { + data, err := json.Marshal(*payload) + if err != nil { + return []error{fmt.Errorf("marshal payload error. Status:%s", err.Error())} + } + request := gorequest.New() + resp, _, errs := request.Post(webhookURL).Send(string(data)).End() + + if errs != nil { + return errs + } + if resp.StatusCode >= 400 { + log.Println(resp.StatusCode, " payload:", string(data)) + return []error{fmt.Errorf("slack sending msg. Status: %v", resp.Status)} + } + + log.Println("Slack send successfully! =>", webhookURL) + return nil +} + +// DiscordSend send the payload to discord channel by webhook +func DiscordSend(webhookURL string, payload *DiscordPayload) []error { + data, err := json.Marshal(*payload) + if err != nil { + return []error{fmt.Errorf("marshal payload error. Status:%s", err.Error())} + } + request := gorequest.New() + resp, _, errs := request.Post(webhookURL).Send(string(data)).End() + + if errs != nil { + return errs + } + if resp.StatusCode >= 400 { + log.Println(resp.StatusCode, " payload:", string(data)) + return []error{fmt.Errorf("Discord sending msg. Status: %v", resp.Status)} + } + log.Println("Discord send successfully! =>", webhookURL) + return nil +} diff --git a/rpcFailover.go b/rpcFailover.go index 7df72bb..16ac4a2 100644 --- a/rpcFailover.go +++ b/rpcFailover.go @@ -74,7 +74,7 @@ func (f *RPCFailover) GoNext(cur *client.Client, config ClusterConfig, workerNum if config.AlternativeEnpoint.SlackAlert.Enabled { var slack SlackPayload slack.FailoverAlertPayload(config, *f.GetEndpoint(), workerNum) - SlackSend(config.AlternativeEnpoint.SlackAlert.WebHook, &slack) + SlackSend(config.AlternativeEnpoint.SlackAlert.Webhook, &slack) } return next } diff --git a/slack.go b/slack.go deleted file mode 100644 index 4ecbbbe..0000000 --- a/slack.go +++ /dev/null @@ -1,30 +0,0 @@ -package main - -import ( - "encoding/json" - "fmt" - "log" - - "github.com/parnurzeal/gorequest" -) - -//SlackSend send the payload to then Slack Channel -func SlackSend(webhookURL string, payload *SlackPayload) []error { - data, err := json.Marshal(*payload) - if err != nil { - return []error{fmt.Errorf("marshal payload error. Status:%s", err.Error())} - } - request := gorequest.New() - resp, _, errs := request.Post(webhookURL).Send(string(data)).End() - - if errs != nil { - return errs - } - if resp.StatusCode >= 400 { - log.Println(resp.StatusCode, " payload:", string(data)) - return []error{fmt.Errorf("slack sending msg. Status: %v", resp.Status)} - } - - log.Println("Slack send successfully! =>", webhookURL) - return nil -} diff --git a/workers.go b/workers.go index ec57181..78b1f65 100644 --- a/workers.go +++ b/workers.go @@ -14,24 +14,23 @@ type PingType string const DefaultAlertThredHold = 20 const ( - Report PingType = "report" - DataPoint1Min PingType = "datapoint1min" + DataPointReport PingType = "report" + DataPoint1Min PingType = "datapoint1min" ) func launchWorkers(c ClustersToRun) { - // Run API API Service // Run Ping Service runCluster := func(clusterConf ClusterConfig) { if !clusterConf.PingServiceEnabled { log.Println("==> go pingDataWorker", clusterConf.Cluster, " PingServiceEnabled ", clusterConf.PingServiceEnabled) - return - } - for i := 0; i < clusterConf.PingConfig.NumWorkers; i++ { - log.Println("==> go pingDataWorker", clusterConf.Cluster, " n:", clusterConf.PingConfig.NumWorkers, "i:", i) - go pingDataWorker(clusterConf, i) - time.Sleep(2 * time.Second) + } else { + for i := 0; i < clusterConf.PingConfig.NumWorkers; i++ { + log.Println("==> go pingDataWorker", clusterConf.Cluster, " n:", clusterConf.PingConfig.NumWorkers, "i:", i) + go pingDataWorker(clusterConf, i) + time.Sleep(2 * time.Second) + } } - if clusterConf.SlackReport.Enabled { + if clusterConf.Report.Enabled { go reportWorker(clusterConf) } } @@ -53,7 +52,7 @@ func launchWorkers(c ClustersToRun) { // Run Retension Service if config.Retension.Enabled { time.Sleep(2 * time.Second) - go RetensionServiceWorker() + go retensionServiceWorker() } } @@ -101,7 +100,7 @@ func pingDataWorker(cConf ClusterConfig, workerNum int) { } } -func RetensionServiceWorker() { +func retensionServiceWorker() { log.Println(">> Retension Service Worker start!") defer log.Println(">> Retension Service Worker end!") for { @@ -128,24 +127,22 @@ func getConfigKeyPair(c SolanaCLIConfig) (types.Account, error) { if err != nil { return types.Account{}, err } - acct, err := types.AccountFromBytes(key) if err != nil { return types.Account{}, err } return acct, nil - } func reportWorker(cConf ClusterConfig) { - log.Println(">> Slack Report Worker for ", cConf.Cluster, " start!") - defer log.Println(">> Slack Report Worker for ", cConf.Cluster, " end!") + log.Println(">> Report Worker for ", cConf.Cluster, " start!") + defer log.Println(">> Report Worker for ", cConf.Cluster, " end!") var lastReporTime int64 - slackTrigger := NewAlertTrigger(cConf) + trigger := NewAlertTrigger(cConf) for { now := time.Now().UTC().Unix() if lastReporTime == 0 { // server restart - lastReporTime = now - int64(cConf.SlackReport.ReportInterval) + lastReporTime = now - int64(cConf.Report.Interval) log.Println("reconstruct lastReport time=", lastReporTime, "time now=", time.Now().UTC().Unix()) } data := getAfter(cConf.Cluster, DataPoint1Min, lastReporTime) @@ -154,25 +151,64 @@ func reportWorker(cConf ClusterConfig) { time.Sleep(30 * time.Second) continue } - groups := grouping1Min(data, lastReporTime, now) groupsStat := statisticCompute(cConf, groups) globalStat := groupsStat.GetGroupsAllStatistic(false) // get raw data lastReporTime = now - payload := SlackPayload{} - payload.ReportPayload(cConf.Cluster, groupsStat, globalStat) - err := SlackSend(cConf.SlackReport.WebHook, &payload) - if err != nil { - log.Println("SlackSend Error:", err) + trigger.Update(globalStat.Loss) + if cConf.Report.Slack.Report.Enabled { + slackReportSend(cConf, groupsStat, &globalStat) } + if cConf.Report.Slack.Alert.Enabled { + if trigger.ShouldAlertSend() { + slackAlertSend(cConf, &globalStat, groupsStat.GlobalErrorStatistic, trigger.ThresholdLevels[trigger.ThresholdIndex]) + } + + } + if cConf.Report.Discord.Report.Enabled { + discordReportSend(cConf, groupsStat, &globalStat) + } + if cConf.Report.Discord.Alert.Enabled { - if cConf.SlackReport.SlackAlert.Enabled { - slackTrigger.Update(globalStat.Loss) - if slackTrigger.ShouldAlertSend() { - AlertSend(cConf, &globalStat, groupsStat.GlobalErrorStatistic, slackTrigger.ThresholdLevels[slackTrigger.ThresholdIndex]) + if trigger.ShouldAlertSend() { + discordAlertSend(cConf, &globalStat, groupsStat.GlobalErrorStatistic, trigger.ThresholdLevels[trigger.ThresholdIndex]) } } - time.Sleep(time.Duration(cConf.SlackReport.ReportInterval) * time.Second) + time.Sleep(time.Duration(cConf.Report.Interval) * time.Second) + } +} +func slackReportSend(cConf ClusterConfig, groupsStat *GroupsAllStatistic, globalStat *GlobalStatistic) { + payload := SlackPayload{} + payload.ReportPayload(cConf.Cluster, groupsStat, *globalStat) + err := SlackSend(cConf.Report.Slack.Report.Webhook, &payload) + if err != nil { + log.Println("slackReportSend Error:", err) + } +} +func slackAlertSend(conf ClusterConfig, globalStat *GlobalStatistic, globalErrorStatistic map[string]int, threadhold float64) { + payload := SlackPayload{} + payload.AlertPayload(conf, globalStat, globalErrorStatistic, threadhold) + err := SlackSend(conf.Report.Slack.Alert.Webhook, &payload) + if err != nil { + log.Println("slackAlertSend Error:", err) + } +} + +func discordReportSend(cConf ClusterConfig, groupsStat *GroupsAllStatistic, globalStat *GlobalStatistic) { + payload := DiscordPayload{BotAvatarURL: cConf.Report.Discord.BotAvatarURL, BotName: cConf.Report.Discord.BotName} + payload.ReportPayload(cConf.Cluster, groupsStat, *globalStat) + err := DiscordSend(cConf.Report.Discord.Report.Webhook, &payload) + if err != nil { + log.Println("discordReportSend Error:", err) + } +} + +func discordAlertSend(cConf ClusterConfig, globalStat *GlobalStatistic, globalErrorStatistic map[string]int, threadhold float64) { + payload := DiscordPayload{BotAvatarURL: cConf.Report.Discord.BotAvatarURL, BotName: cConf.Report.Discord.BotName} + payload.AlertPayload(cConf, globalStat, globalErrorStatistic, threadhold) + err := DiscordSend(cConf.Report.Discord.Alert.Webhook, &payload) + if err != nil { + log.Println("discordAlertSend Error:", err) } }