Skip to content

feat(performance): implement system performance monitoring - #2835

Merged
Calcium-Ion merged 1 commit into
mainfrom
feat/performance-monitoring
Feb 4, 2026
Merged

feat(performance): implement system performance monitoring#2835
Calcium-Ion merged 1 commit into
mainfrom
feat/performance-monitoring

Conversation

@Calcium-Ion

@Calcium-Ion Calcium-Ion commented Feb 4, 2026

Copy link
Copy Markdown
Member

Summary by CodeRabbit

Release Notes

  • New Features

    • Added system performance monitoring with configurable thresholds for CPU, memory, and disk usage
    • Implemented automatic request throttling when system resources exceed configured limits
    • Added performance monitoring controls to Settings page with enable/disable toggle and threshold configuration
  • Localization

    • Added translations for performance monitoring settings in English and Chinese

@coderabbitai

coderabbitai Bot commented Feb 4, 2026

Copy link
Copy Markdown
Contributor

Walkthrough

A new system performance monitoring feature is introduced that periodically collects CPU, memory, and disk usage metrics, stores them in atomic state, and enforces configurable thresholds via a middleware component. Configuration is managed through settings with corresponding UI controls, and platform-specific disk space information collection is centralized to the common package.

Changes

Cohort / File(s) Summary
Core Monitoring Infrastructure
common/performance_config.go, common/system_monitor.go
New performance monitoring foundation: PerformanceMonitorConfig struct with atomic storage and getters/setters; StartSystemMonitor() goroutine that collects CPU, memory, disk metrics every 5 seconds; GetSystemStatus() returns latest metrics; DiskSpaceInfo and SystemStatus types for metric storage.
Platform-Specific Disk Space Implementation
common/system_monitor_unix.go, common/system_monitor_windows.go
Platform-specific GetDiskSpaceInfo() implementations moved to common package with local function calls; previously in controller package with external common package dependencies.
Middleware & Router Integration
middleware/performance.go, router/relay-router.go
New SystemPerformanceCheck() middleware enforces CPU/memory/disk thresholds; returns HTTP 503 with appropriate error codes (system_cpu_overloaded, system_memory_overloaded, system_disk_overloaded) when limits breached; integrated into six router groups (/pg, /v1, /mj, /:mode/mj, /suno, /v1beta).
Controller & Configuration Updates
controller/performance.go, setting/performance_setting/config.go
DiskSpaceInfo type migrated to common package; PerformanceStats updated to use common.DiskSpaceInfo; PerformanceConfig extended with MonitorEnabled, MonitorCPUThreshold, MonitorMemoryThreshold, MonitorDiskThreshold fields; defaults set to enabled with 90% thresholds.
Startup & Runtime
main.go
common.StartSystemMonitor() invoked during resource initialization after Redis setup.
Localization & UI
web/src/i18n/locales/en.json, web/src/i18n/locales/zh.json, web/src/pages/Setting/Performance/SettingsPerformance.jsx
English and Chinese translations for system performance monitoring labels, descriptions, and thresholds; SettingsPerformance.jsx adds UI toggle and threshold inputs with conditional enabling based on monitor_enabled flag.

Sequence Diagram

sequenceDiagram
    participant Client
    participant Middleware
    participant Common
    participant SystemMonitor as System Monitoring<br/>(Background)
    participant Resources as System Resources

    Note over SystemMonitor: Every 5 seconds
    SystemMonitor->>Common: updateSystemStatus()
    Common->>Resources: Collect CPU, Memory, Disk
    Resources-->>Common: Metrics
    Common->>Common: Store in atomic.Value

    Client->>Middleware: HTTP Request
    Middleware->>Common: GetPerformanceMonitorConfig()
    Common-->>Middleware: Config (Enabled, Thresholds)
    
    alt Monitoring Disabled
        Middleware->>Middleware: Skip checks
    else Monitoring Enabled
        Middleware->>Common: GetSystemStatus()
        Common-->>Middleware: Current Metrics
        
        alt CPU > Threshold
            Middleware->>Middleware: NewAPIError<br/>system_cpu_overloaded
            Middleware-->>Client: HTTP 503
        else Memory > Threshold
            Middleware->>Middleware: NewAPIError<br/>system_memory_overloaded
            Middleware-->>Client: HTTP 503
        else Disk > Threshold
            Middleware->>Middleware: NewAPIError<br/>system_disk_overloaded
            Middleware-->>Client: HTTP 503
        else All OK
            Middleware->>Client: c.Next() → Handler
        end
    end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~50 minutes

