fix log cursor rotation gap

This commit is contained in:
LTbinglingfeng
2026-06-15 18:37:21 +08:00
parent 5036513bf9
commit 0b21b07115
2 changed files with 89 additions and 3 deletions
+24 -3
View File
@@ -773,13 +773,34 @@ func locateLogCursorFile(files []string, cursor logCursor) (int, bool, error) {
if cursor.File != defaultLogFileName || (cursor.Offset == 0 && cursor.Size == 0 && !deferEmptyMainMatch) {
return 0, false, nil
}
if cursor.Offset == 0 && cursor.Size == 0 {
for i := range files {
if filepath.Base(files[i]) == defaultLogFileName {
continue
}
if !logFileChangedAfterCursor(files[i], cursor) {
continue
}
matches, truncated, errMatch := logFileMatchesCursor(files[i], cursor)
if errMatch != nil {
if errors.Is(errMatch, os.ErrNotExist) {
continue
}
return 0, false, errMatch
}
if truncated {
continue
}
if matches {
return i, true, nil
}
}
return 0, false, nil
}
for i := len(files) - 1; i >= 0; i-- {
if filepath.Base(files[i]) == defaultLogFileName {
continue
}
if cursor.Offset == 0 && cursor.Size == 0 && !logFileChangedAfterCursor(files[i], cursor) {
continue
}
matches, truncated, errMatch := logFileMatchesCursor(files[i], cursor)
if errMatch != nil {
if errors.Is(errMatch, os.ErrNotExist) {
@@ -474,6 +474,71 @@ func TestGetLogsZeroOffsetCursorWithEmptyFileReadsAcrossRotation(t *testing.T) {
}
}
func TestGetLogsZeroOffsetCursorWithEmptyFileReadsAcrossTwoRotations(t *testing.T) {
dir := t.TempDir()
writeMainLog(t, dir, "")
initial := performGetLogs(t, newLogsTestHandler(dir, true), "/v0/management/logs?limit=1")
if initial.NextCursor == "" {
t.Fatal("initial next-cursor is empty")
}
cursor, errCursor := decodeLogCursor(initial.NextCursor)
if errCursor != nil {
t.Fatalf("decode initial cursor: %v", errCursor)
}
if cursor.Offset != 0 || cursor.Size != 0 {
t.Fatalf("cursor offset/size = %d/%d, want empty zero offset", cursor.Offset, cursor.Size)
}
mainPath := filepath.Join(dir, defaultLogFileName)
firstRotatedPath := filepath.Join(dir, defaultLogFileName+".1")
secondRotatedPath := filepath.Join(dir, defaultLogFileName+".2")
firstModTime := time.Unix(0, cursorModTimeUnixNano(cursor)+int64(time.Second))
secondModTime := time.Unix(0, cursorModTimeUnixNano(cursor)+2*int64(time.Second))
appendMainLog(t, dir, "first\n")
if err := os.Chtimes(mainPath, firstModTime, firstModTime); err != nil {
t.Fatalf("update first main log mtime: %v", err)
}
if err := os.Rename(mainPath, firstRotatedPath); err != nil {
t.Fatalf("rotate first main log: %v", err)
}
writeMainLog(t, dir, "second\n")
if err := os.Chtimes(mainPath, secondModTime, secondModTime); err != nil {
t.Fatalf("update second main log mtime: %v", err)
}
if err := os.Rename(firstRotatedPath, secondRotatedPath); err != nil {
t.Fatalf("advance first rotated log: %v", err)
}
if err := os.Rename(mainPath, firstRotatedPath); err != nil {
t.Fatalf("rotate second main log: %v", err)
}
writeMainLog(t, dir, "third\n")
resp := performGetLogs(t, newLogsTestHandler(dir, true), "/v0/management/logs?cursor="+url.QueryEscape(initial.NextCursor)+"&limit=1")
if !reflect.DeepEqual(resp.Lines, []string{"first"}) {
t.Fatalf("lines = %#v, want oldest rotated line", resp.Lines)
}
if resp.CursorReset {
t.Fatal("cursor-reset = true, want false")
}
next := performGetLogs(t, newLogsTestHandler(dir, true), "/v0/management/logs?cursor="+url.QueryEscape(resp.NextCursor)+"&limit=1")
if !reflect.DeepEqual(next.Lines, []string{"second"}) {
t.Fatalf("next lines = %#v, want newer rotated line", next.Lines)
}
if next.CursorReset {
t.Fatal("next cursor-reset = true, want false")
}
latest := performGetLogs(t, newLogsTestHandler(dir, true), "/v0/management/logs?cursor="+url.QueryEscape(next.NextCursor)+"&limit=1")
if !reflect.DeepEqual(latest.Lines, []string{"third"}) {
t.Fatalf("latest lines = %#v, want main line", latest.Lines)
}
if latest.CursorReset {
t.Fatal("latest cursor-reset = true, want false")
}
}
func TestGetLogsZeroOffsetCursorWithEmptyFileResetsWhenRotationModTimeAmbiguous(t *testing.T) {
dir := t.TempDir()
mainPath := filepath.Join(dir, defaultLogFileName)