华为云CES监控与飞书通知

news2025/5/22 11:10:39

华为云负载均衡连接数监控与飞书通知

在云服务的日常运维中,持续监控资源状态是保障系统稳定性的关键步骤之一。本文通过一个实际案例展示了如何使用华为云的Go SDK获取负载均衡器的连接数,并通过飞书Webhook发送通知到团队群组,以便运维人员及时获取最新的监控信息。本来准备直接使用ces告警,但是看了一下模版以及最佳实践貌似没有很好的支持webhook,就直接自己使用go sdk实现了!

背景知识

在华为云上,负载均衡服务(ELB)用于分发来自客户端的网络请求到多个云服务器,确保系统在面对不同的负载情况时,仍能够提供稳定、可靠的服务。ELB的性能指标,如每分钟连接数(CPS),是反映当前系统承载能力的重要数据。通常情况下,我们希望能够实时监控这些关键指标。

随着云服务技术的成熟,大型企业往往会将监控数据集成到实时通讯工具中,便于团队成员即时查看和响应潜在的问题。本案例中选择的通讯工具是飞书,华为云Go SDK则是我们与华为云服务交互的媒介。

环境准备

华为云提供的Go SDK是一套围绕华为云API构建的开发工具包,使得开发者可以在Go语言环境中便捷地调用云服务。在这里,我们利用Cloud Eye Service (CES) 的API,通过SDK检索ELB的CPS指标数据。

安装华为云Go SDK

首先需要安装华为云Go SDK。可以通过go get命令安装所需的SDK包:

go get -u github.com/huaweicloud/huaweicloud-sdk-go-v3

安装完成后,即可在项目中引入相关的SDK模块。

初始化客户端

要与华为云的服务交互,我们需要创建并初始化一个SDK客户端。如下示例中,我们创建了用于CES(Cloud Eye Service)服务的客户端,并使用了之前提到的AK和SK进行了认证。

package main

// 导入相关的包
import (
    "fmt"
    "bytes"
    "json"
    "http"
    "ioutil"
    "time"

    "github.com/huaweicloud/huaweicloud-sdk-go-v3/core/auth/basic"
    "github.com/huaweicloud/huaweicloud-sdk-go-v3/services/ces/v1"
    ces "github.com/huaweicloud/huaweicloud-sdk-go-v3/services/ces/v1/model"
)

const (
    feishuWebhookURL = "xxxx" // 飞书Webhook URL
    ak               = "xxx"  // Access Key
    sk               = "xxxxx" // Secret Key
)

func main() {
    // 构建认证信息
    auth := basic.NewCredentialsBuilder().
       WithAk(ak).
       WithSk(sk).
       Build()

    // 初始化CES客户端
    client := ces.NewCesClient(
       ces.CesClientBuilder().
          WithRegion(region.ValueOf("cn-east-3")).
          WithCredential(auth).
          Build())

    // ...后续代码
}

设置定时器和执行任务

我们通过一个定时器来定期检查负载均衡器的最大连接数,例如:

    ticker := time.NewTicker(1 * time.Minute) // 每分钟触发检查
    for {
       select {
       case t := <-ticker.C:
          currentHour := t.Hour()
          // 只在既定的时间范围内执行
          if currentHour >= 7 && currentHour < 24 {
             // 我们设定在59分时收集数据
             if t.Minute() == 59 {
                go collectDataAndSendToFeishu(client)
             }
          }
       }
    }

这里限制了定时器发送的时间范围早上7点到24点执行,0点-7点默认不执行。并且执行的时间是每个小时的59分执行!

收集和发送数据

一旦定时器触发并满足条件,我们会收集负载均衡的最大连接数并发送给飞书,参考 华为云ces ShowMetricData接口:
image.png
具体实现如下,注意**ShowMetricDataRequest **中具体参数:

func collectDataAndSendToFeishu(client *ces.CesClient) {
    currentTime := time.Now().UTC()
    startTime := currentTime.Truncate(time.Hour).Add(time.Minute * 58)
    endTime := startTime.Add(time.Minute)

    startTimestamp := startTime.UnixNano() / int64(time.Millisecond)
    endTimestamp := endTime.UnixNano() / int64(time.Millisecond)

    request := &model.ShowMetricDataRequest{
       Namespace:  "SYS.ELB",
       MetricName: "m1_cps",
       Dim0:       "lbaas_instance_id,xxxxxx",
       Filter:     model.GetShowMetricDataRequestFilterEnum().MAX,
       Period:     int32(1),
       From:       startTimestamp,
       To:         endTimestamp,
    }

    response, err := client.ShowMetricData(request)
    if err != nil {
       fmt.Println("Error querying CES data:", err)
       return
    }
    fmt.Printf("CES response: %+v\n", response)

    // Extract max value and timestamp from the response
    var maxConnection float64
    var timestamp int64
    if response.Datapoints != nil && len(*response.Datapoints) > 0 {
       datapoints := *response.Datapoints
       maxConnection = *datapoints[0].Max
       timestamp = datapoints[0].Timestamp
    }

    // Format the timestamp to a readable form
    readableTime := time.Unix(timestamp/1000, (timestamp%1000)*int64(time.Millisecond)).Format("2006-01-02 15:04:05")
    // Prepare the message to send to Feishu
    feishuMessage := fmt.Sprintf("当前时间 %s 负载均衡最大连接数是 %.2f", readableTime, maxConnection)

    if err := sendToFeishuWebhook(feishuWebhookURL, feishuMessage); err != nil {
       fmt.Println("Error sending to Feishu webhook:", err)
    }
}

发送Webhook通知

最后,实现sendToFeishuWebhook方法以将消息推送到飞书。

func sendToFeishuWebhook(webhookURL string, message string) error {
    webhookMessage := FeishuWebhookMessage{
       MsgType: "text",
    }
    webhookMessage.Content.Text = message

    jsonData, err := json.Marshal(webhookMessage)
    if err != nil {
       return fmt.Errorf("failed to marshal webhook message: %v", err)
    }

    req, err := http.NewRequest("POST", webhookURL, bytes.NewBuffer(jsonData))
    if err != nil {
       return fmt.Errorf("failed to create HTTP request: %v", err)
    }
    req.Header.Set("Content-Type", "application/json")

    client := &http.Client{}
    resp, err := client.Do(req)
    if err != nil {
       return fmt.Errorf("failed to send HTTP request: %v", err)
    }
    defer resp.Body.Close()

    responseBody, err := ioutil.ReadAll(resp.Body)
    if err != nil {
       return fmt.Errorf("failed to read webhook response body: %v", err)
    }

    fmt.Println("Feishu webhook response:", string(responseBody))
    return nil
}

完整代码:

每小时59分统计58-59分最大值发送统计到飞书:

package main
type FeishuWebhookMessage struct {
    MsgType string `json:"msg_type"`
    Content struct {
       Text string `json:"text"`
    } `json:"content"`
}

const (
    // 定时器间隔,用于根据特定时间点触发数据检索。例如:59分时执行任务,就是(59 - 当前时间的分钟数) x 每分钟的秒数
    feishuWebhookURL = "xxxx"
    ak               = "xxx"
    sk               = "xxxxx"
)

func main() {
    auth := basic.NewCredentialsBuilder().
       WithAk(ak).
       WithSk(sk).
       Build()

    client := ces.NewCesClient(
       ces.CesClientBuilder().
          WithRegion(region.ValueOf("cn-east-3")).
          WithCredential(auth).
          Build())

    ticker := time.NewTicker(1 * time.Minute) // Check every 10 minutes to adjust for the next 59th minute.
    for {
       select {
       case t := <-ticker.C:
          // 这里设置只在7-24点执行
          currentHour := t.Hour()
          if currentHour >= 7 && currentHour < 24 {
             if t.Minute() == 59 {
                go collectDataAndSendToFeishu(client)
             }
          }
       }
    }
}
func collectDataAndSendToFeishu(client *ces.CesClient) {
    currentTime := time.Now().UTC()
    startTime := currentTime.Truncate(time.Hour).Add(time.Minute * 58)
    endTime := startTime.Add(time.Minute)

    startTimestamp := startTime.UnixNano() / int64(time.Millisecond)
    endTimestamp := endTime.UnixNano() / int64(time.Millisecond)

    request := &model.ShowMetricDataRequest{
       Namespace:  "SYS.ELB",
       MetricName: "m1_cps",
       Dim0:       "lbaas_instance_id,xxxxxx",
       Filter:     model.GetShowMetricDataRequestFilterEnum().MAX,
       Period:     int32(1),
       From:       startTimestamp,
       To:         endTimestamp,
    }

    response, err := client.ShowMetricData(request)
    if err != nil {
       fmt.Println("Error querying CES data:", err)
       return
    }
    fmt.Printf("CES response: %+v\n", response)

    // Extract max value and timestamp from the response
    var maxConnection float64
    var timestamp int64
    if response.Datapoints != nil && len(*response.Datapoints) > 0 {
       datapoints := *response.Datapoints
       maxConnection = *datapoints[0].Max
       timestamp = datapoints[0].Timestamp
    }

    // Format the timestamp to a readable form
    readableTime := time.Unix(timestamp/1000, (timestamp%1000)*int64(time.Millisecond)).Format("2006-01-02 15:04:05")
    // Prepare the message to send to Feishu
    feishuMessage := fmt.Sprintf("当前时间 %s 负载均衡最大连接数是 %.2f", readableTime, maxConnection)

    if err := sendToFeishuWebhook(feishuWebhookURL, feishuMessage); err != nil {
       fmt.Println("Error sending to Feishu webhook:", err)
    }
}