Possibly related PRs

  • feat: disk request body cache #2780 — Directly overlaps on disk cache and performance monitoring code, including DiskSpaceInfo types, GetDiskSpaceInfo function, and controller performance endpoints.

Poem

🐰 Hops through metrics with glee,
CPU, memory, disk—all three!
Thresholds alert when things run hot,
Goroutines keep tabs on the lot,
Atomic states, safe and sound,
Performance magic, all around!

🚥 Pre-merge checks | ✅ 2 | ❌ 1
❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 58.82% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'feat(performance): implement system performance monitoring' directly and clearly summarizes the main change—introducing a new system performance monitoring feature across the codebase.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feat/performance-monitoring

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@Calcium-Ion
Calcium-Ion merged commit 65b2ca4 into main Feb 4, 2026
1 check was pending

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
web/src/pages/Setting/Performance/SettingsPerformance.jsx (1)

63-71: ⚠️ Potential issue | 🟡 Minor

UI default for monitor_enabled conflicts with backend default.

Server defaults to enabled, but the UI default is false; if the option isn’t persisted yet, the UI can show “off” while monitoring is actually on. Align the default or derive it from backend options.

✅ Suggested fix
-  'performance_setting.monitor_enabled': false,
+  'performance_setting.monitor_enabled': true,
🤖 Fix all issues with AI agents
In `@middleware/performance.go`:
- Around line 49-61: The threshold checks cast float usage values to int causing
truncation; update the three comparisons (the CPU, Memory and Disk checks that
reference config.CPUThreshold, config.MemoryThreshold, config.DiskThreshold and
status.CPUUsage, status.MemoryUsage, status.DiskUsage) to compare floats instead
(e.g., convert the int thresholds to float64 or compare status.*Usage >=
float64(config.*Threshold)) and keep the same error returns via
types.NewErrorWithStatusCode when the condition is met.

In `@web/src/i18n/locales/en.json`:
- Around line 2729-2769: Remove the duplicated Disk Cache/Performance
translation block and keep only the first set of keys; locate the repeated keys
such as "磁盘缓存设置(磁盘换内存)", "启用磁盘缓存", "磁盘缓存阈值 (MB)", "性能监控", "请求体磁盘缓存", "磁盘缓存已清理",
and "输出价格" and delete the redundant second block that introduces the English
keys (which may override earlier entries), ensuring each translation key appears
exactly once and translations remain the original English values from the first
occurrence.
🧹 Nitpick comments (4)
common/system_monitor.go (1)

3-49: Make StartSystemMonitor idempotent to avoid multiple goroutines.
If this gets called more than once (tests, re-init paths), it will spawn duplicate loops. A sync.Once guard keeps it safe.

♻️ Suggested change
 import (
+	"sync"
 	"sync/atomic"
 	"time"

 	"github.com/shirou/gopsutil/cpu"
 	"github.com/shirou/gopsutil/mem"
 )
@@
-var latestSystemStatus atomic.Value
+var (
+	latestSystemStatus     atomic.Value
+	startSystemMonitorOnce sync.Once
+)
@@
 func StartSystemMonitor() {
-	go func() {
-		for {
-			config := GetPerformanceMonitorConfig()
-			if !config.Enabled {
-				time.Sleep(30 * time.Second)
-				continue
-			}
-
-			updateSystemStatus()
-			time.Sleep(5 * time.Second)
-		}
-	}()
+	startSystemMonitorOnce.Do(func() {
+		go func() {
+			for {
+				config := GetPerformanceMonitorConfig()
+				if !config.Enabled {
+					time.Sleep(30 * time.Second)
+					continue
+				}
+
+				updateSystemStatus()
+				time.Sleep(5 * time.Second)
+			}
+		}()
+	})
 }
