package logging import ( "bufio" "fmt" "os" "path/filepath" "sort" "time" ) type LogEntry struct { Path string ModTime time.Time Size int64 } func LogDir() string { home, err := os.UserHomeDir() if err != nil { return "" } return filepath.Join(home, ".config", "ai-agent", "logs") } func ListLogs(n int) ([]LogEntry, error) { return listLogsIn(LogDir(), n) } func listLogsIn(dir string, n int) ([]LogEntry, error) { entries, err := os.ReadDir(dir) if err != nil { return nil, fmt.Errorf("read log dir: %w", err) } var logs []LogEntry for _, e := range entries { if e.IsDir() { continue } info, err := e.Info() if err != nil { continue } logs = append(logs, LogEntry{ Path: filepath.Join(dir, e.Name()), ModTime: info.ModTime(), Size: info.Size(), }) } sort.Slice(logs, func(i, j int) bool { return logs[i].ModTime.After(logs[j].ModTime) }) if n > 0 && n < len(logs) { logs = logs[:n] } return logs, nil } func LatestLogPath() (string, error) { return latestLogPathIn(LogDir()) } func latestLogPathIn(dir string) (string, error) { logs, err := listLogsIn(dir, 1) if err != nil { return "", err } if len(logs) == 0 { return "", fmt.Errorf("no log files found in %s", dir) } return logs[0].Path, nil } func TailLog(path string, n int) ([]string, error) { f, err := os.Open(path) if err != nil { return nil, fmt.Errorf("open log: %w", err) } defer f.Close() var lines []string scanner := bufio.NewScanner(f) for scanner.Scan() { lines = append(lines, scanner.Text()) } if err := scanner.Err(); err != nil { return nil, fmt.Errorf("read log: %w", err) } if n > 0 && n < len(lines) { lines = lines[len(lines)-n:] } return lines, nil }