// sendToFeishuWebhook sends a message to Feishu webhook
func sendToFeishuWebhook(webhookURL string, message string) error {
    webhookMessage := FeishuWebhookMessage{
       MsgType: "text",
    }
    webhookMessage.Content.Text = message

    jsonData, err := json.Marshal(webhookMessage)
    if err != nil {
       return fmt.Errorf("failed to marshal webhook message: %v", err)
    }

    req, err := http.NewRequest("POST", webhookURL, bytes.NewBuffer(jsonData))
    if err != nil {
       return fmt.Errorf("failed to create HTTP request: %v", err)
    }
    req.Header.Set("Content-Type", "application/json")

    client := &http.Client{}
    resp, err := client.Do(req)
    if err != nil {
       return fmt.Errorf("failed to send HTTP request: %v", err)
    }
    defer resp.Body.Close()

    responseBody, err := ioutil.ReadAll(resp.Body)
    if err != nil {
       return fmt.Errorf("failed to read webhook response body: %v", err)
    }

    fmt.Println("Feishu webhook response:", string(responseBody))
    return nil
}

运行以上代码:
img_v3_026i_b57d3d26-178b-4f64-8ade-5ecfcd3917dg.jpg

其它的扩展玩法:

每分钟检查一次,当连接数大于100报警触发

package main

import (
	"bytes"
	"encoding/json"
	"fmt"
	"github.com/huaweicloud/huaweicloud-sdk-go-v3/core/auth/basic"
	ces "github.com/huaweicloud/huaweicloud-sdk-go-v3/services/ces/v1"
	"github.com/huaweicloud/huaweicloud-sdk-go-v3/services/ces/v1/model"
	region "github.com/huaweicloud/huaweicloud-sdk-go-v3/services/ces/v1/region"
	"io/ioutil"
	"net/http"
	"time"
)

type FeishuWebhookMessage struct {
	MsgType string `json:"msg_type"`
	Content struct {
		Text string `json:"text"`
	} `json:"content"`
}

const (
	feishuWebhookURL = "xxxx"
	ak               = "xxxx"
	sk               = "xxxxx"
)

func main() {
	auth := basic.NewCredentialsBuilder().
		WithAk(ak).
		WithSk(sk).
		Build()

	client := ces.NewCesClient(
		ces.CesClientBuilder().
			WithRegion(region.ValueOf("cn-east-3")).
			WithCredential(auth).
			Build())

	ticker := time.NewTicker(1 * time.Minute) // Check every 10 minutes to adjust for the next 59th minute.
	for {
		select {
		case t := <-ticker.C:
			// 这里设置只在7-24点执行
			currentHour := t.Hour()
			if currentHour >= 7 && currentHour < 24 {
				go collectDataAndSendToFeishu(client)
			}
		}
	}
}
func collectDataAndSendToFeishu(client *ces.CesClient) {
	currentTime := time.Now().UTC().Truncate(time.Minute)
	startTime := currentTime.Add(-1 * time.Minute)
	endTime := currentTime

	startTimestamp := startTime.UnixNano() / int64(time.Millisecond)
	endTimestamp := endTime.UnixNano() / int64(time.Millisecond)

	request := &model.ShowMetricDataRequest{
		Namespace:  "SYS.ELB",
		MetricName: "m1_cps",
		Dim0:       "lbaas_instance_id,xxxxx",
		Filter:     model.GetShowMetricDataRequestFilterEnum().MAX,
		Period:     int32(1),
		From:       startTimestamp,
		To:         endTimestamp,
	}

	response, err := client.ShowMetricData(request)
	if err != nil {
		fmt.Println("Error querying CES data:", err)
		return
	}
	fmt.Printf("CES response: %+v\n", response)

	// Extract max value and timestamp from the response
	var maxConnection float64
	var timestamp int64
	if response.Datapoints != nil && len(*response.Datapoints) > 0 {
		datapoints := *response.Datapoints
		maxConnection = *datapoints[0].Max
		timestamp = datapoints[0].Timestamp
	}

	// Format the timestamp to a readable form
	readableTime := time.Unix(timestamp/1000, (timestamp%1000)*int64(time.Millisecond)).Format("2006-01-02 15:04:05")
	// Prepare the message to send to Feishu
	if maxConnection > 100 {
		// Prepare the alert message to send to Feishu
		feishuMessage := fmt.Sprintf("警告:当前时间 %s 负载均衡连接数超越100,当前数值是 %.2f", readableTime, maxConnection)

		if err := sendToFeishuWebhook(feishuWebhookURL, feishuMessage); err != nil {
			fmt.Println("Error sending to Feishu webhook:", err)
		}
	}
}

