Add real-time log monitoring and system stats dashboard
Implements a comprehensive monitoring system for the admin interface: Backend: - New monitoring package with Redis ring buffer for log storage - Zerolog MultiWriter to capture logs to Redis - System stats collection (CPU, memory, disk, goroutines, GC) - HTTP metrics middleware (request counts, latency, error rates) - Asynq queue stats for worker process - WebSocket endpoint for real-time log streaming - Admin auth middleware now accepts token in query params (for WebSocket) Frontend: - New monitoring page with tabs (Overview, Logs, API Stats, Worker Stats) - Real-time log viewer with level filtering and search - System stats cards showing CPU, memory, goroutines, uptime - HTTP endpoint statistics table - Asynq queue depth visualization - Enable/disable monitoring toggle in settings Memory safeguards: - Max 200 unique endpoints tracked - Hourly stats reset to prevent unbounded growth - Max 1000 log entries in ring buffer - Max 1000 latency samples for P95 calculation 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -8,10 +8,12 @@ import (
|
||||
"syscall"
|
||||
|
||||
"github.com/hibiken/asynq"
|
||||
"github.com/redis/go-redis/v9"
|
||||
"github.com/rs/zerolog/log"
|
||||
|
||||
"github.com/treytartt/casera-api/internal/config"
|
||||
"github.com/treytartt/casera-api/internal/database"
|
||||
"github.com/treytartt/casera-api/internal/monitoring"
|
||||
"github.com/treytartt/casera-api/internal/push"
|
||||
"github.com/treytartt/casera-api/internal/repositories"
|
||||
"github.com/treytartt/casera-api/internal/services"
|
||||
@@ -70,6 +72,43 @@ func main() {
|
||||
log.Fatal().Err(err).Msg("Failed to parse Redis URL")
|
||||
}
|
||||
|
||||
// Initialize monitoring service (if Redis is available)
|
||||
var monitoringService *monitoring.Service
|
||||
redisClientOpt, ok := redisOpt.(asynq.RedisClientOpt)
|
||||
if ok {
|
||||
redisClient := redis.NewClient(&redis.Options{
|
||||
Addr: redisClientOpt.Addr,
|
||||
Password: redisClientOpt.Password,
|
||||
DB: redisClientOpt.DB,
|
||||
})
|
||||
|
||||
// Verify Redis connection
|
||||
if err := redisClient.Ping(context.Background()).Err(); err != nil {
|
||||
log.Warn().Err(err).Msg("Failed to connect to Redis for monitoring - monitoring disabled")
|
||||
} else {
|
||||
monitoringService = monitoring.NewService(monitoring.Config{
|
||||
Process: "worker",
|
||||
RedisClient: redisClient,
|
||||
DB: db, // Pass database for enable_monitoring setting sync
|
||||
})
|
||||
|
||||
// Reinitialize logger with monitoring writer
|
||||
utils.InitLoggerWithWriter(cfg.Server.Debug, monitoringService.LogWriter())
|
||||
|
||||
// Create Asynq inspector for queue statistics
|
||||
inspector := asynq.NewInspector(redisOpt)
|
||||
monitoringService.SetAsynqInspector(inspector)
|
||||
|
||||
// Start stats collection
|
||||
monitoringService.Start()
|
||||
defer monitoringService.Stop()
|
||||
|
||||
log.Info().
|
||||
Bool("log_capture_enabled", monitoringService.IsEnabled()).
|
||||
Msg("Monitoring service initialized")
|
||||
}
|
||||
}
|
||||
|
||||
// Create Asynq server
|
||||
srv := asynq.NewServer(
|
||||
redisOpt,
|
||||
|
||||
Reference in New Issue
Block a user