fix(logs): only report rotation when the log file actually shrank#74252
fix(logs): only report rotation when the log file actually shrank#74252BSG2000 wants to merge 2 commits intoopenclaw:mainfrom
Conversation
Greptile SummaryThis PR fixes a false-positive "file rotated" notice in Confidence Score: 5/5This PR is safe to merge — it is a minimal, well-reasoned semantic fix with no schema changes and new tests covering both affected paths. The change is a 5-line narrowing of when No files require special attention. Reviews (1): Last reviewed commit: "fix(logs): only report rotation when the..." | Re-trigger Greptile Re-review progress:
|
|
Codex review: needs real behavior proof before merge. Summary Reproducibility: yes. Source inspection on current main gives a high-confidence path: call Real behavior proof Next step before merge Security Review detailsBest possible solution: Merge the narrow semantic fix after the contributor adds observable after-fix proof and the exact-head required checks finish cleanly. Do we have a high-confidence way to reproduce the issue? Yes. Source inspection on current main gives a high-confidence path: call Is this the best way to solve the issue? Yes for the code direction. Removing What I checked:
Likely related people:
Remaining risk / open question:
Codex review notes: model gpt-5.5, reasoning high; reviewed against 64bbe96d8843. Re-review progress:
|
d0ebb87 to
965f4e5
Compare
|
Addressed @clawsweeper [P3] in f729cbc: added an |
f729cbc to
f6298d9
Compare
readLogSlice set both truncated and reset whenever the file grew faster than --max-bytes between polls, even though the cursor was still valid in that case. The CLI then printed 'Log cursor reset (file rotated).' to stderr on every burst, which was misleading: no rotation had occurred, the tail was just truncated to fit the byte budget. Tighten the contract so reset is set only when the file is shorter than the previously-returned cursor (the actual rotation/truncation signal). The fast-growth case keeps truncated: true, so callers still see the existing 'Log tail truncated (increase --max-bytes).' message without the spurious rotation notice. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…sage Address review feedback on PR openclaw#74252 (P3 from clawsweeper): add Unreleased > Fixes entry per CONTRIBUTING policy for user-facing fixes. No code change; log-tail.test.ts: 3/3 green. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
4868f27 to
fa08a97
Compare
PR title:
fix(logs): only report rotation when the log file actually shrankSummary
openclaw logs --followprintsLog cursor reset (file rotated).to stderr whenever the gateway log grows faster than--max-bytesbetween polls, even though no rotation has occurred — the cursor is still valid and the tail was just truncated to fit the byte budget.Log tail truncated (increase --max-bytes).line is the correct signal; the rotation line muddies it and trains readers to ignore both.src/logging/log-tail.ts::readLogSlice, only setreset = truein the true rotation case (cursor > size— the file shrank below the previous cursor). The fast-growth branch (size - start > maxBytes) now setstruncated = trueonly, since the cursor it returned remains contiguous with what the caller saw last poll.LogTailPayloadshape, the rotation-case behavior, theLog tail truncatedmessage, and the byte-budget arithmetic are all unchanged. No CLI strings, schema, or downstream consumers were modified —src/logging/diagnostic-support-export.tsandsrc/cli/logs-cli.tscontinue to work with the same fields.Change Type (select all)
Scope (select all touched areas)
Linked Issue/PR
cron add/cron editwith invalid--cronexpression logs gateway error and returnsUNAVAILABLEinstead ofINVALID_REQUEST(raw croner TypeError/RangeError leaks to CLI + log) #74066.Root Cause (if applicable)
readLogSliceconflated two situations into a singleresetflag:cursor > size— the previously-returned cursor is past EOF; the file was rotated/truncated, so the cursor is meaningless and we must restart from the new tail.size - start > maxBytes— the file grew faster than the per-poll byte budget; the cursor is still valid, we just can't read everything that was appended in one poll.Only case (1) is a real reset/rotation. Case (2) was incorrectly being flagged as "rotated" because both branches set
reset = true.log-tail.test.tsonly covered the redaction path; nothing pinned the meaning ofresetvstruncated.src/cli/logs-cli.ts:402) hard-codesLog cursor reset (file rotated).forpayload.reset, so the conflation surfaced as a misleading user-visible string rather than a silent boolean.Regression Test Plan (if applicable)
src/logging/log-tail.test.ts>> maxBytesbetween two polls with the same valid cursor →truncated: true,reset: false, lines returned.reset: true.readLogSliceboundary; both scenarios can be exercised end-to-end against a real temp log file using the existingsetLoggerOverridetest seam.User-visible / Behavior Changes
openclaw logs --follow(and JSON-mode--json) no longer emits theLog cursor reset (file rotated).notice during high-throughput writes. The existingLog tail truncated (increase --max-bytes).notice still fires in that case, which is the actionable signal. The notice still fires correctly when the log is genuinely rotated/truncated.Diagram (if applicable)
N/ASecurity Impact (required)
NoNoNoNoNoRepro + Verification
Environment
pnpm dev)Steps (to reproduce the original misleading notice on
main)openclaw status --watchagainst a busy gateway).openclaw logs --follow --max-bytes 4000.Expected
Only
Log tail truncated (increase --max-bytes).is printed to stderr while the burst is being caught up.Actual (before this PR)
Both
Log tail truncated (increase --max-bytes).andLog cursor reset (file rotated).are printed, even though the file was never rotated.After this PR
Only the truthful
Log tail truncatednotice is printed during fast growth. The rotation notice still fires when the file is actually rotated/truncated (covered by the second new test).Evidence
src/logging/log-tail.test.ts)Local verification:
Human Verification (required)
start = max(0, size - maxBytes)and reportstruncatedonly (unchanged); empty file still returnscursor: size, lines: [](unchanged); cursor inside[start, size]window withsize - start <= maxBytesis unchanged.Review Conversations
Compatibility / Migration
YesNoNoRisks and Mitigations
reset === trueto mean "skipped some lines" rather than "the cursor is no longer meaningful".payload.reset/LogTailPayload. The only consumers aresrc/cli/logs-cli.ts(renders the user-visible string this PR is correcting) andsrc/logging/diagnostic-support-export.ts::sanitizeLogTail(passes the boolean through verbatim into the support bundle). Both are display-only; neither usesresetto decide whether lines were skipped — they use the existingtruncatedflag for that.AI/Vibe-Coded PRs Welcome! 🤖
resetis asserted inreadLogSlice).codex review --base origin/mainnot run locally (no Codex access in this environment); happy to address Codex bot comments after the PR opens.