Skip to content

perf(logs): poll request history incrementally - #3250

Draft
chilung-cgu wants to merge 2 commits into
lidge-jun:devfrom
chilung-cgu:codex/perf-dashboard-log-delta
Draft

perf(logs): poll request history incrementally#3250
chilung-cgu wants to merge 2 commits into
lidge-jun:devfrom
chilung-cgu:codex/perf-dashboard-log-delta

Conversation

@chilung-cgu

@chilung-cgu chilung-cgu commented Sep 2, 2026

Copy link
Copy Markdown
Contributor

Summary

Replace 2,000-row full snapshot polling on GET /api/logs with a backward-compatible opaque cursor delta protocol:

  • Server-side Delta Slicing: GET /api/logs?cursor=<opaque> decodes a safe base64url cursor ({ v: 1, t: timestamp, id: requestId }), matches against the in-memory log ring, and returns only entries appended since the cursor along with additive metadata (cursor, reset: boolean).
  • Self-Healing Recovery: If a cursor is evicted (due to high traffic or proxy restart), the server returns the full window with reset: true so the client transparently resets without losing data.
  • Fail-Closed Validation: Malformed or type-confused cursor parameters return HTTP 400 invalid_cursor.
  • Client Delta Merge: GUI Logs.tsx requests incremental deltas after the initial full fetch, merging new rows by requestId up to the 2,000-row cap, while falling back cleanly to full snapshots when talking to older servers.

Verification

Automated Test Gates

  • Focused Backend Tests:
    bun test tests/request-log-cursor.test.ts tests/management-api-logs-metrics.test.ts tests/request-log.test.ts
    # Result: 76 pass, 0 fail (343 expect() calls)
  • Focused GUI Tests:
    cd gui && bun test tests/log-poll.test.ts tests/logs-auto-refresh.test.tsx tests/client-resource-poll.test.tsx tests/visibility-poll.test.ts
    # Result: 38 pass, 0 fail (159 expect() calls)
  • Typecheck & Privacy Scan:
    bun run typecheck
    bun run privacy:scan
    # Result: TypeScript clean, Privacy scan passed
  • GUI Lint & Build:
    cd gui && bun run lint && bun run build
    # Result: oxlint clean, Vite production bundle built successfully
  • Import-Connected Test Suite:
    bun run test:changed
    # Result: 2999 pass, 0 fail across 167 files (22225 expect() calls)
  • Core-Lab Boundary & Repo Hygiene:
    bun test tests/core-lab-boundary.test.ts tests/repo-hygiene.test.ts
    # Result: 29 pass, 0 fail
  • Full GUI Test Suite:
    cd gui && bun test tests
    # Result: 1235 pass, 0 fail across 200 files (10637 expect() calls)

UI Verification

Visual layout, controls, filters, auto-refresh toggles, and detail dialogs remain bit-for-bit identical; network payload on background polling drops from ~7.3 MB per tick (full 2,000 DTOs) to < 1 KB (empty or incremental delta).

Checklist

  • Scope stays focused and avoids unrelated cleanup.
  • Docs or release notes were updated when needed.
  • Security-sensitive changes were reviewed for secrets, auth, and unsafe defaults.

Review readiness checklist

This PR stays in draft until every box below is ticked. Tick all four boxes once the requirements are met:

  • All CI tests are green on my local testing.

  • I pushed my PR to the latest dev commit.

  • I resolved all correct Codex and CodeRabbit findings.

  • My PR is ready for review.

@github-actions

github-actions Bot commented Sep 2, 2026

Copy link
Copy Markdown
Contributor

Deterministic PR hygiene checks passed.

@coderabbitai

coderabbitai Bot commented Sep 2, 2026

Copy link
Copy Markdown
Contributor

Important

Draft PR not reviewed

Draft PRs are not automatically reviewed by default.

  • Trigger a manual review

To automatically review draft PRs, update your CodeRabbit configuration:

reviews:
  auto_review:
    drafts: true

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@github-actions github-actions Bot added the enhancement New feature or request label Sep 2, 2026
@github-actions

github-actions Bot commented Sep 2, 2026

Copy link
Copy Markdown
Contributor

⏳ DRAFT

  • UI screenshot required.

What to do

  • Add a screenshot of the UI change to the PR description.
  • Tick all four boxes in the PR description once you're done (currently 0/4).

