package cmd import ( "context" "fmt" "os" "text/tabwriter" "time" "github.com/spf13/cobra" "github.com/manalejandro/buque/internal/models" "github.com/manalejandro/buque/internal/stats" ) var statsCmd = &cobra.Command{ Use: "stats [environment]", Short: "Show container statistics", Long: `Display resource usage statistics for containers. If an environment is specified, shows only containers from that environment.`, RunE: func(cmd *cobra.Command, args []string) error { collector, err := stats.NewCollector() if err != nil { return err } defer collector.Close() ctx := context.Background() continuous, _ := cmd.Flags().GetBool("continuous") interval, _ := cmd.Flags().GetInt("interval") sortBy, _ := cmd.Flags().GetString("sort") if continuous { // Clear screen and show stats continuously fmt.Print("\033[2J") // Clear screen ticker := time.NewTicker(time.Duration(interval) * time.Second) defer ticker.Stop() for { select { case <-ctx.Done(): return nil case <-ticker.C: fmt.Print("\033[H") // Move cursor to home position if err := displayStats(ctx, collector, args, sortBy); err != nil { return err } fmt.Printf("\nRefreshing every %d seconds... (Press Ctrl+C to exit)\n", interval) } } } return displayStats(ctx, collector, args, sortBy) }, } func displayStats(ctx context.Context, collector *stats.Collector, args []string, sortBy string) error { var containerStats []models.ContainerStats var err error if len(args) > 0 { // Show stats for specific environment containerStats, err = collector.CollectForEnvironment(ctx, args[0]) } else { // Show stats for all containers containerStats, err = collector.CollectAll(ctx) } if err != nil { return err } if len(containerStats) == 0 { fmt.Println("No running containers found.") return nil } // Sort stats containerStats = collector.SortStats(containerStats, sortBy, true) // Display in table format w := tabwriter.NewWriter(os.Stdout, 0, 0, 3, ' ', 0) fmt.Fprintln(w, "CONTAINER\tENVIRONMENT\tCPU %\tMEMORY USAGE\tMEMORY %\tNET I/O\tBLOCK I/O") for _, stat := range containerStats { netIO := fmt.Sprintf("%s / %s", stats.FormatBytes(stat.NetworkRx), stats.FormatBytes(stat.NetworkTx)) blockIO := fmt.Sprintf("%s / %s", stats.FormatBytes(stat.BlockRead), stats.FormatBytes(stat.BlockWrite)) memUsage := fmt.Sprintf("%s / %s", stats.FormatBytes(stat.MemoryUsage), stats.FormatBytes(stat.MemoryLimit)) fmt.Fprintf(w, "%s\t%s\t%.2f%%\t%s\t%.2f%%\t%s\t%s\n", stat.Name, stat.Environment, stat.CPUPercentage, memUsage, stat.MemoryPercent, netIO, blockIO, ) } w.Flush() // Show aggregated stats aggStats, err := collector.GetAggregatedStats(ctx) if err == nil { fmt.Printf("\nTotal Containers: %d\n", aggStats.TotalContainers) fmt.Printf("Total CPU: %.2f%%\n", aggStats.TotalCPUPercent) fmt.Printf("Total Memory: %s / %s (%.2f%%)\n", stats.FormatBytes(aggStats.TotalMemoryUsage), stats.FormatBytes(aggStats.TotalMemoryLimit), aggStats.TotalMemoryPercent) fmt.Printf("Total Network: %s / %s\n", stats.FormatBytes(aggStats.TotalNetworkRx), stats.FormatBytes(aggStats.TotalNetworkTx)) } return nil } func init() { statsCmd.Flags().BoolP("continuous", "c", false, "Continuous monitoring mode") statsCmd.Flags().IntP("interval", "i", 2, "Refresh interval in seconds (for continuous mode)") statsCmd.Flags().StringP("sort", "s", "cpu", "Sort by: cpu, memory, network, name") }