golang监控内存交换区和CPU统计信息并通过UDP发送的插件库stats的使用
Golang监控内存交换区和CPU统计信息并通过UDP发送的插件库stats的使用
包简介
stats包允许收集关于Go应用程序及其运行系统的统计信息,并通过UDP将这些统计信息发送到服务器,您可以在服务器上对这些统计信息进行各种处理:显示、存储到数据库或发送到日志服务。
当前收集的Go相关信息
- 垃圾回收次数
- 最后一次垃圾回收
- 最后一次垃圾回收暂停时间
- 已分配内存
- 堆内存分配
- 堆系统内存分配
- Go版本
- Goroutine数量
- HTTP请求日志(通过中间件实现时)
当前收集的系统信息
- 主机信息(主机名、操作系统等)
- CPU信息(类型、型号、核心数等)
- 总CPU时间
- 每核心CPU时间
- 内存和交换区信息
安装
使用go get安装:
go get gopkg.in/go-playground/stats.v1
或更新:
go get -u gopkg.in/go-playground/stats.v1
然后在代码中导入:
import "gopkg.in/go-playground/stats.v1"
示例代码
服务器端示例
package main
import (
"fmt"
"gopkg.in/go-playground/stats.v1"
)
func main() {
config := &stats.ServerConfig{
Domain: "",
Port: 3008,
Debug: false,
}
server, err := stats.NewServer(config)
if err != nil {
panic(err)
}
for stat := range server.Run() {
// 计算CPU时间
// totalCPUTimes := stat.CalculateTotalCPUTimes()
// perCoreCPUTimes := stat.CalculateCPUTimes()
// 对数据进行任意处理
// * 保存到数据库
// * 流式传输到其他地方
// * 打印到控制台
fmt.Println(stat)
}
}
客户端示例
package main
import (
"fmt"
"net/http"
"runtime"
"gopkg.in/go-playground/stats.v1"
)
var statsClient *stats.ClientStats
func main() {
serverConfig := &stats.ServerConfig{
Domain: "remoteserver",
Port: 3008,
Debug: false,
}
clientConfig := &stats.ClientConfig{
Domain: "",
Port: 3009,
PollInterval: 1000,
Debug: false,
LogHostInfo: true,
LogCPUInfo: true,
LogTotalCPUTimes: true,
LogPerCPUTimes: true,
LogMemory: true,
LogGoMemory: true,
}
client, err := stats.NewClient(clientConfig, serverConfig)
if err != nil {
panic(err)
}
go client.Run()
// 如果想在中间件中捕获HTTP请求
// 需要访问客户端
statsClient = client
}
// LoggingRecoveryHandler ...
//
// 捕获HTTP请求信息的中间件示例
// 注意:这是标准的Go中间件,但可以轻松适应其他类型/风格
func LoggingRecoveryHandler(next http.Handler) http.Handler {
fn := func(w http.ResponseWriter, r *http.Request) {
// 记录传入请求
logReq := statsClient.NewHTTPRequest(w, r)
defer func() {
if err := recover(); err != nil {
trace := make([]byte, 1<<16)
n := runtime.Stack(trace, true)
// 记录失败
logReq.Failure(fmt.Sprintf("%s\n%s", err, trace[:n]))
http.Error(w, "Friendly error message", 500)
return
}
}()
next.ServeHTTP(logReq.Writer(), r)
// 记录完成
logReq.Complete()
}
return http.HandlerFunc(fn)
}
许可证
- MIT License, Copyright © 2015 Dean Karn
- BSD License
- Copyright © 2014, WAKAYAMA Shirou
- Copyright © 2009 The Go Authors. All rights reserved.
- BSD License, Copyright © 2010-2012 The w32 Authors. All rights reserved.
更多关于golang监控内存交换区和CPU统计信息并通过UDP发送的插件库stats的使用的实战教程也可以访问 https://www.itying.com/category-94-b0.html
1 回复
更多关于golang监控内存交换区和CPU统计信息并通过UDP发送的插件库stats的使用的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html
Golang 监控内存、交换区和CPU统计信息并通过UDP发送的插件库
下面我将介绍如何使用Golang编写一个监控系统统计信息并通过UDP发送的插件库。这个库将监控内存使用情况、交换区使用情况和CPU统计信息。
核心代码实现
首先,我们创建一个名为stats
的包,包含以下功能:
package stats
import (
"encoding/json"
"fmt"
"net"
"os"
"runtime"
"time"
)
// Stats 包含系统统计信息
type Stats struct {
Timestamp int64 `json:"timestamp"`
Hostname string `json:"hostname"`
MemoryUsed uint64 `json:"memory_used"` // 已用内存(字节)
MemoryTotal uint64 `json:"memory_total"` // 总内存(字节)
SwapUsed uint64 `json:"swap_used"` // 已用交换区(字节)
SwapTotal uint64 `json:"swap_total"` // 总交换区(字节)
CPUUser float64 `json:"cpu_user"` // 用户态CPU使用率
CPUSystem float64 `json:"cpu_system"` // 内核态CPU使用率
CPUIdle float64 `json:"cpu_idle"` // CPU空闲率
NumGoroutine int `json:"num_goroutine"` // Goroutine数量
}
// Collector 统计收集器
type Collector struct {
udpAddr *net.UDPAddr
conn *net.UDPConn
}
// NewCollector 创建新的收集器
func NewCollector(udpServer string) (*Collector, error) {
addr, err := net.ResolveUDPAddr("udp", udpServer)
if err != nil {
return nil, fmt.Errorf("failed to resolve UDP address: %v", err)
}
conn, err := net.DialUDP("udp", nil, addr)
if err != nil {
return nil, fmt.Errorf("failed to dial UDP: %v", err)
}
return &Collector{
udpAddr: addr,
conn: conn,
}, nil
}
// Close 关闭UDP连接
func (c *Collector) Close() error {
if c.conn != nil {
return c.conn.Close()
}
return nil
}
// Collect 收集系统统计信息
func (c *Collector) Collect() (*Stats, error) {
hostname, err := os.Hostname()
if err != nil {
return nil, fmt.Errorf("failed to get hostname: %v", err)
}
// 获取内存信息
memStats := &runtime.MemStats{}
runtime.ReadMemStats(memStats)
// 获取CPU使用率
cpuUser, cpuSystem, cpuIdle := getCPUUsage()
stats := &Stats{
Timestamp: time.Now().Unix(),
Hostname: hostname,
MemoryUsed: memStats.Alloc,
MemoryTotal: memStats.Sys,
NumGoroutine: runtime.NumGoroutine(),
CPUUser: cpuUser,
CPUSystem: cpuSystem,
CPUIdle: cpuIdle,
}
// 获取交换区信息(仅Linux)
if swapUsed, swapTotal, err := getSwapUsage(); err == nil {
stats.SwapUsed = swapUsed
stats.SwapTotal = swapTotal
}
return stats, nil
}
// Send 发送统计信息到UDP服务器
func (c *Collector) Send(stats *Stats) error {
data, err := json.Marshal(stats)
if err != nil {
return fmt.Errorf("failed to marshal stats: %v", err)
}
_, err = c.conn.Write(data)
if err != nil {
return fmt.Errorf("failed to send UDP packet: %v", err)
}
return nil
}
// 以下为平台特定实现,这里简化为示例
func getCPUUsage() (float64, float64, float64) {
// 实际实现中应该读取/proc/stat(Linux)或调用系统API
// 这里返回示例值
return 20.5, 10.2, 69.3
}
func getSwapUsage() (uint64, uint64, error) {
// 实际实现中应该读取/proc/meminfo(Linux)或调用系统API
// 这里返回示例值
return 1024 * 1024 * 500, 1024 * 1024 * 2000, nil
}
使用示例
下面是如何使用这个stats库的示例:
package main
import (
"log"
"time"
"./stats" // 替换为你的stats包路径
)
func main() {
// 创建收集器,连接到UDP服务器
collector, err := stats.NewCollector("127.0.0.1:8125")
if err != nil {
log.Fatalf("Failed to create collector: %v", err)
}
defer collector.Close()
// 定时收集和发送统计信息
ticker := time.NewTicker(5 * time.Second)
defer ticker.Stop()
for range ticker.C {
// 收集统计信息
stats, err := collector.Collect()
if err != nil {
log.Printf("Failed to collect stats: %v", err)
continue
}
// 发送统计信息
if err := collector.Send(stats); err != nil {
log.Printf("Failed to send stats: %v", err)
continue
}
log.Printf("Stats sent successfully: %+v", stats)
}
}
功能扩展建议
- 平台兼容性:添加对不同操作系统(Linux, Windows, macOS)的支持
- 性能优化:使用连接池或批量发送减少UDP包数量
- 错误处理:添加重试机制和错误恢复
- 配置支持:从配置文件读取UDP服务器地址和采集间隔
- 数据压缩:对大体积数据使用压缩算法
- 安全传输:添加简单的加密或认证机制
注意事项
- UDP是不可靠协议,如果需要可靠传输,可以考虑TCP或添加确认机制
- 频繁采集可能会影响系统性能,需要合理设置采集间隔
- 跨平台实现需要考虑不同操作系统的API差异
- 生产环境应考虑添加日志记录和监控功能
这个实现提供了基本框架,你可以根据实际需求进行扩展和完善。