// sendToFeishuWebhook sends a message to Feishu webhook
func sendToFeishuWebhook(webhookURL string, message string) error {
	webhookMessage := FeishuWebhookMessage{
		MsgType: "text",
	}
	webhookMessage.Content.Text = message

	jsonData, err := json.Marshal(webhookMessage)
	if err != nil {
		return fmt.Errorf("failed to marshal webhook message: %v", err)
	}

	req, err := http.NewRequest("POST", webhookURL, bytes.NewBuffer(jsonData))
	if err != nil {
		return fmt.Errorf("failed to create HTTP request: %v", err)
	}
	req.Header.Set("Content-Type", "application/json")

	client := &http.Client{}
	resp, err := client.Do(req)
	if err != nil {
		return fmt.Errorf("failed to send HTTP request: %v", err)
	}
	defer resp.Body.Close()

	responseBody, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return fmt.Errorf("failed to read webhook response body: %v", err)
	}

	fmt.Println("Feishu webhook response:", string(responseBody))
	return nil
}

为了方便代码的复用性,可读性。将100作为一个可配置常量提取出来:

package main

import (
	"bytes"
	"encoding/json"
	"fmt"
	"github.com/huaweicloud/huaweicloud-sdk-go-v3/core/auth/basic"
	ces "github.com/huaweicloud/huaweicloud-sdk-go-v3/services/ces/v1"
	"github.com/huaweicloud/huaweicloud-sdk-go-v3/services/ces/v1/model"
	region "github.com/huaweicloud/huaweicloud-sdk-go-v3/services/ces/v1/region"
	"io/ioutil"
	"net/http"
	"time"
)

type FeishuWebhookMessage struct {
	MsgType string `json:"msg_type"`
	Content struct {
		Text string `json:"text"`
	} `json:"content"`
}

const (
	// 定时器间隔,用于根据特定时间点触发数据检索。例如:59分时执行任务,就是(59 - 当前时间的分钟数) x 每分钟的秒数
	feishuWebhookURL                = "xxxxx"
	ak                              = "xxxx"
	sk                              = "xxxx"
	loadBalancerConnectionThreshold = 100.00 // 负载均衡连接数阈值
)

func main() {
	auth := basic.NewCredentialsBuilder().
		WithAk(ak).
		WithSk(sk).
		Build()

	client := ces.NewCesClient(
		ces.CesClientBuilder().
			WithRegion(region.ValueOf("cn-east-3")).
			WithCredential(auth).
			Build())

	ticker := time.NewTicker(1 * time.Minute) // Check every 10 minutes to adjust for the next 59th minute.
	for {
		select {
		case t := <-ticker.C:
			// 这里设置只在7-24点执行
			currentHour := t.Hour()
			if currentHour >= 7 && currentHour < 24 {
				go collectDataAndSendToFeishu(client)
			}
		}
	}
}
func collectDataAndSendToFeishu(client *ces.CesClient) {
	currentTime := time.Now().UTC().Truncate(time.Minute)
	startTime := currentTime.Add(-1 * time.Minute)
	endTime := currentTime

	startTimestamp := startTime.UnixNano() / int64(time.Millisecond)
	endTimestamp := endTime.UnixNano() / int64(time.Millisecond)

	request := &model.ShowMetricDataRequest{
		Namespace:  "SYS.ELB",
		MetricName: "m1_cps",
		Dim0:       "lbaas_instance_id,xxxx",
		Filter:     model.GetShowMetricDataRequestFilterEnum().MAX,
		Period:     int32(1),
		From:       startTimestamp,
		To:         endTimestamp,
	}

	response, err := client.ShowMetricData(request)
	if err != nil {
		fmt.Println("Error querying CES data:", err)
		return
	}
	fmt.Printf("CES response: %+v\n", response)

	// Extract max value and timestamp from the response
	var maxConnection float64
	var timestamp int64
	if response.Datapoints != nil && len(*response.Datapoints) > 0 {
		datapoints := *response.Datapoints
		maxConnection = *datapoints[0].Max
		timestamp = datapoints[0].Timestamp
	}

	// Format the timestamp to a readable form
	readableTime := time.Unix(timestamp/1000, (timestamp%1000)*int64(time.Millisecond)).Format("2006-01-02 15:04:05")
	// Prepare the message to send to Feishu
	if maxConnection > loadBalancerConnectionThreshold {
		// Prepare the alert message to send to Feishu
		feishuMessage := fmt.Sprintf("警报:在%s,负载均衡器的连接数超过了%.2f,当前连接数:%.2f", readableTime, loadBalancerConnectionThreshold, maxConnection)

		if err := sendToFeishuWebhook(feishuWebhookURL, feishuMessage); err != nil {
			fmt.Println("Error sending to Feishu webhook:", err)
		}
	}
}

