Files
pika/internal/migrate/v0_0_13/migrate.go
T
2026-08-12 18:59:29 +08:00

804 lines
25 KiB
Go

package models
import (
"context"
"fmt"
"log"
"github.com/pika-monitor/pika/internal/protocol"
"github.com/pika-monitor/pika/internal/vmclient"
"gorm.io/gorm"
)
const (
// 每批处理的数据量
batchSize = 1000
)
// Migrate 执行数据迁移:将 PostgreSQL 中的历史指标数据迁移到 VictoriaMetrics
func Migrate(db *gorm.DB, client *vmclient.VMClient) error {
ctx := context.Background()
log.Println("开始迁移历史指标数据到 VictoriaMetrics...")
// 迁移各类型的指标数据
migrationTasks := []struct {
name string
tableName string
migrateFunc func(context.Context, *gorm.DB, *vmclient.VMClient) error
}{
{"CPU指标", "cpu_metrics", migrateCPUMetrics},
{"内存指标", "memory_metrics", migrateMemoryMetrics},
{"磁盘指标", "disk_metrics", migrateDiskMetrics},
{"网络指标", "network_metrics", migrateNetworkMetrics},
{"网络连接指标", "network_connection_metrics", migrateNetworkConnectionMetrics},
{"磁盘IO指标", "disk_io_metrics", migrateDiskIOMetrics},
{"GPU指标", "gpu_metrics", migrateGPUMetrics},
{"温度指标", "temperature_metrics", migrateTemperatureMetrics},
{"监控指标", "monitor_metrics", migrateMonitorMetrics},
}
var errors []string
for _, task := range migrationTasks {
log.Printf("开始迁移 %s...", task.name)
if err := task.migrateFunc(ctx, db, client); err != nil {
errMsg := fmt.Sprintf("迁移 %s 失败: %v", task.name, err)
log.Println(errMsg)
errors = append(errors, errMsg)
continue // 继续迁移其他类型的数据
}
log.Printf("✓ %s 迁移完成", task.name)
}
if len(errors) > 0 {
log.Printf("迁移过程中遇到 %d 个错误,但已尽可能完成迁移", len(errors))
return fmt.Errorf("迁移过程中遇到 %d 个错误", len(errors))
}
log.Println("✓ 数据迁移完成!")
return nil
}
// migrateCPUMetrics 迁移CPU指标
func migrateCPUMetrics(ctx context.Context, db *gorm.DB, client *vmclient.VMClient) error {
var totalCount int64
if err := db.Model(&CPUMetric{}).Count(&totalCount).Error; err != nil {
return err
}
if totalCount == 0 {
log.Println(" 没有CPU数据需要迁移")
return nil
}
log.Printf(" 找到 %d 条CPU记录", totalCount)
offset := 0
migratedCount := 0
for {
var metrics []CPUMetric
if err := db.Offset(offset).Limit(batchSize).Order("timestamp ASC").Find(&metrics).Error; err != nil {
return err
}
if len(metrics) == 0 {
break
}
var vmMetrics []vmclient.Metric
for _, m := range metrics {
cpuData := &protocol.CPUData{
UsagePercent: m.UsagePercent,
LogicalCores: m.LogicalCores,
PhysicalCores: m.PhysicalCores,
ModelName: m.ModelName,
}
converted := convertToMetrics(m.AgentID, string(protocol.MetricTypeCPU), cpuData, m.Timestamp)
vmMetrics = append(vmMetrics, converted...)
}
// 批量写入 VictoriaMetrics
if err := client.Write(ctx, vmMetrics); err != nil {
log.Printf(" 警告: 写入CPU数据失败 (offset=%d): %v", offset, err)
}
migratedCount += len(metrics)
offset += batchSize
// 打印进度
if migratedCount%10000 == 0 || migratedCount == int(totalCount) {
log.Printf(" 进度: %d/%d (%.1f%%)", migratedCount, totalCount, float64(migratedCount)/float64(totalCount)*100)
}
}
return nil
}
// migrateMemoryMetrics 迁移内存指标
func migrateMemoryMetrics(ctx context.Context, db *gorm.DB, client *vmclient.VMClient) error {
var totalCount int64
if err := db.Model(&MemoryMetric{}).Count(&totalCount).Error; err != nil {
return err
}
if totalCount == 0 {
log.Println(" 没有内存数据需要迁移")
return nil
}
log.Printf(" 找到 %d 条内存记录", totalCount)
offset := 0
migratedCount := 0
for {
var metrics []MemoryMetric
if err := db.Offset(offset).Limit(batchSize).Order("timestamp ASC").Find(&metrics).Error; err != nil {
return err
}
if len(metrics) == 0 {
break
}
var vmMetrics []vmclient.Metric
for _, m := range metrics {
memData := &protocol.MemoryData{
Total: m.Total,
Used: m.Used,
Free: m.Free,
Available: m.Available,
UsagePercent: m.UsagePercent,
SwapTotal: m.SwapTotal,
SwapUsed: m.SwapUsed,
SwapFree: m.SwapFree,
}
converted := convertToMetrics(m.AgentID, string(protocol.MetricTypeMemory), memData, m.Timestamp)
vmMetrics = append(vmMetrics, converted...)
}
if err := client.Write(ctx, vmMetrics); err != nil {
log.Printf(" 警告: 写入内存数据失败 (offset=%d): %v", offset, err)
}
migratedCount += len(metrics)
offset += batchSize
if migratedCount%10000 == 0 || migratedCount == int(totalCount) {
log.Printf(" 进度: %d/%d (%.1f%%)", migratedCount, totalCount, float64(migratedCount)/float64(totalCount)*100)
}
}
return nil
}
// migrateDiskMetrics 迁移磁盘指标
func migrateDiskMetrics(ctx context.Context, db *gorm.DB, client *vmclient.VMClient) error {
var totalCount int64
if err := db.Model(&DiskMetric{}).Count(&totalCount).Error; err != nil {
return err
}
if totalCount == 0 {
log.Println(" 没有磁盘数据需要迁移")
return nil
}
log.Printf(" 找到 %d 条磁盘记录", totalCount)
offset := 0
migratedCount := 0
for {
var metrics []DiskMetric
if err := db.Offset(offset).Limit(batchSize).Order("timestamp ASC").Find(&metrics).Error; err != nil {
return err
}
if len(metrics) == 0 {
break
}
// 按 agent_id + timestamp 分组
groupedMetrics := make(map[string][]protocol.DiskData)
for _, m := range metrics {
key := fmt.Sprintf("%s_%d", m.AgentID, m.Timestamp)
groupedMetrics[key] = append(groupedMetrics[key], protocol.DiskData{
MountPoint: m.MountPoint,
Total: m.Total,
Used: m.Used,
Free: m.Free,
UsagePercent: m.UsagePercent,
})
}
var vmMetrics []vmclient.Metric
for key, diskDataList := range groupedMetrics {
// 从 key 中提取 agentID 和 timestamp
var agentID string
var timestamp int64
fmt.Sscanf(key, "%s_%d", &agentID, &timestamp)
converted := convertToMetrics(agentID, string(protocol.MetricTypeDisk), diskDataList, timestamp)
vmMetrics = append(vmMetrics, converted...)
}
if err := client.Write(ctx, vmMetrics); err != nil {
log.Printf(" 警告: 写入磁盘数据失败 (offset=%d): %v", offset, err)
}
migratedCount += len(metrics)
offset += batchSize
if migratedCount%10000 == 0 || migratedCount == int(totalCount) {
log.Printf(" 进度: %d/%d (%.1f%%)", migratedCount, totalCount, float64(migratedCount)/float64(totalCount)*100)
}
}
return nil
}
// migrateNetworkMetrics 迁移网络指标
func migrateNetworkMetrics(ctx context.Context, db *gorm.DB, client *vmclient.VMClient) error {
var totalCount int64
if err := db.Model(&NetworkMetric{}).Count(&totalCount).Error; err != nil {
return err
}
if totalCount == 0 {
log.Println(" 没有网络数据需要迁移")
return nil
}
log.Printf(" 找到 %d 条网络记录", totalCount)
offset := 0
migratedCount := 0
for {
var metrics []NetworkMetric
if err := db.Offset(offset).Limit(batchSize).Order("timestamp ASC").Find(&metrics).Error; err != nil {
return err
}
if len(metrics) == 0 {
break
}
// 按 agent_id + timestamp 分组
groupedMetrics := make(map[string][]protocol.NetworkData)
for _, m := range metrics {
key := fmt.Sprintf("%s_%d", m.AgentID, m.Timestamp)
groupedMetrics[key] = append(groupedMetrics[key], protocol.NetworkData{
Interface: m.Interface,
BytesSentRate: m.BytesSentRate,
BytesRecvRate: m.BytesRecvRate,
BytesSentTotal: m.BytesSentTotal,
BytesRecvTotal: m.BytesRecvTotal,
})
}
var vmMetrics []vmclient.Metric
for key, netDataList := range groupedMetrics {
var agentID string
var timestamp int64
fmt.Sscanf(key, "%s_%d", &agentID, &timestamp)
converted := convertToMetrics(agentID, string(protocol.MetricTypeNetwork), netDataList, timestamp)
vmMetrics = append(vmMetrics, converted...)
}
if err := client.Write(ctx, vmMetrics); err != nil {
log.Printf(" 警告: 写入网络数据失败 (offset=%d): %v", offset, err)
}
migratedCount += len(metrics)
offset += batchSize
if migratedCount%10000 == 0 || migratedCount == int(totalCount) {
log.Printf(" 进度: %d/%d (%.1f%%)", migratedCount, totalCount, float64(migratedCount)/float64(totalCount)*100)
}
}
return nil
}
// migrateNetworkConnectionMetrics 迁移网络连接指标
func migrateNetworkConnectionMetrics(ctx context.Context, db *gorm.DB, client *vmclient.VMClient) error {
var totalCount int64
if err := db.Model(&NetworkConnectionMetric{}).Count(&totalCount).Error; err != nil {
return err
}
if totalCount == 0 {
log.Println(" 没有网络连接数据需要迁移")
return nil
}
log.Printf(" 找到 %d 条网络连接记录", totalCount)
offset := 0
migratedCount := 0
for {
var metrics []NetworkConnectionMetric
if err := db.Offset(offset).Limit(batchSize).Order("timestamp ASC").Find(&metrics).Error; err != nil {
return err
}
if len(metrics) == 0 {
break
}
var vmMetrics []vmclient.Metric
for _, m := range metrics {
connData := &protocol.NetworkConnectionData{
Established: m.Established,
SynSent: m.SynSent,
SynRecv: m.SynRecv,
TimeWait: m.TimeWait,
CloseWait: m.CloseWait,
Total: m.Total,
}
converted := convertToMetrics(m.AgentID, string(protocol.MetricTypeNetworkConnection), connData, m.Timestamp)
vmMetrics = append(vmMetrics, converted...)
}
if err := client.Write(ctx, vmMetrics); err != nil {
log.Printf(" 警告: 写入网络连接数据失败 (offset=%d): %v", offset, err)
}
migratedCount += len(metrics)
offset += batchSize
if migratedCount%10000 == 0 || migratedCount == int(totalCount) {
log.Printf(" 进度: %d/%d (%.1f%%)", migratedCount, totalCount, float64(migratedCount)/float64(totalCount)*100)
}
}
return nil
}
// migrateDiskIOMetrics 迁移磁盘IO指标
func migrateDiskIOMetrics(ctx context.Context, db *gorm.DB, client *vmclient.VMClient) error {
var totalCount int64
if err := db.Model(&DiskIOMetric{}).Count(&totalCount).Error; err != nil {
return err
}
if totalCount == 0 {
log.Println(" 没有磁盘IO数据需要迁移")
return nil
}
log.Printf(" 找到 %d 条磁盘IO记录", totalCount)
offset := 0
migratedCount := 0
for {
var metrics []DiskIOMetric
if err := db.Offset(offset).Limit(batchSize).Order("timestamp ASC").Find(&metrics).Error; err != nil {
return err
}
if len(metrics) == 0 {
break
}
// 按 agent_id + timestamp 分组
groupedMetrics := make(map[string][]*protocol.DiskIOData)
for _, m := range metrics {
key := fmt.Sprintf("%s_%d", m.AgentID, m.Timestamp)
groupedMetrics[key] = append(groupedMetrics[key], &protocol.DiskIOData{
Device: m.Device,
ReadCount: m.ReadCount,
WriteCount: m.WriteCount,
ReadBytes: m.ReadBytes,
WriteBytes: m.WriteBytes,
ReadBytesRate: m.ReadBytesRate,
WriteBytesRate: m.WriteBytesRate,
ReadTime: m.ReadTime,
WriteTime: m.WriteTime,
IoTime: m.IoTime,
IopsInProgress: m.IopsInProgress,
})
}
var vmMetrics []vmclient.Metric
for key, diskIODataList := range groupedMetrics {
var agentID string
var timestamp int64
fmt.Sscanf(key, "%s_%d", &agentID, &timestamp)
converted := convertToMetrics(agentID, string(protocol.MetricTypeDiskIO), diskIODataList, timestamp)
vmMetrics = append(vmMetrics, converted...)
}
if err := client.Write(ctx, vmMetrics); err != nil {
log.Printf(" 警告: 写入磁盘IO数据失败 (offset=%d): %v", offset, err)
}
migratedCount += len(metrics)
offset += batchSize
if migratedCount%10000 == 0 || migratedCount == int(totalCount) {
log.Printf(" 进度: %d/%d (%.1f%%)", migratedCount, totalCount, float64(migratedCount)/float64(totalCount)*100)
}
}
return nil
}
// migrateGPUMetrics 迁移GPU指标
func migrateGPUMetrics(ctx context.Context, db *gorm.DB, client *vmclient.VMClient) error {
var totalCount int64
if err := db.Model(&GPUMetric{}).Count(&totalCount).Error; err != nil {
return err
}
if totalCount == 0 {
log.Println(" 没有GPU数据需要迁移")
return nil
}
log.Printf(" 找到 %d 条GPU记录", totalCount)
offset := 0
migratedCount := 0
for {
var metrics []GPUMetric
if err := db.Offset(offset).Limit(batchSize).Order("timestamp ASC").Find(&metrics).Error; err != nil {
return err
}
if len(metrics) == 0 {
break
}
// 按 agent_id + timestamp 分组
groupedMetrics := make(map[string][]protocol.GPUData)
for _, m := range metrics {
key := fmt.Sprintf("%s_%d", m.AgentID, m.Timestamp)
groupedMetrics[key] = append(groupedMetrics[key], protocol.GPUData{
Index: m.Index,
Name: m.Name,
Utilization: m.Utilization,
MemoryTotal: m.MemoryTotal,
MemoryUsed: m.MemoryUsed,
MemoryFree: m.MemoryFree,
Temperature: m.Temperature,
PowerUsage: m.PowerDraw,
FanSpeed: m.FanSpeed,
})
}
var vmMetrics []vmclient.Metric
for key, gpuDataList := range groupedMetrics {
var agentID string
var timestamp int64
fmt.Sscanf(key, "%s_%d", &agentID, &timestamp)
converted := convertToMetrics(agentID, string(protocol.MetricTypeGPU), gpuDataList, timestamp)
vmMetrics = append(vmMetrics, converted...)
}
if err := client.Write(ctx, vmMetrics); err != nil {
log.Printf(" 警告: 写入GPU数据失败 (offset=%d): %v", offset, err)
}
migratedCount += len(metrics)
offset += batchSize
if migratedCount%10000 == 0 || migratedCount == int(totalCount) {
log.Printf(" 进度: %d/%d (%.1f%%)", migratedCount, totalCount, float64(migratedCount)/float64(totalCount)*100)
}
}
return nil
}
// migrateTemperatureMetrics 迁移温度指标
func migrateTemperatureMetrics(ctx context.Context, db *gorm.DB, client *vmclient.VMClient) error {
var totalCount int64
if err := db.Model(&TemperatureMetric{}).Count(&totalCount).Error; err != nil {
return err
}
if totalCount == 0 {
log.Println(" 没有温度数据需要迁移")
return nil
}
log.Printf(" 找到 %d 条温度记录", totalCount)
offset := 0
migratedCount := 0
for {
var metrics []TemperatureMetric
if err := db.Offset(offset).Limit(batchSize).Order("timestamp ASC").Find(&metrics).Error; err != nil {
return err
}
if len(metrics) == 0 {
break
}
// 按 agent_id + timestamp 分组
groupedMetrics := make(map[string][]protocol.TemperatureData)
for _, m := range metrics {
key := fmt.Sprintf("%s_%d", m.AgentID, m.Timestamp)
groupedMetrics[key] = append(groupedMetrics[key], protocol.TemperatureData{
SensorKey: m.SensorKey,
Temperature: m.Temperature,
Type: m.SensorLabel,
})
}
var vmMetrics []vmclient.Metric
for key, tempDataList := range groupedMetrics {
var agentID string
var timestamp int64
fmt.Sscanf(key, "%s_%d", &agentID, &timestamp)
converted := convertToMetrics(agentID, string(protocol.MetricTypeTemperature), tempDataList, timestamp)
vmMetrics = append(vmMetrics, converted...)
}
if err := client.Write(ctx, vmMetrics); err != nil {
log.Printf(" 警告: 写入温度数据失败 (offset=%d): %v", offset, err)
}
migratedCount += len(metrics)
offset += batchSize
if migratedCount%10000 == 0 || migratedCount == int(totalCount) {
log.Printf(" 进度: %d/%d (%.1f%%)", migratedCount, totalCount, float64(migratedCount)/float64(totalCount)*100)
}
}
return nil
}
// migrateMonitorMetrics 迁移监控指标
func migrateMonitorMetrics(ctx context.Context, db *gorm.DB, client *vmclient.VMClient) error {
var totalCount int64
if err := db.Model(&MonitorMetric{}).Count(&totalCount).Error; err != nil {
return err
}
if totalCount == 0 {
log.Println(" 没有监控数据需要迁移")
return nil
}
log.Printf(" 找到 %d 条监控记录", totalCount)
offset := 0
migratedCount := 0
for {
var metrics []MonitorMetric
if err := db.Offset(offset).Limit(batchSize).Order("timestamp ASC").Find(&metrics).Error; err != nil {
return err
}
if len(metrics) == 0 {
break
}
// 按 agent_id + timestamp 分组
groupedMetrics := make(map[string][]protocol.MonitorData)
for _, m := range metrics {
key := fmt.Sprintf("%s_%d", m.AgentId, m.Timestamp)
groupedMetrics[key] = append(groupedMetrics[key], protocol.MonitorData{
AgentId: m.AgentId,
MonitorId: m.MonitorId,
Type: m.Type,
Target: m.Target,
Status: m.Status,
StatusCode: m.StatusCode,
ResponseTime: m.ResponseTime,
Error: m.Error,
Message: m.Message,
ContentMatch: m.ContentMatch,
CertExpiryTime: m.CertExpiryTime,
CertDaysLeft: m.CertDaysLeft,
CheckedAt: m.Timestamp, // 使用 timestamp 作为 CheckedAt
})
}
var vmMetrics []vmclient.Metric
for key, monitorDataList := range groupedMetrics {
var agentID string
var timestamp int64
fmt.Sscanf(key, "%s_%d", &agentID, &timestamp)
converted := convertToMetrics(agentID, string(protocol.MetricTypeMonitor), monitorDataList, timestamp)
vmMetrics = append(vmMetrics, converted...)
}
if err := client.Write(ctx, vmMetrics); err != nil {
log.Printf(" 警告: 写入监控数据失败 (offset=%d): %v", offset, err)
}
migratedCount += len(metrics)
offset += batchSize
if migratedCount%10000 == 0 || migratedCount == int(totalCount) {
log.Printf(" 进度: %d/%d (%.1f%%)", migratedCount, totalCount, float64(migratedCount)/float64(totalCount)*100)
}
}
return nil
}
// DropOldTables 删除旧的指标数据表
func DropOldTables(db *gorm.DB) error {
// 要删除的表列表(除了 host_metrics,它仍然需要保留)
tables := []string{
"cpu_metrics",
"memory_metrics",
"disk_metrics",
"network_metrics",
"network_connection_metrics",
"disk_io_metrics",
"gpu_metrics",
"temperature_metrics",
"monitor_metrics",
// 聚合表也删除
"cpu_metrics_aggs",
"memory_metrics_aggs",
"disk_metrics_aggs",
"network_metrics_aggs",
"network_connection_metrics_aggs",
"disk_io_metrics_aggs",
"gpu_metrics_aggs",
"temperature_metrics_aggs",
"monitor_metrics_aggs",
"aggregation_progress",
// 统计表
"monitor_stats",
}
for _, table := range tables {
// 检查表是否存在
if !db.Migrator().HasTable(table) {
log.Printf(" 表 %s 不存在,跳过", table)
continue
}
log.Printf(" 删除表: %s", table)
if err := db.Migrator().DropTable(table); err != nil {
log.Printf(" 警告: 删除表 %s 失败: %v", table, err)
continue
}
}
return nil
}
// convertToMetrics 将指标数据转换为 VictoriaMetrics Metric 对象
// 这个函数复制自 internal/service/metric_converter.go,避免循环依赖
func convertToMetrics(agentID string, metricType string, data interface{}, timestamp int64) []vmclient.Metric {
var metrics []vmclient.Metric
switch protocol.MetricType(metricType) {
case protocol.MetricTypeCPU:
cpuData := data.(*protocol.CPUData)
metrics = append(metrics, createMetric("pika_cpu_usage_percent", agentID, nil, cpuData.UsagePercent, timestamp))
metrics = append(metrics, createMetric("pika_cpu_cores_logical", agentID, nil, float64(cpuData.LogicalCores), timestamp))
metrics = append(metrics, createMetric("pika_cpu_cores_physical", agentID, nil, float64(cpuData.PhysicalCores), timestamp))
case protocol.MetricTypeMemory:
memData := data.(*protocol.MemoryData)
metrics = append(metrics, createMetric("pika_memory_usage_percent", agentID, nil, memData.UsagePercent, timestamp))
metrics = append(metrics, createMetric("pika_memory_total_bytes", agentID, nil, float64(memData.Total), timestamp))
metrics = append(metrics, createMetric("pika_memory_used_bytes", agentID, nil, float64(memData.Used), timestamp))
metrics = append(metrics, createMetric("pika_memory_available_bytes", agentID, nil, float64(memData.Available), timestamp))
metrics = append(metrics, createMetric("pika_memory_swap_total_bytes", agentID, nil, float64(memData.SwapTotal), timestamp))
metrics = append(metrics, createMetric("pika_memory_swap_used_bytes", agentID, nil, float64(memData.SwapUsed), timestamp))
case protocol.MetricTypeDisk:
diskDataList := data.([]protocol.DiskData)
for _, diskData := range diskDataList {
labels := map[string]string{"mount_point": diskData.MountPoint}
metrics = append(metrics, createMetric("pika_disk_usage_percent", agentID, labels, diskData.UsagePercent, timestamp))
metrics = append(metrics, createMetric("pika_disk_total_bytes", agentID, labels, float64(diskData.Total), timestamp))
metrics = append(metrics, createMetric("pika_disk_used_bytes", agentID, labels, float64(diskData.Used), timestamp))
metrics = append(metrics, createMetric("pika_disk_free_bytes", agentID, labels, float64(diskData.Free), timestamp))
}
case protocol.MetricTypeNetwork:
networkDataList := data.([]protocol.NetworkData)
for _, netData := range networkDataList {
labels := map[string]string{"interface": netData.Interface}
metrics = append(metrics, createMetric("pika_network_sent_bytes_rate", agentID, labels, float64(netData.BytesSentRate), timestamp))
metrics = append(metrics, createMetric("pika_network_recv_bytes_rate", agentID, labels, float64(netData.BytesRecvRate), timestamp))
metrics = append(metrics, createMetric("pika_network_sent_bytes_total", agentID, labels, float64(netData.BytesSentTotal), timestamp))
metrics = append(metrics, createMetric("pika_network_recv_bytes_total", agentID, labels, float64(netData.BytesRecvTotal), timestamp))
}
case protocol.MetricTypeNetworkConnection:
connData := data.(*protocol.NetworkConnectionData)
metrics = append(metrics, createMetric("pika_network_conn_established", agentID, nil, float64(connData.Established), timestamp))
metrics = append(metrics, createMetric("pika_network_conn_syn_sent", agentID, nil, float64(connData.SynSent), timestamp))
metrics = append(metrics, createMetric("pika_network_conn_syn_recv", agentID, nil, float64(connData.SynRecv), timestamp))
metrics = append(metrics, createMetric("pika_network_conn_time_wait", agentID, nil, float64(connData.TimeWait), timestamp))
metrics = append(metrics, createMetric("pika_network_conn_close_wait", agentID, nil, float64(connData.CloseWait), timestamp))
metrics = append(metrics, createMetric("pika_network_conn_listen", agentID, nil, float64(connData.Listen), timestamp))
metrics = append(metrics, createMetric("pika_network_conn_total", agentID, nil, float64(connData.Total), timestamp))
case protocol.MetricTypeDiskIO:
diskIODataList := data.([]*protocol.DiskIOData)
// 汇总所有磁盘的 IO
var totalReadRate, totalWriteRate uint64
for _, diskIOData := range diskIODataList {
totalReadRate += diskIOData.ReadBytesRate
totalWriteRate += diskIOData.WriteBytesRate
}
metrics = append(metrics, createMetric("pika_disk_read_bytes_rate", agentID, nil, float64(totalReadRate), timestamp))
metrics = append(metrics, createMetric("pika_disk_write_bytes_rate", agentID, nil, float64(totalWriteRate), timestamp))
case protocol.MetricTypeGPU:
gpuDataList := data.([]protocol.GPUData)
for _, gpuData := range gpuDataList {
labels := map[string]string{
"gpu_index": fmt.Sprintf("%d", gpuData.Index),
"gpu_name": gpuData.Name,
}
metrics = append(metrics, createMetric("pika_gpu_utilization_percent", agentID, labels, gpuData.Utilization, timestamp))
metrics = append(metrics, createMetric("pika_gpu_memory_total_bytes", agentID, labels, float64(gpuData.MemoryTotal), timestamp))
metrics = append(metrics, createMetric("pika_gpu_memory_used_bytes", agentID, labels, float64(gpuData.MemoryUsed), timestamp))
metrics = append(metrics, createMetric("pika_gpu_temperature_celsius", agentID, labels, gpuData.Temperature, timestamp))
metrics = append(metrics, createMetric("pika_gpu_power_draw_watts", agentID, labels, gpuData.PowerUsage, timestamp))
}
case protocol.MetricTypeTemperature:
tempDataList := data.([]protocol.TemperatureData)
for _, tempData := range tempDataList {
labels := map[string]string{
"sensor_label": tempData.Type,
}
metrics = append(metrics, createMetric("pika_temperature_celsius", agentID, labels, tempData.Temperature, timestamp))
}
case protocol.MetricTypeMonitor:
monitorDataList := data.([]protocol.MonitorData)
for _, monitorData := range monitorDataList {
labels := map[string]string{
"monitor_id": monitorData.MonitorId,
"monitor_type": monitorData.Type,
"target": monitorData.Target,
}
metrics = append(metrics, createMetric("pika_monitor_response_time_ms", agentID, labels, float64(monitorData.ResponseTime), timestamp))
}
}
return metrics
}
// createMetric 创建 VictoriaMetrics Metric 对象
func createMetric(metricName, agentID string, extraLabels map[string]string, value float64, timestamp int64) vmclient.Metric {
labels := make(map[string]string)
labels["__name__"] = metricName
labels["agent_id"] = agentID
if extraLabels != nil {
for k, v := range extraLabels {
labels[k] = v
}
}
return vmclient.Metric{
Metric: labels,
Values: []float64{value},
Timestamps: []int64{timestamp},
}
}