Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions cmd/axis/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ func newRootCmd() *cobra.Command {
root.AddCommand(doctorCmd())
root.AddCommand(summaryCmd())
root.AddCommand(reservationsCmd())
root.AddCommand(observationsCmd())

ui.ApplyHelpTemplate(root)

Expand Down
231 changes: 231 additions & 0 deletions cmd/axis/observations.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,231 @@
package main

import (
"encoding/json"
"fmt"
"sort"
"strings"
"time"

"github.com/spf13/cobra"
"github.com/toasterbook88/axis/internal/models"
"github.com/toasterbook88/axis/internal/state"
"github.com/toasterbook88/axis/internal/ui"
)

var loadObservationsState = state.Load

func observationsCmd() *cobra.Command {
cmd := &cobra.Command{
Use: "observations",
Short: "Show execution observations tracked by the cluster",
RunE: func(cmd *cobra.Command, args []string) error {
return runObservationsLocal(cmd)
},
}
cmd.AddCommand(observationsListCmd())
cmd.AddCommand(observationsInspectCmd())
return cmd
}

func runObservationsLocal(cmd *cobra.Command) error {
st, err := loadObservationsState()
if err != nil {
return fmt.Errorf("loading state: %w", err)
}
if st == nil || len(st.Observations) == 0 {
fmt.Fprintln(cmd.OutOrStdout(), "No observations tracked")
return nil
}
entries := make([]models.ExecutionObservation, 0, len(st.Observations))
for _, obs := range st.Observations {
entries = append(entries, obs)
}
fmt.Fprint(cmd.OutOrStdout(), renderObservationTable(entries))
return nil
}

func renderObservationTable(entries []models.ExecutionObservation) string {
var b strings.Builder
sep := strings.Repeat("─", 90)
b.WriteString("\n")
ui.WhiteColor.Fprintf(&b, " EXECUTION OBSERVATIONS\n")
b.WriteString(" ")
b.WriteString(sep)
b.WriteString("\n")

if len(entries) == 0 {
ui.DimColor.Fprintf(&b, " No observations tracked\n\n")
return b.String()
}

ui.WhiteColor.Fprintf(&b, " %-15s %-12s %-12s %-12s %10s %10s %8s %8s\n",
"NODE", "WORKLOAD", "BACKEND", "TOOL", "WALL MS", "PEAK RAM", "PEAK VRAM", "SAMPLES")
Comment on lines +62 to +63
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.

medium

The header PEAK VRAM is 9 characters long, but the format specifier %8s is used. This will cause the column to be at least 9 characters wide anyway, potentially misaligning it with the data rows if they strictly follow the 8-character width. Additionally, for clarity, it would be beneficial to include units (MB) in the PEAK RAM header or values, similar to how VRAM is handled. Furthermore, per repository guidelines, if this list of observations can become excessively long, it should be truncated with an indication of the remaining count.

References
  1. When displaying a list of items in a user-facing message (e.g., warnings, logs), truncate the list if it can become excessively long and indicate that it has been truncated, for example by showing a count of the remaining items.

b.WriteString(" ")
b.WriteString(sep)
b.WriteString("\n")

display := entries
truncated := 0
if len(entries) > 50 {
display = entries[:50]
truncated = len(entries) - 50
}

for _, obs := range display {
peakVRAM := "-"
if obs.PeakVRAMMB > 0 {
peakVRAM = fmt.Sprintf("%d MB", obs.PeakVRAMMB)
}
success := ""
if !obs.LastSuccess {
success = ui.RedColor.Sprintf(" (last failed)")
}
fmt.Fprintf(&b, " %-15s %-12s %-12s %-12s %10d %10d %8s %8d%s\n",
obs.Scope.Node,
obs.Scope.Workload,
obs.Scope.Backend,
obs.Scope.Tool,
obs.WallTimeMS,
obs.PeakRAMMB,
peakVRAM,
obs.SampleCount,
success,
)
}

if truncated > 0 {
ui.DimColor.Fprintf(&b, "\n ... and %d more observations.\n", truncated)
}

b.WriteString("\n")
return b.String()
}

func observationsListCmd() *cobra.Command {
var format string

cmd := &cobra.Command{
Use: "list",
Short: "List execution observations from the local state ledger",
RunE: func(cmd *cobra.Command, args []string) error {
st, err := loadObservationsState()
if err != nil {
return fmt.Errorf("loading state: %w", err)
}

entries := make([]models.ExecutionObservation, 0, len(st.Observations))
for _, obs := range st.Observations {
entries = append(entries, obs)
}
sort.Slice(entries, func(i, j int) bool {
return entries[i].ObservedAt.After(entries[j].ObservedAt)
})

switch format {
case "json":
return json.NewEncoder(cmd.OutOrStdout()).Encode(entries)
default:
if len(entries) == 0 {
fmt.Fprintln(cmd.OutOrStdout(), "No observations tracked")
return nil
}
tbl := ui.NewTable("KEY", "NODE", "WORKLOAD", "BACKEND", "TOOL", "WALL MS", "PEAK RAM", "PEAK VRAM", "SAMPLES", "OBSERVED")
for _, obs := range entries {
key := state.ObservationKey(obs.Scope)
peakVRAM := "-"
if obs.PeakVRAMMB > 0 {
peakVRAM = fmt.Sprintf("%d MB", obs.PeakVRAMMB)
}
tbl.AddRow(
truncateID(key, 12),
obs.Scope.Node,
string(obs.Scope.Workload),
obs.Scope.Backend,
obs.Scope.Tool,
fmt.Sprintf("%d", obs.WallTimeMS),
fmt.Sprintf("%d MB", obs.PeakRAMMB),
peakVRAM,
fmt.Sprintf("%d", obs.SampleCount),
obs.ObservedAt.Format(time.RFC3339),
)
}
tbl.Render(cmd.OutOrStdout())
return nil
}
},
}
cmd.Flags().StringVar(&format, "format", "text", "Output format: text or json")
return cmd
}

func observationsInspectCmd() *cobra.Command {
var format string

cmd := &cobra.Command{
Use: "inspect <key>",
Short: "Show full details of an execution observation",
Args: cobra.ExactArgs(1),
RunE: func(cmd *cobra.Command, args []string) error {
key := args[0]
st, err := loadObservationsState()
if err != nil {
return fmt.Errorf("loading state: %w", err)
}

var found *models.ExecutionObservation
for k, obs := range st.Observations {
if k == key {
obsCopy := obs
found = &obsCopy
break
}
}
Comment on lines +177 to +183
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.

medium

This loop is unnecessary for an exact key lookup in a map. You can directly access the element using the key, which is more efficient ($O(1)$ vs $O(N)$).

if obs, ok := st.Observations[key]; ok {
	obsCopy := obs
	found = &obsCopy
}

if found == nil {
// Allow lookup by prefix for convenience.
for k, obs := range st.Observations {
if strings.HasPrefix(k, key) {
obsCopy := obs
found = &obsCopy
break
}
}
Comment on lines +186 to +192
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.

medium

Iterating over a map to find a prefix match is non-deterministic in Go because map iteration order is randomized. If multiple keys share the same prefix, the command will return a different observation each time it is run. Consider collecting all matches and returning an error if more than one is found, or sorting the keys before matching to ensure determinism.

}

if found == nil {
return ExitCodeError{Code: ExitErrGeneric, Message: fmt.Sprintf("observation %q not found", key)}
}

switch format {
case "json":
return json.NewEncoder(cmd.OutOrStdout()).Encode(found)
default:
out := cmd.OutOrStdout()
fmt.Fprintf(out, "Key: %s\n", state.ObservationKey(found.Scope))
fmt.Fprintf(out, "Node: %s\n", found.Scope.Node)
fmt.Fprintf(out, "Workload: %s\n", found.Scope.Workload)
fmt.Fprintf(out, "Backend: %s\n", found.Scope.Backend)
fmt.Fprintf(out, "Tool: %s\n", found.Scope.Tool)
if found.Scope.ModelName != "" {
fmt.Fprintf(out, "Model: %s\n", found.Scope.ModelName)
}
fmt.Fprintf(out, "Wall Time: %d ms\n", found.WallTimeMS)
fmt.Fprintf(out, "Peak RAM: %d MB\n", found.PeakRAMMB)
if found.PeakVRAMMB > 0 {
fmt.Fprintf(out, "Peak VRAM: %d MB\n", found.PeakVRAMMB)
}
fmt.Fprintf(out, "Samples: %d\n", found.SampleCount)
fmt.Fprintf(out, "Last Success:%v\n", found.LastSuccess)
fmt.Fprintf(out, "Observed At: %s\n", found.ObservedAt.Format(time.RFC3339))
isStale := ""
if !state.ObservationIsFresh(*found, time.Now().UTC()) {
isStale = " (stale)"
}
fmt.Fprintf(out, "Fresh: %v%s\n", state.ObservationIsFresh(*found, time.Now().UTC()), isStale)
Comment on lines +221 to +224
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.

medium

The function state.ObservationIsFresh is called twice with the same arguments. You can reuse the result of the first call to improve readability and slightly reduce overhead.

isFresh := state.ObservationIsFresh(*found, time.Now().UTC())
isStale := ""
if !isFresh {
	isStale = " (stale)"
}
fmt.Fprintf(out, "Fresh:       %v%s\n", isFresh, isStale)

return nil
}
},
}
cmd.Flags().StringVar(&format, "format", "text", "Output format: text or json")
return cmd
}
Loading