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

本文涉及的产品
云监控,每月短信1000条
简介: 推荐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)
  }
}
相关实践学习
借助OSS搭建在线教育视频课程分享网站
本教程介绍如何基于云服务器ECS和对象存储OSS,搭建一个在线教育视频课程分享网站。
7天玩转云服务器
云服务器ECS(Elastic Compute Service)是一种弹性可伸缩的计算服务,可降低 IT 成本,提升运维效率。本课程手把手带你了解ECS、掌握基本操作、动手实操快照管理、镜像管理等。了解产品详情:&nbsp;https://www.aliyun.com/product/ecs
相关文章
|
9天前
|
分布式计算 大数据 数据挖掘
阿里云服务器计算型c8i、通用型g8i、内存型r8i实例测评与价格参考
阿里云服务器计算型c8i、通用型g8i、内存型r8i实例是阿里云的第八代云服务器实例规格,是除了计算型c7和c8y、通用型g7与g8y、内存型r7与r8y之外同样深受用户喜欢的云服务器实例规格。本文将详细介绍阿里云第八代云服务器中的计算型c8i、通用型g8i、以及内存型r8i实例,包括它们的技术特性、适用场景以及最新的活动价格信息。
阿里云服务器计算型c8i、通用型g8i、内存型r8i实例测评与价格参考
|
24天前
|
编解码 前端开发 安全
通过阿里云的活动购买云服务器时如何选择实例、带宽、云盘
在我们选购阿里云服务器的过程中,不管是新用户还是老用户通常都是通过阿里云的活动去买了,一是价格更加实惠,二是活动中的云服务器配置比较丰富,足可以满足大部分用户的需求,但是面对琳琅满目的云服务器实例、带宽和云盘选项,如何选择更适合自己,成为许多用户比较关注的问题。本文将介绍如何在阿里云的活动中选择合适的云服务器实例、带宽和云盘,以供参考和选择。
通过阿里云的活动购买云服务器时如何选择实例、带宽、云盘
|
22天前
|
弹性计算 运维 安全
阿里云轻量应用服务器和经济型e实例区别及选择参考
目前在阿里云的活动中,轻量应用服务器2核2G3M带宽价格为82元1年,2核2G3M带宽的经济型e实例云服务器价格99元1年,对于云服务器配置和性能要求不是很高的阿里云用户来说,这两款服务器配置和价格都差不多,阿里云轻量应用服务器和ECS云服务器让用户二选一,很多用户不清楚如何选择,本文来说说轻量应用服务器和经济型e实例的区别及选择参考。
阿里云轻量应用服务器和经济型e实例区别及选择参考
|
23天前
|
机器学习/深度学习 存储 人工智能
阿里云GPU云服务器实例规格gn6v、gn7i、gn6i实例性能及区别和选择参考
阿里云的GPU云服务器产品线在深度学习、科学计算、图形渲染等多个领域展现出强大的计算能力和广泛的应用价值。本文将详细介绍阿里云GPU云服务器中的gn6v、gn7i、gn6i三个实例规格族的性能特点、区别及选择参考,帮助用户根据自身需求选择合适的GPU云服务器实例。
阿里云GPU云服务器实例规格gn6v、gn7i、gn6i实例性能及区别和选择参考
|
14天前
|
设计模式 数据库连接 PHP
PHP中的设计模式:如何提高代码的可维护性与扩展性在软件开发领域,PHP 是一种广泛使用的服务器端脚本语言。随着项目规模的扩大和复杂性的增加,保持代码的可维护性和可扩展性变得越来越重要。本文将探讨 PHP 中的设计模式,并通过实例展示如何应用这些模式来提高代码质量。
设计模式是经过验证的解决软件设计问题的方法。它们不是具体的代码,而是一种编码和设计经验的总结。在PHP开发中,合理地使用设计模式可以显著提高代码的可维护性、复用性和扩展性。本文将介绍几种常见的设计模式,包括单例模式、工厂模式和观察者模式,并通过具体的例子展示如何在PHP项目中应用这些模式。
|
8天前
|
Go
Go 语言循环语句
在不少实际问题中有许多具有规律性的重复操作,因此在程序中就需要重复执行某些语句。
17 1
|
7天前
|
Go 开发者
探索Go语言的并发之美
在Go语言的世界里,"并发"不仅仅是一个特性,它是一种哲学。本文将带你领略Go语言中goroutine和channel的魔力,揭示如何通过Go的并发机制来构建高效、可靠的系统。我们将通过一个简单的示例,展示如何利用Go的并发特性来解决实际问题,让你的程序像Go一样,轻盈而强大。
|
8天前
|
JSON Go API
使用Go语言和Gin框架构建RESTful API:GET与POST请求示例
使用Go语言和Gin框架构建RESTful API:GET与POST请求示例
|
8天前
|
Go
go语言创建字典
go语言创建字典
|
9天前
|
安全 Go 数据处理
探索Go语言的并发之美:Goroutines与Channels
在Go语言的世界里,"并发"不仅仅是一个概念,它是一种生活的方式。本文将带你领略Go语言中Goroutines和Channels的魔力,它们是如何让并发编程变得既简单又高效。我们将通过一个简单的示例,展示如何使用这些工具来构建一个高性能的网络服务。
下一篇
无影云桌面