zl程序教程

您现在的位置是:首页 >  工具

当前栏目

【DevOps】推荐Go语言开源项目:Excelize ,获取阿里云ECS实例监控数据导出到自定义Excel表格(三)

2023-09-27 14:25:55 时间

愿你前行的路上终有人陪😄~

安装要求

1、Golang版本 1.15+
2、调用阿里云API权限

目标

利用阿里云现有的云监控服务,生成自定义数据报表。
以七天为周期定时收集数据发送到企业邮箱

目前调用了两种阿里云API

获取监控数据API:查询指定云服务时序指标的监控数据
https://next.api.aliyun.com/api/Cms/2019-01-01/DescribeMetricList?params={}&sdkStyle=old

获取主机信息API:查询所有已安装和未安装云监控插件的主机列表
https://next.api.aliyun.com/api/Cms/2019-01-01/DescribeMonitoringAgentHosts?params={}&sdkStyle=old&tab=DEBUG

目前进度

1、(完成) 已获取所有主机指定时间段内的各种指标(目前该项目以cpu使用率为例)
2、(完成) 已获取所有主机主机名和ip信息
3、(完成) 把接口一获取到的instanceid和接口二获得的instanceid对比,如果相等,把接口二获取的主机名和ip写到该表行的“主机名”与“IP”列
4、(进行中)获取整个周期时间段数据的百分比,例如7天内,在10-12点的cpu使用率

目前效果

在这里插入图片描述

安装说明

设置GOPROXY,创建mod环境

GOPROXY=https://goproxy.cn
go mod tidy

main.go

// This file is auto-generated, don't edit it. Thanks.
package main

import (
	"encoding/json"
	"fmt"
	cms20190101 "github.com/alibabacloud-go/cms-20190101/v2/client"
	openapi "github.com/alibabacloud-go/darabonba-openapi/client"
	"github.com/alibabacloud-go/tea/tea"
	"github.com/aliyun/alibaba-cloud-sdk-go/sdk/requests"
	"github.com/aliyun/alibaba-cloud-sdk-go/services/cms"
	"github.com/xuri/excelize/v2"
	_ "github.com/xuri/excelize/v2"
	"os"
	"strconv"
)

type Monitor_data_struct struct {
	Order      int     `json:"order"`
	Timestamp  int     `json:"timestamp"`
	UserId     string  `json:"userId"`
	InstanceId string  `json:"instanceId"`
	Minimum    float32 `json:"Minimum"`
	Maximum    float32 `json:"Maximum"`
	Average    float32 `json:"Average"`
	Count      float32 `json:"_count"`
}


func CreateClient(accessKeyId *string, accessKeySecret *string) (_result *cms20190101.Client, _err error) {
	config := &openapi.Config{
		// 您的AccessKey ID
		AccessKeyId: accessKeyId,
		// 您的AccessKey Secret
		AccessKeySecret: accessKeySecret,
	}
	// 访问的域名
	config.Endpoint = tea.String("metrics.cn-hangzhou.aliyuncs.com")
	_result = &cms20190101.Client{}
	_result, _err = cms20190101.NewClient(config)
	return _result, _err
}