Review readiness checklist

  • ⬜ All CI tests are green on my local testing.
  • ⬜ I pushed my PR to the latest dev commit.
  • ⬜ I resolved all correct Codex and CodeRabbit findings.
  • ⬜ My PR is ready for review.

0/4 boxes ticked.

This pull request was already a draft. Its draft status will be preserved after every issue above is resolved.
@chilung-cgu Tick the boxes once your local CI is green, your branch is on the latest dev commit, and every correct Codex and CodeRabbit finding is resolved.

@lidge-jun

Copy link
Copy Markdown
Owner

리뷰 · 우선순위 56 / 80

이 PR은 대시보드 로그 화면이 매번 최대 2,000줄을 통째로 다시 받아오던 폴링을, 불투명 커서 기반 증분(delta) 읽기로 바꾸는 성능 개선이다. 지금 devsrc/server/management/logs-usage-routes.ts GET /api/logsgetRequestLogEntries() 전체를 필터·limit 해서 배열로만 돌려준다. GUI gui/src/pages/Logs.tsxlimit=2000 풀 스냅샷을 반복 fetch한다. 백그라운드 폴링 한 번에 수 MB가 나갈 수 있다.

서버 쪽은 새 파일 src/server/request-log-cursor.ts에서 { v:1, t, id }를 base64url로 인코딩·디코딩하고, 링에서 커서 위치 이후만 잘라 reset 플래그와 함께 돌려준다. 잘못된 커서는 HTTP 400 invalid_cursor로 닫고, 링에서 커서가 쫓겨나면 전체 창을 주며 reset: true로 클라이언트가 스스로 고치게 한다. 응답에 cursor / reset을 덧붙이되 기존 logs / total / timeZone 형태는 유지한다.

클라이언트는 gui/src/pages/log-poll.tsparseLogPollResponse / mergeLogDelta로 옛 서버(배열만 주는 경우)와 새 서버를 같이 처리한다. 첫 fetch는 풀 스냅샷, 이후에는 커서로 증분만 받아 requestId 기준으로 합치고 2,000줄 상한을 지킨다. 테스트가 백엔드·GUI 양쪽에 꽤 두껍다.

현재 HEAD 기준으로는 실사용 구멍이 아니라 대역폭/CPU 비용 줄이기다. 그래서 점수는 중간이다. 같은 주 Logs.tsx를 만지는 #3251(티어 확인 툴팁)과 충돌할 수 있다. types/config 분할과는 무관하고, Private Inference·암호화 V2 열차와도 겹치지 않는다. 아직 draft이고 준비 체크리스트가 비어 있다.

동작 설계(퇴거 시 reset, 잘못된 커서 400, 구서버 폴백)는 건전하다. 다만 필터+커서를 같이 쓰는 API 소비자는 total이 전체 링 기준이고 logs만 delta라는 점을 문서/주석으로 더 분명히 하는 편이 좋다. GUI 기본 경로는 클라이언트 필터라 당장 큰 문제는 아니다.

src/server/management/logs-usage-routes.ts - total은 여전히 전체 all 필터 카운트이고 logs만 delta 슬라이스다. 테스트가 의도한 동작이나, 외부 API 문서에 한 줄 없으면 헷갈릴 수 있음
gui/src/pages/Logs.tsx - #3251도 같은 파일을 수정함. 둘 다 랜딩하면 한쪽 리베이스 필요
gui/src/pages/log-poll.ts / mergeLogDelta - requestId가 없는 행은 중복 제거에서 빠질 수 있음. 현재 DTO는 id가 있어 실무 위험은 낮음
경로/심볼 - 서버가 항상 링의 최신 항목으로 새 커서를 주는지(필터와 무관)는 맞음. 필터만 바꾼 뒤 커서를 유지하는 외부 클라이언트가 빈 delta를 정상으로 볼 수 있으니 주석 권장
라인 - draft 체크리스트 미완료 (CI·dev 최신·CodeRabbit·ready)

메인테이너의 판단이 필요한 지점

너의 추천
닫지 않는다. enhancement로 유효하다. 다만 #3251보다 충돌 비용이 크니, #3251을 먼저 넣거나 이 PR을 #3251 이후 dev에 리베이스한 뒤 draft 해제·CI 그린 확인 후 머지한다. types/config 분할 때문에 버릴 대상은 아니다. 라벨은 유지하고 닫지 말 것.

이 댓글은 grok-bot이 작성했습니다

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants