推荐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)
  }
}
相关实践学习
使用操作系统智能助手OS Copilot解锁操作系统运维与编程
在本实验场景中,将在阿里云ECS上体验OS Copilot产品。OS Copilot是阿里云操作系统团队基于大模型构建的OS智能助手。它具有自然语言问答、辅助命令执行、系统运维调优等功能,帮助用户更好地使用Linux,提升阿里云的使用体验。
7天玩转云服务器
云服务器ECS(Elastic Compute Service)是一种弹性可伸缩的计算服务,可降低 IT 成本,提升运维效率。本课程手把手带你了解ECS、掌握基本操作、动手实操快照管理、镜像管理等。了解产品详情:&nbsp;https://www.aliyun.com/product/ecs
相关文章
|
8月前
|
存储 安全 数据管理
服务器违规资源被删,数据定时备份OSS 云存储才是 “救命稻草”
在数字化时代,数据已成为企业与个人的核心资产。然而,服务器违规、硬件故障等问题频发,导致数据丢失、业务中断,甚至造成不可挽回的损失。为保障数据安全与业务连续性,定时备份至关重要。阿里云国际站OSS提供高效、可靠的云存储解决方案,支持自动定时备份,帮助用户轻松应对数据风险。本文详解OSS备份操作步骤与注意事项,助你为数据穿上“防护甲”,实现安全无忧存储。
|
9月前
|
网络协议 关系型数据库 应用服务中间件
如何迁移网站数据到新的服务器
迁移网站数据到新服务器是一个系统化的过程,需谨慎操作以避免数据丢失或服务中断。小编为您整理发布如何迁移网站数据到新的服务器,以下是详细步骤和注意事项。
|
9月前
|
监控 Java 编译器
限流、控并发、减GC!一文搞懂Go项目资源优化的正确姿势
本章介绍Go语言项目在构建与部署阶段的性能调优和资源控制策略,涵盖编译优化、程序性能提升、并发与系统资源管理、容器化部署及自动化测试等内容,助力开发者打造高效稳定的生产级应用。
|
9月前
|
测试技术 Go 开发工具
Go语言项目工程化 — 常见开发工具与 CI/CD 支持
Go语言项目工程化实践中的开发工具与CI/CD支持,涵盖格式化、静态检查、依赖管理、构建打包、自动化测试及部署策略。内容包括常用工具如gofmt、go vet、golangci-lint、Docker、GitHub Actions等,并提供实战建议与总结,提升团队协作效率与项目质量。
|
9月前
|
JSON 安全 Go
Go语言项目工程化 —— 日志、配置、错误处理规范
本章详解Go语言项目工程化核心规范,涵盖日志、配置与错误处理三大关键领域。在日志方面,强调其在问题排查、性能优化和安全审计中的作用,推荐使用高性能结构化日志库zap,并介绍日志级别与结构化输出的最佳实践。配置管理部分讨论了配置分离的必要性,对比多种配置格式如JSON、YAML及环境变量,并提供viper库实现多环境配置的示例。错误处理部分阐述Go语言显式返回error的设计哲学,讲解标准处理方式、自定义错误类型、错误封装与堆栈追踪技巧,并提出按调用层级进行错误处理的建议。最后,总结各模块的工程化最佳实践,助力构建可维护、可观测且健壮的Go应用。
|
9月前
|
NoSQL 中间件 Go
Go语言项目工程化 — 项目结构与模块划分
本章讲解Go语言项目工程化中的结构设计与模块划分,涵盖单体及分层架构方案,指导如何按功能组织代码,提升项目的可维护性、扩展性,适用于不同规模的开发场景。
|
10月前
|
弹性计算 安全
阿里云服务器镜像,快速迁移项目数据
有时候旧服务器快到期了,想把项目、数据、软件挪到新服务器上,如果全部重新搭建的话,那无疑是耗时又费力。有了镜像迁移,就方便了许多。
725 1
|
11月前
|
弹性计算 NoSQL 数据库
阿里云服务器如何备份数据?
阿里云服务器数据备份有多种方法,用户可按需选择。主要方式包括:1)快照备份,创建云盘的时间点拷贝,支持定期备份与数据恢复;2)数据库备份DBS,适用于多种环境的数据库备份,涵盖本地及多云场景;3)云备份Cloud Backup,提供统一灾备平台,支持ECS整机、数据库、文件系统等全方位备份,保障数据安全。
|
11月前
|
存储 数据库 Python
使用HTTP POST协议将本地压缩数据发送到服务器
总的来说,使用HTTP POST协议将本地压缩数据发送到服务器是一个涉及多个步骤的过程,包括创建压缩文件,设置HTTP客户端,发送POST请求,以及服务器端的处理。虽然这个过程可能看起来复杂,但一旦你理解了每个步骤,就会变得相对简单。
389 19
|
12月前
|
缓存 人工智能 架构师
释放数据潜力:利用 MCP 资源让大模型读懂你的服务器
MCP(Model Control Protocol)资源系统是将服务器数据暴露给客户端的核心机制,支持文本和二进制两种类型资源。资源通过唯一URI标识,客户端可通过资源列表或模板发现资源,并使用`resources/read`接口读取内容。MCP还支持资源实时更新通知及订阅机制,确保动态数据的及时性。实现时需遵循最佳实践,如清晰命名、设置MIME类型和缓存策略,同时注重安全性,包括访问控制、路径清理和速率限制等。提供的示例代码展示了如何用JavaScript和Python实现资源支持。
1133 80