package controller import ( "net/http" "os" "runtime" "time" "github.com/QuantumNous/new-api/common" "github.com/gin-gonic/gin" ) // PerformanceStats 性能统计信息 type PerformanceStats struct { // 缓存统计 CacheStats common.DiskCacheStats `json:"cache_stats"` // 系统内存统计 MemoryStats MemoryStats `json:"memory_stats"` // 磁盘缓存目录信息 DiskCacheInfo DiskCacheInfo `json:"disk_cache_info"` // 磁盘空间信息 DiskSpaceInfo common.DiskSpaceInfo `json:"disk_space_info"` // 配置信息 Config PerformanceConfig `json:"config"` } // MemoryStats 内存统计 type MemoryStats struct { // 已分配内存(字节) Alloc uint64 `json:"alloc"` // 总分配内存(字节) TotalAlloc uint64 `json:"total_alloc"` // 系统内存(字节) Sys uint64 `json:"sys"` // GC 次数 NumGC uint32 `json:"num_gc"` // Goroutine 数量 NumGoroutine int `json:"num_goroutine"` } // DiskCacheInfo 磁盘缓存目录信息 type DiskCacheInfo struct { // 缓存目录路径 Path string `json:"path"` // 目录是否存在 Exists bool `json:"exists"` // 文件数量 FileCount int `json:"file_count"` // 总大小(字节) TotalSize int64 `json:"total_size"` } // PerformanceConfig 性能配置 type PerformanceConfig struct { // 是否启用磁盘缓存 DiskCacheEnabled bool `json:"disk_cache_enabled"` // 磁盘缓存阈值(MB) DiskCacheThresholdMB int `json:"disk_cache_threshold_mb"` // 磁盘缓存最大大小(MB) DiskCacheMaxSizeMB int `json:"disk_cache_max_size_mb"` // 磁盘缓存路径 DiskCachePath string `json:"disk_cache_path"` // 是否在容器中运行 IsRunningInContainer bool `json:"is_running_in_container"` // MonitorEnabled 是否启用性能监控 MonitorEnabled bool `json:"monitor_enabled"` // MonitorCPUThreshold CPU 使用率阈值(%) MonitorCPUThreshold int `json:"monitor_cpu_threshold"` // MonitorMemoryThreshold 内存使用率阈值(%) MonitorMemoryThreshold int `json:"monitor_memory_threshold"` // MonitorDiskThreshold 磁盘使用率阈值(%) MonitorDiskThreshold int `json:"monitor_disk_threshold"` } // GetPerformanceStats 获取性能统计信息 func GetPerformanceStats(c *gin.Context) { // 不再每次获取统计都全量扫描磁盘,依赖原子计数器保证性能 // 仅在系统启动或显式清理时同步 cacheStats := common.GetDiskCacheStats() // 获取内存统计 var memStats runtime.MemStats runtime.ReadMemStats(&memStats) // 获取磁盘缓存目录信息 diskCacheInfo := getDiskCacheInfo() // 获取配置信息 diskConfig := common.GetDiskCacheConfig() monitorConfig := common.GetPerformanceMonitorConfig() config := PerformanceConfig{ DiskCacheEnabled: diskConfig.Enabled, DiskCacheThresholdMB: diskConfig.ThresholdMB, DiskCacheMaxSizeMB: diskConfig.MaxSizeMB, DiskCachePath: diskConfig.Path, IsRunningInContainer: common.IsRunningInContainer(), MonitorEnabled: monitorConfig.Enabled, MonitorCPUThreshold: monitorConfig.CPUThreshold, MonitorMemoryThreshold: monitorConfig.MemoryThreshold, MonitorDiskThreshold: monitorConfig.DiskThreshold, } // 获取磁盘空间信息 // 使用缓存的系统状态,避免频繁调用系统 API systemStatus := common.GetSystemStatus() diskSpaceInfo := common.DiskSpaceInfo{ UsedPercent: systemStatus.DiskUsage, } // 如果需要详细信息,可以按需获取,或者扩展 SystemStatus // 这里为了保持接口兼容性,我们仍然调用 GetDiskSpaceInfo,但注意这可能会有性能开销 // 考虑到 GetPerformanceStats 是管理接口,频率较低,直接调用是可以接受的 // 但为了一致性,我们也可以考虑从 SystemStatus 中获取部分信息 diskSpaceInfo = common.GetDiskSpaceInfo() stats := PerformanceStats{ CacheStats: cacheStats, MemoryStats: MemoryStats{ Alloc: memStats.Alloc, TotalAlloc: memStats.TotalAlloc, Sys: memStats.Sys, NumGC: memStats.NumGC, NumGoroutine: runtime.NumGoroutine(), }, DiskCacheInfo: diskCacheInfo, DiskSpaceInfo: diskSpaceInfo, Config: config, } c.JSON(http.StatusOK, gin.H{ "success": true, "data": stats, }) } // ClearDiskCache 清理不活跃的磁盘缓存 func ClearDiskCache(c *gin.Context) { // 清理超过 10 分钟未使用的缓存文件 // 10 分钟是一个安全的阈值,确保正在进行的请求不会被误删 err := common.CleanupOldDiskCacheFiles(10 * time.Minute) if err != nil { common.ApiError(c, err) return } c.JSON(http.StatusOK, gin.H{ "success": true, "message": "不活跃的磁盘缓存已清理", }) } // ResetPerformanceStats 重置性能统计 func ResetPerformanceStats(c *gin.Context) { common.ResetDiskCacheStats() c.JSON(http.StatusOK, gin.H{ "success": true, "message": "统计信息已重置", }) } // ForceGC 强制执行 GC func ForceGC(c *gin.Context) { runtime.GC() c.JSON(http.StatusOK, gin.H{ "success": true, "message": "GC 已执行", }) } // getDiskCacheInfo 获取磁盘缓存目录信息 func getDiskCacheInfo() DiskCacheInfo { // 使用统一的缓存目录 dir := common.GetDiskCacheDir() info := DiskCacheInfo{ Path: dir, Exists: false, } entries, err := os.ReadDir(dir) if err != nil { return info } info.Exists = true info.FileCount = 0 info.TotalSize = 0 for _, entry := range entries { if entry.IsDir() { continue } info.FileCount++ if fileInfo, err := entry.Info(); err == nil { info.TotalSize += fileInfo.Size() } } return info }