mirror of https://github.com/jetkvm/kvm.git
refactor(audio): centralize metrics collection with new registry
Introduce MetricsRegistry to serve as single source of truth for audio metrics Remove duplicate metrics collection logic from web endpoints Add callback mechanism for metrics updates
This commit is contained in:
parent
fe4571956d
commit
0d4176cf98
|
@ -1,5 +0,0 @@
|
|||
# Netscape HTTP Cookie File
|
||||
# https://curl.se/docs/http-cookies.html
|
||||
# This file was generated by libcurl! Edit at your own risk.
|
||||
|
||||
#HttpOnly_192.168.100.214 FALSE / FALSE 1756968962 authToken 3b0b77eb-3771-4eb2-9704-ffcdf3ba788b
|
|
@ -721,26 +721,17 @@ func GetLastMetricsUpdate() time.Time {
|
|||
|
||||
// StartMetricsUpdater starts a goroutine that periodically updates Prometheus metrics
|
||||
func StartMetricsUpdater() {
|
||||
// Start the centralized metrics collector
|
||||
registry := GetMetricsRegistry()
|
||||
registry.StartMetricsCollector()
|
||||
|
||||
// Start a separate goroutine for periodic updates
|
||||
go func() {
|
||||
ticker := time.NewTicker(5 * time.Second) // Update every 5 seconds
|
||||
defer ticker.Stop()
|
||||
|
||||
for range ticker.C {
|
||||
// Update audio output metrics
|
||||
audioMetrics := GetAudioMetrics()
|
||||
UpdateAudioMetrics(convertAudioMetricsToUnified(audioMetrics))
|
||||
|
||||
// Update microphone input metrics
|
||||
micMetrics := GetAudioInputMetrics()
|
||||
UpdateMicrophoneMetrics(convertAudioInputMetricsToUnified(micMetrics))
|
||||
|
||||
// Update audio configuration metrics
|
||||
audioConfig := GetAudioConfig()
|
||||
UpdateAudioConfigMetrics(audioConfig)
|
||||
micConfig := GetMicrophoneConfig()
|
||||
UpdateMicrophoneConfigMetrics(micConfig)
|
||||
|
||||
// Update memory metrics
|
||||
// Update memory metrics (not part of centralized registry)
|
||||
UpdateMemoryMetrics()
|
||||
}
|
||||
}()
|
||||
|
|
|
@ -0,0 +1,151 @@
|
|||
//go:build cgo
|
||||
|
||||
package audio
|
||||
|
||||
import (
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
"time"
|
||||
)
|
||||
|
||||
// MetricsRegistry provides a centralized source of truth for all audio metrics
|
||||
// This eliminates duplication between session-specific and global managers
|
||||
type MetricsRegistry struct {
|
||||
mu sync.RWMutex
|
||||
audioMetrics AudioMetrics
|
||||
audioInputMetrics AudioInputMetrics
|
||||
audioConfig AudioConfig
|
||||
microphoneConfig AudioConfig
|
||||
lastUpdate int64 // Unix timestamp
|
||||
}
|
||||
|
||||
var (
|
||||
globalMetricsRegistry *MetricsRegistry
|
||||
registryOnce sync.Once
|
||||
)
|
||||
|
||||
// GetMetricsRegistry returns the global metrics registry instance
|
||||
func GetMetricsRegistry() *MetricsRegistry {
|
||||
registryOnce.Do(func() {
|
||||
globalMetricsRegistry = &MetricsRegistry{
|
||||
lastUpdate: time.Now().Unix(),
|
||||
}
|
||||
})
|
||||
return globalMetricsRegistry
|
||||
}
|
||||
|
||||
// UpdateAudioMetrics updates the centralized audio output metrics
|
||||
func (mr *MetricsRegistry) UpdateAudioMetrics(metrics AudioMetrics) {
|
||||
mr.mu.Lock()
|
||||
mr.audioMetrics = metrics
|
||||
mr.lastUpdate = time.Now().Unix()
|
||||
mr.mu.Unlock()
|
||||
|
||||
// Update Prometheus metrics directly to avoid circular dependency
|
||||
UpdateAudioMetrics(convertAudioMetricsToUnified(metrics))
|
||||
}
|
||||
|
||||
// UpdateAudioInputMetrics updates the centralized audio input metrics
|
||||
func (mr *MetricsRegistry) UpdateAudioInputMetrics(metrics AudioInputMetrics) {
|
||||
mr.mu.Lock()
|
||||
mr.audioInputMetrics = metrics
|
||||
mr.lastUpdate = time.Now().Unix()
|
||||
mr.mu.Unlock()
|
||||
|
||||
// Update Prometheus metrics directly to avoid circular dependency
|
||||
UpdateMicrophoneMetrics(convertAudioInputMetricsToUnified(metrics))
|
||||
}
|
||||
|
||||
// UpdateAudioConfig updates the centralized audio configuration
|
||||
func (mr *MetricsRegistry) UpdateAudioConfig(config AudioConfig) {
|
||||
mr.mu.Lock()
|
||||
mr.audioConfig = config
|
||||
mr.lastUpdate = time.Now().Unix()
|
||||
mr.mu.Unlock()
|
||||
|
||||
// Update Prometheus metrics directly
|
||||
UpdateAudioConfigMetrics(config)
|
||||
}
|
||||
|
||||
// UpdateMicrophoneConfig updates the centralized microphone configuration
|
||||
func (mr *MetricsRegistry) UpdateMicrophoneConfig(config AudioConfig) {
|
||||
mr.mu.Lock()
|
||||
mr.microphoneConfig = config
|
||||
mr.lastUpdate = time.Now().Unix()
|
||||
mr.mu.Unlock()
|
||||
|
||||
// Update Prometheus metrics directly
|
||||
UpdateMicrophoneConfigMetrics(config)
|
||||
}
|
||||
|
||||
// GetAudioMetrics returns the current audio output metrics
|
||||
func (mr *MetricsRegistry) GetAudioMetrics() AudioMetrics {
|
||||
mr.mu.RLock()
|
||||
defer mr.mu.RUnlock()
|
||||
return mr.audioMetrics
|
||||
}
|
||||
|
||||
// GetAudioInputMetrics returns the current audio input metrics
|
||||
func (mr *MetricsRegistry) GetAudioInputMetrics() AudioInputMetrics {
|
||||
mr.mu.RLock()
|
||||
defer mr.mu.RUnlock()
|
||||
return mr.audioInputMetrics
|
||||
}
|
||||
|
||||
// GetAudioConfig returns the current audio configuration
|
||||
func (mr *MetricsRegistry) GetAudioConfig() AudioConfig {
|
||||
mr.mu.RLock()
|
||||
defer mr.mu.RUnlock()
|
||||
return mr.audioConfig
|
||||
}
|
||||
|
||||
// GetMicrophoneConfig returns the current microphone configuration
|
||||
func (mr *MetricsRegistry) GetMicrophoneConfig() AudioConfig {
|
||||
mr.mu.RLock()
|
||||
defer mr.mu.RUnlock()
|
||||
return mr.microphoneConfig
|
||||
}
|
||||
|
||||
// GetLastUpdate returns the timestamp of the last metrics update
|
||||
func (mr *MetricsRegistry) GetLastUpdate() time.Time {
|
||||
timestamp := atomic.LoadInt64(&mr.lastUpdate)
|
||||
return time.Unix(timestamp, 0)
|
||||
}
|
||||
|
||||
// StartMetricsCollector starts a background goroutine to collect metrics
|
||||
func (mr *MetricsRegistry) StartMetricsCollector() {
|
||||
go func() {
|
||||
ticker := time.NewTicker(1 * time.Second)
|
||||
defer ticker.Stop()
|
||||
|
||||
for range ticker.C {
|
||||
// Collect from session-specific manager if available
|
||||
if sessionProvider := GetSessionProvider(); sessionProvider != nil && sessionProvider.IsSessionActive() {
|
||||
if inputManager := sessionProvider.GetAudioInputManager(); inputManager != nil {
|
||||
metrics := inputManager.GetMetrics()
|
||||
mr.UpdateAudioInputMetrics(metrics)
|
||||
}
|
||||
} else {
|
||||
// Fallback to global manager if no session is active
|
||||
globalManager := getAudioInputManager()
|
||||
metrics := globalManager.GetMetrics()
|
||||
mr.UpdateAudioInputMetrics(metrics)
|
||||
}
|
||||
|
||||
// Collect audio output metrics directly from global metrics variable to avoid circular dependency
|
||||
audioMetrics := AudioMetrics{
|
||||
FramesReceived: atomic.LoadInt64(&metrics.FramesReceived),
|
||||
FramesDropped: atomic.LoadInt64(&metrics.FramesDropped),
|
||||
BytesProcessed: atomic.LoadInt64(&metrics.BytesProcessed),
|
||||
ConnectionDrops: atomic.LoadInt64(&metrics.ConnectionDrops),
|
||||
LastFrameTime: metrics.LastFrameTime,
|
||||
AverageLatency: metrics.AverageLatency,
|
||||
}
|
||||
mr.UpdateAudioMetrics(audioMetrics)
|
||||
|
||||
// Collect configuration directly from global variables to avoid circular dependency
|
||||
mr.UpdateAudioConfig(currentConfig)
|
||||
mr.UpdateMicrophoneConfig(currentMicrophoneConfig)
|
||||
}
|
||||
}()
|
||||
}
|
18
web.go
18
web.go
|
@ -212,7 +212,8 @@ func setupRouter() *gin.Engine {
|
|||
})
|
||||
|
||||
protected.GET("/audio/metrics", func(c *gin.Context) {
|
||||
metrics := audio.GetAudioMetrics()
|
||||
registry := audio.GetMetricsRegistry()
|
||||
metrics := registry.GetAudioMetrics()
|
||||
c.JSON(200, gin.H{
|
||||
"frames_received": metrics.FramesReceived,
|
||||
"frames_dropped": metrics.FramesDropped,
|
||||
|
@ -399,19 +400,8 @@ func setupRouter() *gin.Engine {
|
|||
})
|
||||
|
||||
protected.GET("/microphone/metrics", func(c *gin.Context) {
|
||||
if currentSession == nil || currentSession.AudioInputManager == nil {
|
||||
c.JSON(200, gin.H{
|
||||
"frames_sent": 0,
|
||||
"frames_dropped": 0,
|
||||
"bytes_processed": 0,
|
||||
"last_frame_time": "",
|
||||
"connection_drops": 0,
|
||||
"average_latency": "0.0ms",
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
metrics := currentSession.AudioInputManager.GetMetrics()
|
||||
registry := audio.GetMetricsRegistry()
|
||||
metrics := registry.GetAudioInputMetrics()
|
||||
c.JSON(200, gin.H{
|
||||
"frames_sent": metrics.FramesSent,
|
||||
"frames_dropped": metrics.FramesDropped,
|
||||
|
|
Loading…
Reference in New Issue