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

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

需求


用阿里云云监控服务:

阿里云云监控没有grafana服务端,生成不了PDF,再加上Prometheus不能生成exl表格数据,阿里云云监控企业版太贵,一个报表0.14元。我们可以自己调取阿里云的api接口,获取ECS主机cpu负载、内存使用率等信息,生成报表定时发送指定邮箱。


有人会说了,为啥不自己搭建一个Prometheus服务端,然后把所有主机全部添加到自己的服务器上。这个想法好,但是如果“二次开发”阿里云 云监控平台,我们公司就不用单独购买服务器,毕竟人家做的也不错,除了有些功能收费以外。其实自己搭建Prometheus服务端我们已经实现了,目前可以做到监控数据生成PDF格式定时发送,动态添加主机(自动增删被监控主机,还未整理,主要是懒🌚),只不过想节省资源,也能为公司每个月省下好几百。


目前进度


1、(完成) 已获取所有主机指定时间段内的各种指标(目前该项目以cpu使用率为例)

2、(进行中) 已获取所有主机主机名和ip信息

3、(未开始) 把接口一获取到的instanceid和接口二获得的instanceid对比,如果相等,把接口二获取的主机名和ip写到该表行的“主机名”与“IP”列

4、(未开始)获取整个周期时间段数据的百分比,例如7天内,在10-12点的cpu使用率


效果一:获取单台主机资源信息


获取一个主机的7天内的cpu使用率信息,生成报表

1675242552355.jpg


阿里云API


阿里云 云监控服务API地址:https://next.api.aliyun.com/home

本篇使用的API网址:https://next.api.aliyun.com/api/Cms/2019-01-01/DescribeMetricTop?params={}


代码示例


// This file is auto-generated, don't edit it. Thanks.
package main
import (
  "encoding/json"
  "fmt"
  "github.com/xuri/excelize/v2"
  "os"
  cms20190101  "github.com/alibabacloud-go/cms-20190101/v2/client"
  openapi  "github.com/alibabacloud-go/darabonba-openapi/client"
  "github.com/alibabacloud-go/tea/tea"
  "strings"
)
type List 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"`
}
/**
 * 使用AK&SK初始化账号Client
 * @param accessKeyId
 * @param accessKeySecret
 * @return Client
 * @throws Exception
 */
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) {
  client, _err := CreateClient(tea.String("LTxxxxxxxxx5dUc"), tea.String("G1WxxxxxxxxxxxxxxxxxxiF6"))
  if _err != nil {
    return _err
  }
  describeMetricListRequest := &cms20190101.DescribeMetricListRequest{
    StartTime: tea.String("1636905600000"),
    EndTime: tea.String("1637424000000"),
    MetricName: tea.String("cpu_total"),
    Namespace: tea.String("acs_ecs_dashboard"),
    Dimensions: tea.String("{\"instanceId\":\"i-8vxxxxxxxxgh\"}"),
    Period: tea.String("604800"),
  }
  // 复制代码运行请自行打印 API 的返回值
  M, _err := client.DescribeMetricList(describeMetricListRequest)
  N := *M.Body.Datapoints
  fmt.Println(N)
  N1 := strings.TrimLeft(N, "[")
  N2 := strings.TrimRight(N1, "]")
  //fmt.Printf("N类型:%T,N值:%v\n",N2,N2)
  fmt.Println(N2)
  var list List
  err1 := json.Unmarshal([]byte(N2), &list)
  if err1 != nil {
    fmt.Printf("序列化转化失败,%v",err1)
  }else {
    fmt.Println("序列化转化成功")
  }
  fmt.Println(list)
  f := excelize.NewFile()
  // 创建一个工作表
  index := f.NewSheet("主机列表")
  err2 := f.SetColWidth("主机列表", "A", "H", 23)
  if err2 != nil {
    fmt.Printf("表格创建失败,%v",err2)
  }else {
    fmt.Println("表格创建成功")
  }
  // 设置单元格的值
  f.SetCellValue("主机列表", "A1", "实例ID号")
  f.SetCellValue("主机列表", "A2", list.InstanceId)
  f.SetCellValue("主机列表","B1","7天CPU最小使用率")
  f.SetCellValue("主机列表","B2",list.Minimum)
  f.SetCellValue("主机列表","C1","7天CPU最大使用率")
  f.SetCellValue("主机列表","C2",list.Maximum)
  f.SetCellValue("主机列表","D1","7天CPU平均使用率")
  f.SetCellValue("主机列表","D2",list.Average)
  // 设置工作簿的默认工作表
  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)
  }
}


效果二:获取所有主机资源信息


1675242589646.jpg


阿里云API


https://next.api.aliyun.com/api/Cms/2019-01-01/DescribeMetricList?params={}

https://next.api.aliyun.com/api/Cms/2019-01-01/DescribeMetricLast?params={}


说实话,不知道这两个有什么区别。都可以用,而且两个获得数据不准,乱七八糟!先讲究用吧


代码实例


获取所有主机监控数据

// 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/xuri/excelize/v2"
  _ "github.com/xuri/excelize/v2"
  "os"
  "strconv"
)
type List 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"`
}
/**
 * 使用AK&SK初始化账号Client
 * @param accessKeyId
 * @param accessKeySecret
 * @return Client
 * @throws Exception
 */
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) {
  client, _err := CreateClient(tea.String("LTAIxxxxxxxxxxx"), tea.String("G1WBNxxxxxxxxxxxxxxxxxxxxxx"))
  if _err != nil {
    return _err
  }
  describeMetricListRequest := &cms20190101.DescribeMetricListRequest{
    StartTime:  tea.String("1636905600000"),
    EndTime:    tea.String("1637424000000"),
    MetricName: tea.String("cpu_total"),
    Namespace:  tea.String("acs_ecs_dashboard"),
    Dimensions: tea.String(""),
    Period:     tea.String("604800"),
  }
  // 复制代码运行请自行打印 API 的返回值
  M, _err := client.DescribeMetricList(describeMetricListRequest)
  N := *M.Body.Datapoints
  //fmt.Println("N值\n", N)
  var slice []map[string]interface{}
  //注意:反序列化map,不需要make,因为make操作被封装到Unmarshal函数
  err := json.Unmarshal([]byte(N), &slice)
  if err != nil {
    fmt.Printf("unmarshal err=%v\n", err)
  }
  f := excelize.NewFile()
  index := f.NewSheet("主机列表")
  f.SetCellValue("主机列表", "A1", "实例ID号")
  f.SetCellValue("主机列表", "B1", "7天内的CPU最大使用率")
  f.SetCellValue("主机列表", "C1", "7天内的CPU最小使用率")
  f.SetCellValue("主机列表", "D1", "7天内的CPU平均使用率")
  f.SetColWidth("主机列表", "A", "H", 23)
/*  fmt.Printf("反序列化后:%v\n", slice)
  fmt.Println("第一个切片是:", slice[0])
  fmt.Println("第二个切片是:", slice[1])
  //获取第一个主机信息
  Arr, err := json.Marshal(slice[0])
  if err != nil {
    fmt.Println(err)
    return
  }
  var List1 List
  err = json.Unmarshal(Arr, &List1)
  if err != nil {
    fmt.Println(err)
    return
  }
  fmt.Println(List1)
  f.SetCellValue("主机列表", "A2", List1.InstanceId)
  f.SetCellValue("主机列表", "B2", List1.Maximum)
  f.SetCellValue("主机列表", "C2", List1.Minimum)
  f.SetCellValue("主机列表", "D2", List1.Average)
    //获取第二个主机信息
  Arr1, err := json.Marshal(slice[1])
  if err != nil {
    fmt.Println(err)
    return
  }
  var List2 List
  err = json.Unmarshal(Arr1, &List2)
  if err != nil {
    fmt.Println(err)
    return
  }
  fmt.Println(List2)
  f.SetCellValue("主机列表", "A3", List2.InstanceId)
  f.SetCellValue("主机列表", "B3", List2.Maximum)
  f.SetCellValue("主机列表", "C3", List2.Minimum)
  f.SetCellValue("主机列表", "D3", List2.Average)
*/
//把上面单个获取主机方式改成for循环
  for  i :=2 ;i < len(slice); i++ {
    A1 :="A"
    //strconv.Itoa函数 可以将int类型转string类型
    A2 := fmt.Sprint(A1 + strconv.Itoa(i))
    B1 :="B"
    B2 := fmt.Sprint(B1 + strconv.Itoa(i))
    C1 :="C"
    C2 := fmt.Sprint(C1 + strconv.Itoa(i))
    D1 :="D"
    D2 := fmt.Sprint(D1 + strconv.Itoa(i))
    Arr, err := json.Marshal(slice[i-2])
    if err != nil {
      fmt.Println(err)
      return
    }
    var List1 List
    err = json.Unmarshal(Arr, &List1)
    if err != nil {
      fmt.Println(err)
      return
    }
    //fmt.Println(List1)
    f.SetCellValue("主机列表", A2, List1.InstanceId)
    f.SetCellValue("主机列表", B2, List1.Maximum)
    f.SetCellValue("主机列表", C2, List1.Minimum)
    f.SetCellValue("主机列表", D2, List1.Average)
  }
  // 设置工作簿的默认工作表
  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)
  }
}
相关实践学习
通义万相文本绘图与人像美化
本解决方案展示了如何利用自研的通义万相AIGC技术在Web服务中实现先进的图像生成。
7天玩转云服务器
云服务器ECS(Elastic Compute Service)是一种弹性可伸缩的计算服务,可降低 IT 成本,提升运维效率。本课程手把手带你了解ECS、掌握基本操作、动手实操快照管理、镜像管理等。了解产品详情:&nbsp;https://www.aliyun.com/product/ecs
相关文章
|
3月前
|
存储 弹性计算 安全
阿里云渠道商:新手如何选择阿里云ECS实例?
阿里云ECS凭借弹性扩展、稳定可靠与安全防护,助力企业高效上云。本文系统解析实例规格选择关键因素:业务场景匹配、性能评估、成本优化、地域部署与扩展规划,结合计费模式与实际需求,提供科学选型建议,助您精准匹配资源,提升云上效能。(238字)
|
3月前
|
弹性计算 人工智能 前端开发
在阿里云ECS上部署n8n自动化工作流:U2实例实战
本文介绍如何在阿里云ECS的u2i/u2a实例上部署开源工作流自动化平台n8n,利用Docker快速搭建并配置定时任务,实现如每日抓取MuleRun新AI Agent并推送通知等自动化流程。内容涵盖环境准备、安全组设置、实战案例与优化建议,助力高效构建低维护成本的自动化系统。
924 5
|
3月前
|
存储 安全 Java
【Golang】(4)Go里面的指针如何?函数与方法怎么不一样?带你了解Go不同于其他高级语言的语法
结构体可以存储一组不同类型的数据,是一种符合类型。Go抛弃了类与继承,同时也抛弃了构造方法,刻意弱化了面向对象的功能,Go并非是一个传统OOP的语言,但是Go依旧有着OOP的影子,通过结构体和方法也可以模拟出一个类。
259 1
|
5月前
|
Cloud Native 安全 Java
Go:为云原生而生的高效语言
Go:为云原生而生的高效语言
354 1
|
5月前
|
Cloud Native Go API
Go:为云原生而生的高效语言
Go:为云原生而生的高效语言
443 0
|
5月前
|
Cloud Native Java Go
Go:为云原生而生的高效语言
Go:为云原生而生的高效语言
299 0
|
5月前
|
Cloud Native Java 中间件
Go:为云原生而生的高效语言
Go:为云原生而生的高效语言
298 0

热门文章

最新文章