// sendToFeishuWebhook sends a message to Feishu webhook
func sendToFeishuWebhook(webhookURL string, message string) error {
	webhookMessage := FeishuWebhookMessage{
		MsgType: "text",
	}
	webhookMessage.Content.Text = message

	jsonData, err := json.Marshal(webhookMessage)
	if err != nil {
		return fmt.Errorf("failed to marshal webhook message: %v", err)
	}

	req, err := http.NewRequest("POST", webhookURL, bytes.NewBuffer(jsonData))
	if err != nil {
		return fmt.Errorf("failed to create HTTP request: %v", err)
	}
	req.Header.Set("Content-Type", "application/json")

	client := &http.Client{}
	resp, err := client.Do(req)
	if err != nil {
		return fmt.Errorf("failed to send HTTP request: %v", err)
	}
	defer resp.Body.Close()

	responseBody, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return fmt.Errorf("failed to read webhook response body: %v", err)
	}

	fmt.Println("Feishu webhook response:", string(responseBody))
	return nil
}

注意loadBalancerConnectionThresholdfloat64.

增加 MetricName多个条件

这里以弹性IP EIP与负载均衡为例,我想查询负载均衡连接数大于100报警,并根据负载均衡对应eip的四个指标:“upstream_bandwidth_usage”,“downstream_bandwidth_usage”,“upstream_bandwidth”,"downstream_bandwidth"报警,完整代码如下:

package main

import (
	"bytes"
	"encoding/json"
	"fmt"
	"github.com/huaweicloud/huaweicloud-sdk-go-v3/core/auth/basic"
	ces "github.com/huaweicloud/huaweicloud-sdk-go-v3/services/ces/v1"
	"github.com/huaweicloud/huaweicloud-sdk-go-v3/services/ces/v1/model"
	region "github.com/huaweicloud/huaweicloud-sdk-go-v3/services/ces/v1/region"
	"io/ioutil"
	"net/http"
	"time"
)

type FeishuWebhookMessage struct {
	MsgType string `json:"msg_type"`
	Content struct {
		Text string `json:"text"`
	} `json:"content"`
}

const (
	// 定时器间隔,用于根据特定时间点触发数据检索。例如:59分时执行任务,就是(59 - 当前时间的分钟数) x 每分钟的秒数
	feishuWebhookURL                = "xxxxxxx"
	ak                              = "xxx"
	sk                              = "xxxx"
	upstreamBandwidthThreshold      = 40    // 出网带宽阈值,单位Mbps
	downstreamBandwidthThreshold    = 80    // 入网带宽阈值,单位Mbps(示例中以百分比为单位,根据实际单位调整)
	upstreamUsageThreshold          = 20    // 出网带宽使用率阈值,单位百分比
	downstreamUsageThreshold        = 40    // 入网带宽使用率阈值,单位百分比
)

var metricNames = []string{
	"upstream_bandwidth_usage",
	"downstream_bandwidth_usage",
	"upstream_bandwidth",
	"downstream_bandwidth",
}

func main() {
	auth := basic.NewCredentialsBuilder().
		WithAk(ak).
		WithSk(sk).
		Build()

	client := ces.NewCesClient(
		ces.CesClientBuilder().
			WithRegion(region.ValueOf("cn-east-3")).
			WithCredential(auth).
			Build())

	ticker := time.NewTicker(time.Minute) // Check every minute.
	for {
		select {
		case <-ticker.C:
			// 每分钟执行
			go collectDataAndSendToFeishu(client)
		}
	}
}