func _main(args []*string) (_err error) {
	//******调用接口******

	//调用接口一:获取监控数据
	metrics_client, _err := CreateClient(tea.String("LTxxxxxxxxxxxxxp3G"), tea.String("0Tn7xxxxxxxxxxxxxxxxxxRGr6GAr"))
	if _err != nil {
		return _err
	}

	describeMetricListRequest := &cms20190101.DescribeMetricListRequest{
		StartTime:  tea.String("1637769600000"),     //开始时间
		EndTime:    tea.String("1637856000000"),     //结束时间
		MetricName: tea.String("cpu_total"),         //cpu使用率
		Namespace:  tea.String("acs_ecs_dashboard"), //ecs实例
		Dimensions: tea.String(""),                  //全部实例
		Period:     tea.String("604800"),             //周期7天 ,60x60x24x7
	}

	//******获取数据******
	// 获取接口一API数据,输出到Monitor_Data
	Monitor_Data, _err := metrics_client.DescribeMetricList(describeMetricListRequest)
	//输出M的Body。Datapoints段数据到N
	Monitor_Data_Body_Datapoints := *Monitor_Data.Body.Datapoints
	//******序列化******
	//开始序列化接口一,这里可以直接进行反序列化,因为得到的数据格式与序列化后的格式一致
	//创建map类型,把Monitor_Data_Body_Datapoints反序列化成map类型
	var Monitor_data_struct_json_InstanceId_map = make(map[string]string, 200)
	var Ecs_Data_HostnameIp_struct_map_hostname = make(map[string]string, 200)
	var  Ecs_Data_HostnameIp_struct_map_ip =make(map[string]string,200)
	//注意:反序列化map,不需要make,因为make操作被封装到Unmarshal函数
	var Monitor_Data_Body_Datapoints_map []map[string]interface{}
	err := json.Unmarshal([]byte(Monitor_Data_Body_Datapoints), &Monitor_Data_Body_Datapoints_map)
	if err != nil {
		fmt.Printf("unmarshal err=%v\n", err)
	}

	//创建文件,规定表头
	var f = excelize.NewFile()
	var Index = f.NewSheet("主机列表")
	f.SetCellValue("主机列表", "A1", "实例ID号")
	f.SetCellValue("主机列表", "B1", "主机名")
	f.SetCellValue("主机列表", "C1", "IP")
	f.SetCellValue("主机列表", "D1", "CPU最小使用率/周")
	f.SetCellValue("主机列表", "E1", "CPU最大使用率/周")
	f.SetCellValue("主机列表", "F1", "CPU平均使用率/周")
	f.SetColWidth("主机列表", "A", "C", 27)
	f.SetColWidth("主机列表", "D", "F", 18)
    //循环取map中得值,序列化结构体后取值写入到exl表格中
	for i := 0; i < len(Monitor_Data_Body_Datapoints_map); i++ {
		Alist := "A"
		Aline := fmt.Sprint(Alist + strconv.Itoa(i+2))
		Dlist := "D"
		Dline := fmt.Sprint(Dlist + strconv.Itoa(i+2))
		Elist := "E"
		Eline := fmt.Sprint(Elist + strconv.Itoa(i+2))
		Flist := "F"
		Fline := fmt.Sprint(Flist + strconv.Itoa(i+2))
		Arr, err := json.Marshal(Monitor_Data_Body_Datapoints_map[i])
		if err != nil {
			fmt.Println(err)
			return
		}
		var Monitor_data_struct_json Monitor_data_struct
		err = json.Unmarshal(Arr, &Monitor_data_struct_json)
		if err != nil {
			fmt.Println(err)
			return
		}
		//每一个实例ID都不一样
		Monitor_data_struct_json_InstanceId_map[Monitor_data_struct_json.InstanceId] = Monitor_data_struct_json.InstanceId

		f.SetCellValue("主机列表", Aline, Monitor_data_struct_json.InstanceId)
		f.SetCellValue("主机列表", Dline, Monitor_data_struct_json.Minimum)
		f.SetCellValue("主机列表", Eline, Monitor_data_struct_json.Maximum)
		f.SetCellValue("主机列表", Fline, Monitor_data_struct_json.Average)
	}

     // ================================================================================================
	//开始调用第二个接口,定义一些变量
	type Ecs_Data_Hosts_Host_json_map []map[string]interface{}
	type Ecs_Data_Hosts_Host struct {
		Host Ecs_Data_Hosts_Host_json_map
	}
	type Ecs_Data_HostnameIp_struct struct {
		HostName   string `json:"HostName"`
		InstanceId string `json:"InstanceId"`
		IpGroup    string `json:"IpGroup"`
	}
	type Ecs_Data_struct struct {
		Code       string              `json:"Code"`
		Message    string              `json:"Message"`
		Success    bool                `json:"Success"`
		RequestId  string              `json:"RequestId"`
		PageTotal  int                 `json:"PageTotal"`
		Total      int                 `json:"Total"`
		PageSize   int                 `json:"PageSize"`
		PageNumber int                 `json:"PageNumber"`
		Hosts      Ecs_Data_Hosts_Host `json:"Hosts"`
	}

	//调用接口二:获取主机名和IP(上一个接口没有主机名和IP,所以需要拼接下)
	ecs_client, err := cms.NewClientWithAccessKey("cn-zhangjiakou", "LTxxxxxxxxxxxxxxxxxx3G", "0TxxxxxxxxxxxxxxxxxxxAr")
	request := cms.CreateDescribeMonitoringAgentHostsRequest()
	request.Scheme = "https"

	request.AliyunHost = requests.NewBoolean(true) //阿里云云监控服务可以自己添加其他类型主机,这里等于true代表只处理阿里云ecs主机,等于false处理不是阿里云ecs的主机
	//获取接口二API数据,输出到Ecs_Data
	Ecs_Data, err := ecs_client.DescribeMonitoringAgentHosts(request)
	if err != nil {
		fmt.Print(err.Error())
	}

	//开始序列化
	Ecs_Data_json, err := json.Marshal(Ecs_Data)
	if err != nil {
		fmt.Println(err)
	}
	var Ecs_Data_struct_json Ecs_Data_struct
	err = json.Unmarshal([]byte(Ecs_Data_json), &Ecs_Data_struct_json)
	if err != nil {
		fmt.Println(err)
	}
	//循环
	for i:=0; i < len(Ecs_Data_struct_json.Hosts.Host);i++ {
		Ecs_Data_Hosts_Host_map, err := json.Marshal(Ecs_Data_struct_json.Hosts.Host[i])
		if err != nil {
			fmt.Println(err)
		}
		//fmt.Println("结构体序列化",string(Ecs_Data_Hosts_Host_map))
		var Ecs_Data_HostnameIp_struct Ecs_Data_HostnameIp_struct
		err = json.Unmarshal([]byte(Ecs_Data_Hosts_Host_map), &Ecs_Data_HostnameIp_struct)
		Ecs_Data_HostnameIp_struct_map_hostname[Ecs_Data_HostnameIp_struct.InstanceId] = Ecs_Data_HostnameIp_struct.HostName
		Ecs_Data_HostnameIp_struct_map_ip[Ecs_Data_HostnameIp_struct.InstanceId] = Ecs_Data_HostnameIp_struct.IpGroup
	}


	//==================================================================================================================
	// 设置工作簿的默认工作表
	f.SetActiveSheet(Index)
	// 根据指定路径保存文件
	if err := f.SaveAs("Book1.xlsx"); err != nil {
		fmt.Println(err)
	}

	for k, v := range Ecs_Data_HostnameIp_struct_map_hostname {
		Monitor_data_struct_json_InstanceId_map[k] = v
	}

	f, err = excelize.OpenFile("Book1.xlsx")
	if err != nil {
		fmt.Println(err)
		return
	}
	for i := 2; i < len(Monitor_Data_Body_Datapoints_map); i++ {
		Alist := "A"
		Aline := fmt.Sprint(Alist + strconv.Itoa(i))
		Blist := "B"
		Bline := fmt.Sprint(Blist + strconv.Itoa(i))
		//获取Book1,xlsx表格指定位置的值
		cell, err := f.GetCellValue("主机列表", Aline)
		if err != nil {
			fmt.Println(err)
			return
		}

		//fmt.Println(cell,Ecs_Data_HostnameIp_struct_map_hostname[cell])
		f.SetCellValue("主机列表", Bline,Monitor_data_struct_json_InstanceId_map[cell])
	}
	// 设置工作簿的默认工作表
	f.SetActiveSheet(Index)
	// 根据指定路径保存文件
	if err := f.SaveAs("Book1.xlsx"); err != nil {
		fmt.Println(err)
	}
	for k, v := range Ecs_Data_HostnameIp_struct_map_ip {
		Monitor_data_struct_json_InstanceId_map[k] = v
	}
	f, err = excelize.OpenFile("Book1.xlsx")
	if err != nil {
		fmt.Println(err)
		return
	}
	for i := 2; i < len(Monitor_Data_Body_Datapoints_map); i++ {
		Alist := "A"
		Aline := fmt.Sprint(Alist + strconv.Itoa(i))
		C1 := "C"
		C2 := fmt.Sprint(C1 + strconv.Itoa(i))
		//获取Book1,xlsx表格指定位置的值
		cell, err := f.GetCellValue("主机列表", Aline)
		if err != nil {
			fmt.Println(err)
			return
		}

		//fmt.Println(cell,Ecs_Data_HostnameIp_struct_map_ip[cell])
		f.SetCellValue("主机列表", C2,Monitor_data_struct_json_InstanceId_map[cell])
	}
	
	//开启表保护,密码:123456
	f.ProtectSheet("主机列表", &excelize.FormatSheetProtection{
		Password:      "123456",
		EditScenarios: false,
	})
	// 设置工作簿的默认工作表
	f.SetActiveSheet(Index)
	// 根据指定路径保存文件
	if err := f.SaveAs("Book1.xlsx"); err != nil {
		fmt.Println(err)
	}

	if _err != nil {
		return _err
	}
	return _err
}



