feat(logs): add limit query param to cap returned logs

This commit is contained in:
hkfires
2025-11-24 19:59:24 +08:00
parent 0a47b452e9
commit 943a8c74df

View File

@@ -58,8 +58,14 @@ func (h *Handler) GetLogs(c *gin.Context) {
return return
} }
limit, errLimit := parseLimit(c.Query("limit"))
if errLimit != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": fmt.Sprintf("invalid limit: %v", errLimit)})
return
}
cutoff := parseCutoff(c.Query("after")) cutoff := parseCutoff(c.Query("after"))
acc := newLogAccumulator(cutoff) acc := newLogAccumulator(cutoff, limit)
for i := range files { for i := range files {
if errProcess := acc.consumeFile(files[i]); errProcess != nil { if errProcess := acc.consumeFile(files[i]); errProcess != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": fmt.Sprintf("failed to read log file %s: %v", files[i], errProcess)}) c.JSON(http.StatusInternalServerError, gin.H{"error": fmt.Sprintf("failed to read log file %s: %v", files[i], errProcess)})
@@ -314,16 +320,22 @@ func (h *Handler) collectLogFiles(dir string) ([]string, error) {
type logAccumulator struct { type logAccumulator struct {
cutoff int64 cutoff int64
limit int
lines []string lines []string
total int total int
latest int64 latest int64
include bool include bool
} }
func newLogAccumulator(cutoff int64) *logAccumulator { func newLogAccumulator(cutoff int64, limit int) *logAccumulator {
capacity := 256
if limit > 0 && limit < capacity {
capacity = limit
}
return &logAccumulator{ return &logAccumulator{
cutoff: cutoff, cutoff: cutoff,
lines: make([]string, 0, 256), limit: limit,
lines: make([]string, 0, capacity),
} }
} }
@@ -361,12 +373,19 @@ func (acc *logAccumulator) addLine(raw string) {
if ts > 0 { if ts > 0 {
acc.include = acc.cutoff == 0 || ts > acc.cutoff acc.include = acc.cutoff == 0 || ts > acc.cutoff
if acc.cutoff == 0 || acc.include { if acc.cutoff == 0 || acc.include {
acc.lines = append(acc.lines, line) acc.append(line)
} }
return return
} }
if acc.cutoff == 0 || acc.include { if acc.cutoff == 0 || acc.include {
acc.lines = append(acc.lines, line) acc.append(line)
}
}
func (acc *logAccumulator) append(line string) {
acc.lines = append(acc.lines, line)
if acc.limit > 0 && len(acc.lines) > acc.limit {
acc.lines = acc.lines[len(acc.lines)-acc.limit:]
} }
} }
@@ -389,6 +408,21 @@ func parseCutoff(raw string) int64 {
return ts return ts
} }
func parseLimit(raw string) (int, error) {
value := strings.TrimSpace(raw)
if value == "" {
return 0, nil
}
limit, err := strconv.Atoi(value)
if err != nil {
return 0, fmt.Errorf("must be a positive integer")
}
if limit <= 0 {
return 0, fmt.Errorf("must be greater than zero")
}
return limit, nil
}
func parseTimestamp(line string) int64 { func parseTimestamp(line string) int64 {
if strings.HasPrefix(line, "[") { if strings.HasPrefix(line, "[") {
line = line[1:] line = line[1:]