func collectDataAndSendToFeishu(client *ces.CesClient) {
	currentTime := time.Now().UTC().Truncate(time.Minute)
	startTime := currentTime.Add(-1 * time.Minute)
	endTime := currentTime

	startTimestamp := startTime.UnixMilli()
	endTimestamp := endTime.UnixMilli()
	dimensionValues := "bandwidth_id,xxxx"
	for _, metricName := range metricNames {
		request := &model.ShowMetricDataRequest{
			Namespace:  "SYS.VPC",
			MetricName: metricName,
			Dim0:       dimensionValues, // Replace with actual dimension value
			Filter:     model.GetShowMetricDataRequestFilterEnum().MAX,
			Period:     int32(1),
			From:       startTimestamp,
			To:         endTimestamp,
		}

		response, err := client.ShowMetricData(request)
		if err != nil {
			fmt.Printf("Error querying CES data for %s: %v\n", metricName, err)
			continue
		}

		if response.Datapoints == nil || len(*response.Datapoints) == 0 {
			fmt.Printf("No datapoints received for %s\n", metricName)
			continue
		}

		datapoints := *response.Datapoints
		var maxUsage float64
		for _, point := range datapoints {
			if point.Max != nil {
				if metricName == "upstream_bandwidth" || metricName == "downstream_bandwidth" {
					// Convert from bits to Mbits
					maxUsage = *point.Max / 1000000.0
				} else {
					maxUsage = *point.Max // for utilization metrics, which are percentages
				}
				break // Assuming there's only 1 datapoint with MAX filter
			}
		}

		if (metricName == "upstream_bandwidth" && maxUsage > upstreamBandwidthThreshold) ||
			(metricName == "downstream_bandwidth" && maxUsage > downstreamBandwidthThreshold) ||
			(metricName == "upstream_bandwidth_usage" && maxUsage > upstreamUsageThreshold) ||
			(metricName == "downstream_bandwidth_usage" && maxUsage > downstreamUsageThreshold) {

			alertMessage := createAlertMessage(metricName, maxUsage, endTime)
			if err := sendToFeishuWebhook(feishuWebhookURL, alertMessage); err != nil {
				fmt.Printf("Error sending to Feishu webhook: %v\n", err)
			}
		}
	}
}

func createAlertMessage(metricName string, usage float64, endTime time.Time) string {
	readableTime := endTime.Add(+8 * time.Hour).Format("2006-01-02 15:04:05")
	var alertMessage string

	// 注意阈值和单位已更新,具体文本格式根据实际需要调整
	switch metricName {
	case "upstream_bandwidth":
		alertMessage = fmt.Sprintf("警报:在%s,出网带宽超过了%.2fMbps,当前带宽:%.2fMbps", readableTime, upstreamBandwidthThreshold, usage)
	case "downstream_bandwidth":
		alertMessage = fmt.Sprintf("警报:在%s,入网带宽超过了%.2fMbps,当前带宽:%.2fMbps", readableTime, downstreamBandwidthThreshold, usage)
	case "upstream_bandwidth_usage":
		alertMessage = fmt.Sprintf("警报:在%s,出网带宽使用率超过了%.2f%%,当前使用率:%.2f%%", readableTime, upstreamUsageThreshold, usage)
	case "downstream_bandwidth_usage":
		alertMessage = fmt.Sprintf("警报:在%s,入网带宽使用率超过了%.2f%%,当前使用率:%.2f%%", readableTime, downstreamUsageThreshold, usage)
	}

	return alertMessage
}

func sendToFeishuWebhook(webhookURL string, message string) error {
	webhookMessage := FeishuWebhookMessage{
		MsgType: "text",
	}
	webhookMessage.Content.Text = message

	jsonData, err := json.Marshal(webhookMessage)
	if err != nil {
		return fmt.Errorf("failed to marshal webhook message: %v", err)
	}

	req, err := http.NewRequest("POST", webhookURL, bytes.NewBuffer(jsonData))
	if err != nil {
		return fmt.Errorf("failed to create HTTP request: %v", err)
	}
	req.Header.Set("Content-Type", "application/json")

	client := &http.Client{}
	resp, err := client.Do(req)
	if err != nil {
		return fmt.Errorf("failed to send HTTP request: %v", err)
	}
	defer resp.Body.Close()

	responseBody, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return fmt.Errorf("failed to read webhook response body: %v", err)
	}

	fmt.Printf("Feishu webhook response: %s\n", responseBody)
	return nil
}