func main() {
	err := _main(tea.StringSlice(os.Args[1:]))
	if err != nil {
		panic(err)
	}
}

调用思路

1、调用阿里云API接口一获得实例ID、CPU使用信息 JSON格式数据

默认得到的数据格式是带请求头的,并且有很多数据不需要
在这里插入图片描述
得到的Monitor_Data值嵌套多个结构体,把需要的数据拿出来,也就是:Monitor_Data_Body_Datapoints := *Monitor_Data.Body.Datapoints

在这里插入图片描述
注意格式:

[{},{}]

这样的格式可以序列化成map类型的切片[]map[string]interface{},序列化后得到的值格式[map[] map[] map[]...],这样的数据其实还是一个切片,我们直接获取元素位置即可得到里面的数据,然后序列化成json格式,最后通过for循环每一个切片的map类型值序列化成结构体,取到其中的值写入到exl表格中。
具体其中一个循环是这样的:
1、得到第0个元素的值

[ map[ ] ]  ---> Monitor_Data_Body_Datapoints_map[0] 

2、把第0个元素得到的值,序列化成json

Arr, err := json.Marshal(Monitor_Data_Body_Datapoints_map[0])

得到格式:

{"Average":0.7308333333333331,"Maximum":50.76,"Minimum":0,"instanceId":"i-8vb1h2roxxxxxxxxxx","timestamp":1637798400000,"userId":"1541654291217958"}

