on main help sign in
add ringbuffer tailing
commitbdeece2c5a3520aab7b511bc4c4fb72dacffb551 authorTai Groot <tai@taigrr.com> dateFri 11 Jul 2025, 12:12 (1 year ago) parentd031c54
2 files changed+63−1
cmd/logs.go+62 internal/config/load.go+1−1
cmd/logs.go+62
@@ -32,6 +32,11 @@ var logsCmd = &cobra.Command{
3232 return fmt.Errorf("failed to get follow flag: %v", err)
3333 }
3434
35+ tailLines, err := cmd.Flags().GetInt("tail")
36+ if err != nil {
37+ return fmt.Errorf("failed to get tail flag: %v", err)
38+ }
39+
3540 log.SetLevel(log.DebugLevel)
3641 // Configure log to output to stdout instead of stderr
3742 log.SetOutput(os.Stdout)
@@ -58,6 +63,15 @@ var logsCmd = &cobra.Command{
5863 for line := range t.Lines {
5964 printLogLine(line.Text)
6065 }
66+ } else if tailLines > 0 {
67+ // Tail mode - show last N lines
68+ lines, err := readLastNLines(logsFile, tailLines)
69+ if err != nil {
70+ return fmt.Errorf("failed to read last %d lines: %v", tailLines, err)
71+ }
72+ for _, line := range lines {
73+ printLogLine(line)
74+ }
6175 } else {
6276 // Oneshot mode - read the entire file once
6377 file, err := os.Open(logsFile)
@@ -88,9 +102,57 @@ var logsCmd = &cobra.Command{
88102
89103func init() {
90104 logsCmd.Flags().BoolP("follow", "f", false, "Follow log output")
105+ logsCmd.Flags().IntP("tail", "t", 0, "Show only the last N lines")
91106 rootCmd.AddCommand(logsCmd)
92107}
93108
109+// readLastNLines reads the last N lines from a file using a simple circular buffer approach
110+func readLastNLines(filename string, n int) ([]string, error) {
111+ file, err := os.Open(filename)
112+ if err != nil {
113+ return nil, err
114+ }
115+ defer file.Close()
116+
117+ // Use a circular buffer to keep only the last N lines
118+ lines := make([]string, n)
119+ count := 0
120+ index := 0
121+
122+ reader := bufio.NewReader(file)
123+ for {
124+ line, err := reader.ReadString('\n')
125+ if err != nil {
126+ if err == io.EOF && line != "" {
127+ // Handle last line without newline
128+ line = strings.TrimSuffix(line, "\n")
129+ lines[index] = line
130+ count++
131+ index = (index + 1) % n
132+ }
133+ break
134+ }
135+ // Remove trailing newline
136+ line = strings.TrimSuffix(line, "\n")
137+ lines[index] = line
138+ count++
139+ index = (index + 1) % n
140+ }
141+
142+ // Extract the last N lines in correct order
143+ if count <= n {
144+ // We have fewer lines than requested, return them all
145+ return lines[:count], nil
146+ }
147+
148+ // We have more lines than requested, extract from circular buffer
149+ result := make([]string, n)
150+ for i := range n {
151+ result[i] = lines[(index+i)%n]
152+ }
153+ return result, nil
154+}
155+
94156func printLogLine(lineText string) {
95157 var data map[string]any
96158 if err := json.Unmarshal([]byte(lineText), &data); err != nil {
internal/config/load.go+1−1
@@ -388,7 +388,7 @@ func (cfg *Config) configureSelectedModels(knownProviders []provider.Provider) e
388388 }
389389 model := cfg.GetModel(large.Provider, large.Model)
390390 slog.Info("Configuring selected large model", "provider", large.Provider, "model", large.Model)
391− slog.Info("MOdel configured", "model", model)
391+ slog.Info("Model configured", "model", model)
392392 if model == nil {
393393 large = defaultLarge
394394 // override the model type to large