测试报警如下:
image.png

其他

  1. 遍历负载均衡列表,批量查询所有负载均衡连接数?发送告警时候传入负载均衡的名称?
  2. 根据负载均衡列表查询绑定的eip实例,查询所有eip对应bandwidth_id,输出所有eip的指标?

总结

此文为你展示了如何通过Go SDK获取华为云上的负载均衡最大连接数and eip指标的多个条件查询,并通过飞书Webhook发送通知的过程。以上的实现可以根据你自己的需求进行调整,比如改变监测的指标或者消息发送的方式。希望本文能帮助你更好地监控和管理华为云上的资源。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1356311.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

2024 Nomachine 最简安装与使用指南

一、前言 二、Nomachine安装包的下载 1、Windows系统下Nomachine包的下载 2、Linux系统Nomachine的下载 &#xff08;1&#xff09;下载Nomachine安装包 &#xff08;2&#xff09;解压安装包 &#xff08;3&#xff09;添加权限 &#xff08;4&#xff09;下载安装包 三、在Wi…

基于GEC6818的点餐系统

本次项目开发环境&#xff1a;gec6818&#xff0c;QT5.14.2&#xff0c;SecureCRT。 所使用的相关技术&#xff1a;c/s架构&#xff0c;STL库&#xff0c;C封装&#xff0c;标准化代码编写 实现的功能&#xff1a;用户登录页面&#xff0c;食品分区在不同页面&#xff0c;用户…

2023海内外零知识证明学习资料汇总(二)(深入理解零知识证明篇)

工欲善其事,必先利其器 Web3开发中&#xff0c;各种工具、教程、社区、语言框架.。。。 种类繁多&#xff0c;是否有一个包罗万象的工具专注与Web3开发和相关资讯能毕其功于一役&#xff1f; 参见另一篇博文&#x1f449; 2024最全面且有知识深度的web3开发工具、web3学习项目…

Java中关键词strictfp有什么作用?

在Java中&#xff0c;关键词strictfp用于声明一个方法、类或接口是严格遵守浮点数计算规范的。 具体作用包括&#xff1a; 保证浮点数计算的结果在不同平台上是一致的&#xff0c;避免由于浮点数计算的不精确性导致的结果不确定性。 指定了严格的浮点数计算规则&#xff0c;禁…

【机器学习基础】DBSCAN

&#x1f680;个人主页&#xff1a;为梦而生~ 关注我一起学习吧&#xff01; &#x1f4a1;专栏&#xff1a;机器学习 欢迎订阅&#xff01;相对完整的机器学习基础教学&#xff01; ⭐特别提醒&#xff1a;针对机器学习&#xff0c;特别开始专栏&#xff1a;机器学习python实战…

springboot实现用户操作日志记录

springboot实现用户操作日志记录 简介&#xff1a;之前写了《aop实现日志持久化记录》一文&#xff0c;主要介绍自定义aop标注方法上&#xff0c;通过切面方法对用户操作插入mysql。思路正确但是实际操作上存在一些小问题&#xff0c;本文将从项目出发&#xff0c;对细节进行补…

vue3+vant4 移动端软键盘弹出 收起导致项目样式布局错乱解决方案,亲测有效!!

问题描述 最近在做vue3 H5的移动端项目 我用的是vue3vant4&#xff0c;然后在使用过程中发现 小米14手机在点击密码输入框软键盘弹出 时会导致项目布局整体向上移动 导致页面布局错乱。 原因分析&#xff1a; 在移动端软键盘弹出收起时&#xff0c;导致项目样式布局错乱的原因…

内网DNS隐蔽隧道搭建之iodine工具

iodine iodine是基于C语言开发的&#xff0c;分为服务端和客户端。iodine支持转发模式和中继模式。其原理是&#xff1a;通过TAP虚拟网卡&#xff0c;在服务端建立一个局域网&#xff1b;在客户端&#xff0c;通过TAP建立一个虚拟网卡&#xff1b;两者通过DNS隧道连接&#xf…

前端开发加速器:十个VSCode插件精选

前端开发是一个不断发展的领域&#xff0c;随着技术的进步&#xff0c;工具也在不断更新。Visual Studio Code&#xff08;VSCode&#xff09;是前端开发者广泛使用的编辑器之一&#xff0c;得益于其强大的插件系统&#xff0c;可以帮助开发者提升工作效率。以下是十个对于前端…