setting/performance_setting/config.go (1)

58-63: Clamp monitor thresholds before syncing.

Values can originate from DB/env and might fall outside 0–100, which can silently disable monitoring or make it overly aggressive. Consider clamping at sync time.

♻️ Suggested clamp before SetPerformanceMonitorConfig
  common.SetDiskCacheConfig(common.DiskCacheConfig{
    Enabled:     performanceSetting.DiskCacheEnabled,
    ThresholdMB: performanceSetting.DiskCacheThresholdMB,
    MaxSizeMB:   performanceSetting.DiskCacheMaxSizeMB,
    Path:        performanceSetting.DiskCachePath,
  })

+ cpu := performanceSetting.MonitorCPUThreshold
+ if cpu < 0 { cpu = 0 } else if cpu > 100 { cpu = 100 }
+ mem := performanceSetting.MonitorMemoryThreshold
+ if mem < 0 { mem = 0 } else if mem > 100 { mem = 100 }
+ disk := performanceSetting.MonitorDiskThreshold
+ if disk < 0 { disk = 0 } else if disk > 100 { disk = 100 }
  common.SetPerformanceMonitorConfig(common.PerformanceMonitorConfig{
    Enabled:         performanceSetting.MonitorEnabled,
-   CPUThreshold:    performanceSetting.MonitorCPUThreshold,
-   MemoryThreshold: performanceSetting.MonitorMemoryThreshold,
-   DiskThreshold:   performanceSetting.MonitorDiskThreshold,
+   CPUThreshold:    cpu,
+   MemoryThreshold: mem,
+   DiskThreshold:   disk,
  })
middleware/performance.go (1)

14-36: Reduce duplicated error-handling branches.

You can call checkSystemPerformance() once and then choose the error shape based on the path, which trims duplication.

♻️ Suggested refactor
   return func(c *gin.Context) {
     // 仅检查 Relay 接口 (/v1, /v1beta 等)
     // 这里简单判断路径前缀,可以根据实际路由调整
     path := c.Request.URL.Path
-    if strings.HasPrefix(path, "/v1/messages") {
-      if err := checkSystemPerformance(); err != nil {
-        c.JSON(err.StatusCode, gin.H{
-          "error": err.ToClaudeError(),
-        })
-        c.Abort()
-        return
-      }
-    } else {
-      if err := checkSystemPerformance(); err != nil {
-        c.JSON(err.StatusCode, gin.H{
-          "error": err.ToOpenAIError(),
-        })
-        c.Abort()
-        return
-      }
-    }
+    if err := checkSystemPerformance(); err != nil {
+      var apiErr any
+      if strings.HasPrefix(path, "/v1/messages") {
+        apiErr = err.ToClaudeError()
+      } else {
+        apiErr = err.ToOpenAIError()
+      }
+      c.JSON(err.StatusCode, gin.H{"error": apiErr})
+      c.Abort()
+      return
+    }
     c.Next()
   }
 }
controller/performance.go (1)

105-114: Remove redundant diskSpaceInfo prefill.

diskSpaceInfo is initialized from SystemStatus and then immediately overwritten, so the first assignment is dead code. Either drop it or make GetDiskSpaceInfo() conditional.

♻️ Suggested simplification
- systemStatus := common.GetSystemStatus()
- diskSpaceInfo := common.DiskSpaceInfo{
-   UsedPercent: systemStatus.DiskUsage,
- }
- // 如果需要详细信息,可以按需获取,或者扩展 SystemStatus
- // 这里为了保持接口兼容性,我们仍然调用 GetDiskSpaceInfo,但注意这可能会有性能开销
- // 考虑到 GetPerformanceStats 是管理接口,频率较低,直接调用是可以接受的
- // 但为了一致性,我们也可以考虑从 SystemStatus 中获取部分信息
- diskSpaceInfo = common.GetDiskSpaceInfo()
+ diskSpaceInfo := common.GetDiskSpaceInfo()

Comment thread middleware/performance.go
Comment on lines +49 to +61
// 检查 CPU
if config.CPUThreshold > 0 && int(status.CPUUsage) > config.CPUThreshold {
return types.NewErrorWithStatusCode(errors.New("system cpu overloaded"), "system_cpu_overloaded", http.StatusServiceUnavailable)
}

// 检查内存
if config.MemoryThreshold > 0 && int(status.MemoryUsage) > config.MemoryThreshold {
return types.NewErrorWithStatusCode(errors.New("system memory overloaded"), "system_memory_overloaded", http.StatusServiceUnavailable)
}

// 检查磁盘
if config.DiskThreshold > 0 && int(status.DiskUsage) > config.DiskThreshold {
return types.NewErrorWithStatusCode(errors.New("system disk overloaded"), "system_disk_overloaded", http.StatusServiceUnavailable)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

# First, let's locate and examine the middleware/performance.go file
fd middleware -type f -name "performance.go"

Repository: QuantumNous/new-api

Length of output: 233


🏁 Script executed:

# Also check for the types/status struct definition
fd -e go | head -20

Repository: QuantumNous/new-api

Length of output: 469


🏁 Script executed:

# Search for the status struct definition that contains CPUUsage, MemoryUsage, DiskUsage
rg "type.*Status.*struct" -A 10

Repository: QuantumNous/new-api

Length of output: 7205


🏁 Script executed:

# Search for config struct with threshold fields
rg "CPUThreshold|MemoryThreshold|DiskThreshold" -B 5 -A 2

Repository: QuantumNous/new-api

Length of output: 5987


Fix float-to-int truncation in threshold checks.

The status.CPUUsage, status.MemoryUsage, and status.DiskUsage fields are float64, while the threshold config values are int. Casting to int truncates (e.g., 90.9 → 90), allowing values just below the integer threshold to bypass the check. Compare as floats instead:

- if config.CPUThreshold > 0 && int(status.CPUUsage) > config.CPUThreshold {
+ if config.CPUThreshold > 0 && status.CPUUsage > float64(config.CPUThreshold) {
     return types.NewErrorWithStatusCode(errors.New("system cpu overloaded"), "system_cpu_overloaded", http.StatusServiceUnavailable)
   }
- if config.MemoryThreshold > 0 && int(status.MemoryUsage) > config.MemoryThreshold {
+ if config.MemoryThreshold > 0 && status.MemoryUsage > float64(config.MemoryThreshold) {
     return types.NewErrorWithStatusCode(errors.New("system memory overloaded"), "system_memory_overloaded", http.StatusServiceUnavailable)
   }
- if config.DiskThreshold > 0 && int(status.DiskUsage) > config.DiskThreshold {
+ if config.DiskThreshold > 0 && status.DiskUsage > float64(config.DiskThreshold) {
     return types.NewErrorWithStatusCode(errors.New("system disk overloaded"), "system_disk_overloaded", http.StatusServiceUnavailable)
   }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
// 检查 CPU
if config.CPUThreshold > 0 && int(status.CPUUsage) > config.CPUThreshold {
return types.NewErrorWithStatusCode(errors.New("system cpu overloaded"), "system_cpu_overloaded", http.StatusServiceUnavailable)
}
// 检查内存
if config.MemoryThreshold > 0 && int(status.MemoryUsage) > config.MemoryThreshold {
return types.NewErrorWithStatusCode(errors.New("system memory overloaded"), "system_memory_overloaded", http.StatusServiceUnavailable)
}
// 检查磁盘
if config.DiskThreshold > 0 && int(status.DiskUsage) > config.DiskThreshold {
return types.NewErrorWithStatusCode(errors.New("system disk overloaded"), "system_disk_overloaded", http.StatusServiceUnavailable)
// 检查 CPU
if config.CPUThreshold > 0 && status.CPUUsage > float64(config.CPUThreshold) {
return types.NewErrorWithStatusCode(errors.New("system cpu overloaded"), "system_cpu_overloaded", http.StatusServiceUnavailable)
}
// 检查内存
if config.MemoryThreshold > 0 && status.MemoryUsage > float64(config.MemoryThreshold) {
return types.NewErrorWithStatusCode(errors.New("system memory overloaded"), "system_memory_overloaded", http.StatusServiceUnavailable)
}
// 检查磁盘
if config.DiskThreshold > 0 && status.DiskUsage > float64(config.DiskThreshold) {
return types.NewErrorWithStatusCode(errors.New("system disk overloaded"), "system_disk_overloaded", http.StatusServiceUnavailable)
}
🤖 Prompt for AI Agents
In `@middleware/performance.go` around lines 49 - 61, The threshold checks cast
float usage values to int causing truncation; update the three comparisons (the
CPU, Memory and Disk checks that reference config.CPUThreshold,
config.MemoryThreshold, config.DiskThreshold and status.CPUUsage,
status.MemoryUsage, status.DiskUsage) to compare floats instead (e.g., convert
the int thresholds to float64 or compare status.*Usage >=
float64(config.*Threshold)) and keep the same error returns via
types.NewErrorWithStatusCode when the condition is met.

Comment on lines +2729 to +2769
"管理员未开启在线支付功能,请联系管理员配置。": "Online payment is not enabled by the admin. Please contact the administrator.",
"磁盘缓存设置(磁盘换内存)": "Disk Cache Settings (Disk Swap Memory)",
"启用磁盘缓存后,大请求体将临时存储到磁盘而非内存,可显著降低内存占用,适用于处理包含大量图片/文件的请求。建议在 SSD 环境下使用。": "When enabled, large request bodies are temporarily stored on disk instead of memory, significantly reducing memory usage. Suitable for requests with large images/files. SSD recommended.",
"启用磁盘缓存": "Enable Disk Cache",
"将大请求体临时存储到磁盘": "Store large request bodies temporarily on disk",
"磁盘缓存阈值 (MB)": "Disk Cache Threshold (MB)",
"请求体超过此大小时使用磁盘缓存": "Use disk cache when request body exceeds this size",
"磁盘缓存最大总量 (MB)": "Max Disk Cache Size (MB)",
"可用空间: {{free}} / 总空间: {{total}}": "Free: {{free}} / Total: {{total}}",
"磁盘缓存占用的最大空间": "Maximum space occupied by disk cache",
"留空使用系统临时目录": "Leave empty to use system temp directory",
"例如 /var/cache/new-api": "e.g. /var/cache/new-api",
"性能监控": "Performance Monitor",
"刷新统计": "Refresh Stats",
"重置统计": "Reset Stats",
"执行 GC": "Run GC",
"请求体磁盘缓存": "Request Body Disk Cache",
"活跃文件": "Active Files",
"磁盘命中": "Disk Hits",
"请求体内存缓存": "Request Body Memory Cache",
"当前缓存大小": "Current Cache Size",
"活跃缓存数": "Active Cache Count",
"内存命中": "Memory Hits",
"缓存目录磁盘空间": "Cache Directory Disk Space",
"磁盘可用空间小于缓存最大总量设置": "Disk free space is less than max cache size setting",
"已分配内存": "Allocated Memory",
"总分配内存": "Total Allocated Memory",
"系统内存": "System Memory",
"GC 次数": "GC Count",
"Goroutine 数": "Goroutine Count",
"目录文件数": "Directory File Count",
"目录总大小": "Directory Total Size",
"磁盘缓存已清理": "Disk cache cleared",
"清理失败": "Cleanup failed",
"统计已重置": "Statistics reset",
"重置失败": "Reset failed",
"GC 已执行": "GC executed",
"GC execution failed": "GC execution failed",
"Cache Directory": "Cache Directory",
"Available": "Available",
"输出价格": "Output Price"

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Remove the duplicated Disk Cache/Performance strings block.
These keys are repeated (and the second block introduces English keys), which can override earlier entries and break key consistency. Please keep only one block.

🧹 Proposed cleanup (drop the duplicated block)
-    "管理员未开启在线支付功能,请联系管理员配置。": "Online payment is not enabled by the admin. Please contact the administrator.",
-    "磁盘缓存设置(磁盘换内存)": "Disk Cache Settings (Disk Swap Memory)",
-    "启用磁盘缓存后,大请求体将临时存储到磁盘而非内存,可显著降低内存占用,适用于处理包含大量图片/文件的请求。建议在 SSD 环境下使用。": "When enabled, large request bodies are temporarily stored on disk instead of memory, significantly reducing memory usage. Suitable for requests with large images/files. SSD recommended.",
-    "启用磁盘缓存": "Enable Disk Cache",
-    "将大请求体临时存储到磁盘": "Store large request bodies temporarily on disk",
-    "磁盘缓存阈值 (MB)": "Disk Cache Threshold (MB)",
-    "请求体超过此大小时使用磁盘缓存": "Use disk cache when request body exceeds this size",
-    "磁盘缓存最大总量 (MB)": "Max Disk Cache Size (MB)",
-    "可用空间: {{free}} / 总空间: {{total}}": "Free: {{free}} / Total: {{total}}",
-    "磁盘缓存占用的最大空间": "Maximum space occupied by disk cache",
-    "留空使用系统临时目录": "Leave empty to use system temp directory",
-    "例如 /var/cache/new-api": "e.g. /var/cache/new-api",
-    "性能监控": "Performance Monitor",
-    "刷新统计": "Refresh Stats",
-    "重置统计": "Reset Stats",
-    "执行 GC": "Run GC",
-    "请求体磁盘缓存": "Request Body Disk Cache",
-    "活跃文件": "Active Files",
-    "磁盘命中": "Disk Hits",
-    "请求体内存缓存": "Request Body Memory Cache",
-    "当前缓存大小": "Current Cache Size",
-    "活跃缓存数": "Active Cache Count",
-    "内存命中": "Memory Hits",
-    "缓存目录磁盘空间": "Cache Directory Disk Space",
-    "磁盘可用空间小于缓存最大总量设置": "Disk free space is less than max cache size setting",
-    "已分配内存": "Allocated Memory",
-    "总分配内存": "Total Allocated Memory",
-    "系统内存": "System Memory",
-    "GC 次数": "GC Count",
-    "Goroutine 数": "Goroutine Count",
-    "目录文件数": "Directory File Count",
-    "目录总大小": "Directory Total Size",
-    "磁盘缓存已清理": "Disk cache cleared",
-    "清理失败": "Cleanup failed",
-    "统计已重置": "Statistics reset",
-    "重置失败": "Reset failed",
-    "GC 已执行": "GC executed",
-    "GC execution failed": "GC execution failed",
-    "Cache Directory": "Cache Directory",
-    "Available": "Available",
-    "输出价格": "Output Price"
+    "管理员未开启在线支付功能,请联系管理员配置。": "Online payment is not enabled by the admin. Please contact the administrator."
🤖 Prompt for AI Agents
In `@web/src/i18n/locales/en.json` around lines 2729 - 2769, Remove the duplicated
Disk Cache/Performance translation block and keep only the first set of keys;
locate the repeated keys such as "磁盘缓存设置(磁盘换内存)", "启用磁盘缓存", "磁盘缓存阈值 (MB)",
"性能监控", "请求体磁盘缓存", "磁盘缓存已清理", and "输出价格" and delete the redundant second block
that introduces the English keys (which may override earlier entries), ensuring
each translation key appears exactly once and translations remain the original
English values from the first occurrence.

ennnnny pushed a commit to ennnnny/new-api that referenced this pull request Mar 17, 2026
…-monitoring

feat(performance): implement system performance monitoring
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant