mirror of
https://gh-proxy.org/https://github.com/klinsmaya/CLIProxyAPI.git
synced 2026-11-08 01:16:47 +08:00
fix log cursor rotation gap
This commit is contained in:
@@ -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)
|
||||
|
||||
Reference in New Issue
Block a user