任务需求分析中的流程图、用例图、er图、类图、时序图线段、图形的作用意义

任务需求分析中的流程图、用例图、er图、类图、时序图线段、图形的作用意义 流程图 流程图中各种图形的含义及用法解析 连接线符号 连接各要素&#xff0c;表示流程的顺序或过程的方向。 批注符号 批注或说明&#xff0c;也可以做条件叙述。 子流程 流程中一部分图形的逻辑…

程序员如何应对裁员-法律知识

目录 程序员如何应对裁员-法律知识 前言收到辞退消息后被要求主动离职可以赔偿多少呢裁员赔偿工资是指基本工资吗被强制接触劳动合同&#xff0c;也不愿意支付赔偿孕妇&#xff0c;公司让离职谈话之后&#xff0c;老板还是不愿意给补偿&#xff0c;我应该怎么办&#xff1f;离…

IO作业4.0

思维导图 创建出三个进程完成两个文件之间拷贝工作&#xff0c;子进程1拷贝前一半内容&#xff0c;子进程2拷贝后一半内容&#xff0c;父进程回收子进程的资源 #include <stdio.h> #include <string.h> #include <stdlib.h> #include <myhead.h> int …

CCNP课程实验-07-OSPF-Trouble-Shooting

目录 实验条件网络拓朴 环境配置开始排错错点1&#xff1a;R1-R2之间认证不匹配错误2&#xff1a;hello包的时间配置不匹配错误3&#xff1a;R2的e0/1接口区域配置不正确错误4&#xff1a;R4的e0/1接口没有配置进OSPF错误5&#xff1a;R2的区域1没有配置成特殊区域错误6&#x…

ASP.NETCore WebAPI 入门 杨中科

ASP.NETCore WebAPI入门1 回顾 mvc开发模式 前端代码和后端代码是混在一个项目之中 WEB API 1、什么是结构化的Http接口。Json。 2、Web API项目的搭建。 3、Web API项目没有Views文件夹。 4、运行项目&#xff0c;解读代码结构。 5、【启用OpenAPI支持】→>swagger,在界…

Pytorch从零开始实战15

Pytorch从零开始实战——ResNeXt-50算法实战 本系列来源于365天深度学习训练营 原作者K同学 文章目录 Pytorch从零开始实战——ResNeXt-50算法实战环境准备数据集模型选择开始训练可视化总结 环境准备 本文基于Jupyter notebook&#xff0c;使用Python3.8&#xff0c;Pytor…

高效分割视频:批量剪辑,轻松提取m3u8视频技巧

在数字媒体时代&#xff0c;视频分割是一项常见的需求。无论是为了编辑、分享还是其他要求&#xff0c;经常要将长视频分割成多个短片。传统的视频分割方法往往需要手动操作&#xff0c;既耗时又容易出错。现在来看云炫AI智剪高效分割视频的方法&#xff0c;批量剪辑并轻松提取…

nest框架的bull队列的基本使用

前言 nestjs/bull是一个用于处理队列的Nest.js模块。它基于Bull库&#xff0c;提供了在Nest框架中使用队列的功能&#xff0c;这个模块要跟redis联合起来使用 1.下载队列模块&#xff1a; npm install --save nestjs/bull bull redis 项目结构&#xff1a; 2. 在模块中导入B…

佳能G3800彩色喷墨多功能一体打印机报5B00错误代码处理方法

5B00错误代码的含义 5B00错误代码是指佳能G3800打印机的“废墨仓已满”。这个废墨仓是打印机内部的一个部件&#xff0c;主要用于收集打印过程中产生的废墨。当废墨仓已满时&#xff0c;打印机就会报5B00错误代码。 佳能G3800彩色喷墨多功能一体打印机报5B00错误代码处理办法 …

vue3中标签form插件

想写一个系统&#xff0c;对八字进行标注&#xff0c;比如格局&#xff0c;有些八字就有很多格局&#xff0c;于是就想着使用el-tag但是&#xff0c;form表单中如何处理呢&#xff1f; 这个时候&#xff0c;就需要自己写一个,modelValue是表单的默认属性 <template><…

uniCloud 云数据库(新建表、增、删、改、查)

新建表结构描述文件 todo 为自定义的表名 表结构描述文件的默认后缀为 .schema.json 设置表的操作权限 uniCloud-aliyun/database/todo.schema.json 默认的操作权限都是 false "permission": {"read": false,"create": false,"update&quo…