3、反序列化成结构体

var Monitor_data_struct_json Monitor_data_struct
json.Unmarshal(Arr, &Monitor_data_struct_json)

得到格式:

main.Monitor_data_struct{Order:0, Timestamp:1637798400000, UserId:"1541654291217958", InstanceId:"i-8vbdzk5bxz93j4qx4jou", Minimum:0.52, Maximum:88.14, Average:5.8727
083, Count:0}

4、添加数据到Monitor_data_struct_json_InstanceId_map
每一个实例ID都不一样,for循环后,将得到所有实例ID和cpu使用信息,依次写入到Monitor_data_struct_json_InstanceId_map,下面用于遍历第二个接口赋值

5、最后就可以直接获取值写入到exl表格了

f.SetCellValue("主机列表", Aline, Monitor_data_struct_json.InstanceId)

2、调用阿里云API接口二获取实例ID、主机名、IP JSON格式数据

主要就干了一件事:

		Ecs_Data_HostnameIp_struct_map_hostname[Ecs_Data_HostnameIp_struct.InstanceId] = Ecs_Data_HostnameIp_struct.HostName
		Ecs_Data_HostnameIp_struct_map_ip[Ecs_Data_HostnameIp_struct.InstanceId] = Ecs_Data_HostnameIp_struct.IpGroup

for循环得到所有map数据,写入到Ecs_Data_HostnameIp_struct_map_hostnameEcs_Data_HostnameIp_struct_map_ip
这样就得到了所有主机的hostnmae和IP,都带有实例ID,下面会通过实例ID为媒介,把hostname和IP与实例ID一一对应,写入到exl表格中

3、遍历主机名的map和IP的map,通过共有实例ID一一对应,写入到exl表格

1、通过for循环,得到Book1.xlsx表格指定位置的值,这里是获取了每一个A列的值,就赋值到C列指定位置