Skip to content

Refine pipeline logging and add retention caps - #880

Closed
rdself wants to merge 1 commit into
cheaper-inference:mainfrom
rdself:coder/log-rotation-clean-followup
Closed

rdself wants to merge 1 commit into
cheaper-inference:mainfrom
rdself:coder/log-rotation-clean-followup

Conversation

@rdself

@rdself rdself commented Apr 1, 2026

Copy link
Copy Markdown
Contributor

Why this change

The unified logging upgrade is already on main, but there were still a few follow-up issues in the current logging flow:

  • request debugging still exposed a redundant SOURCE REQUEST stage
  • the request-log toggle text in the dashboard was longer and noisier than it needed to be
  • log retention only had time-based cleanup, so operators still had no simple way to cap how many rotated app logs or per-request call log artifacts could accumulate on disk

This PR tightens that behavior without changing the overall unified logging design that is already in place on main.

What changed

  • removed SOURCE REQUEST from newly captured pipeline payloads
  • removed the old 2_req_source.json translator whitelist entry
  • renamed the dashboard toggle from Detailed Logs to Pipeline Logs
  • removed the extra helper sentence under that toggle
  • added APP_LOG_MAX_FILES for rotated application log archives
  • added CALL_LOG_MAX_ENTRIES for per-request call log artifacts
  • kept the existing day-based retention behavior, with the new count cap applying alongside it
  • updated .env.example, README, CHANGELOG, and OpenAPI version-sync docs

Notes

  • this is a follow-up cleanup on top of the unified logging work already merged into main
  • old DATA_DIR/logs/ behavior is not being reintroduced or changed here
  • existing historical artifacts that already contain sourceRequest remain readable; new artifacts simply stop capturing that stage

Validation

  • npm run check:docs-sync
  • npm run typecheck:core
  • node --import tsx/esm --test tests/unit/call-log-file-rotation.test.mjs tests/unit/log-rotation.test.mjs tests/unit/call-log-cap.test.mjs tests/unit/log-retention.test.mjs tests/unit/console-log-levels.test.mjs

Repo baseline note

  • the current main branch also has an unrelated failure in tests/unit/copilot-usage.test.mjs (100 !== 60 in github copilot business seats infer business plan and hide unlimited buckets)
  • this PR does not touch Copilot usage logic and was validated with focused checks around the logging changes above

Copilot AI review requested due to automatic review settings April 1, 2026 00:51
Comment thread src/lib/usage/callLogs.ts
@@ -230,6 +230,7 @@ function writeCallArtifact(artifact: CallLogArtifact): string | null {
try {
fs.mkdirSync(path.dirname(absPath), { recursive: true });
fs.writeFileSync(absPath, JSON.stringify(artifact, null, 2));
rotateCallLogs();

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

WARNING: Performance concern - rotation and overflow cleanup runs synchronously after every artifact write. This includes retention-based directory cleanup and file count pruning, which could cause latency spikes under high request throughput.

Consider deferring the cleanup to a scheduled job or batching it (e.g., run cleanup every N writes or every X seconds).

@kilo-code-bot

kilo-code-bot Bot commented Apr 1, 2026 •

Copy link
Copy Markdown

Code Review Summary

Status: 1 Issue Found | Recommendation: Address before merge

Overview

Severity Count
CRITICAL 0
WARNING 1
SUGGESTION 0
Issue Details (click to expand)

WARNING

File Line Issue
src/lib/usage/callLogs.ts 233 Synchronous cleanup on every write can cause latency spikes
Other Observations (not in diff)
File Line Issue
N/A N/A No issues in unchanged code
Files Reviewed (12 files)
  • .env.example
  • CHANGELOG.md
  • README.md
  • src/lib/logEnv.ts
  • src/lib/logRotation.ts
  • src/lib/usage/callLogs.ts
  • src/shared/components/RequestLoggerDetail.tsx
  • src/shared/components/RequestLoggerV2.tsx
  • src/shared/validation/schemas.ts
  • tests/unit/call-log-cap.test.mjs
  • tests/unit/call-log-file-rotation.test.mjs
  • tests/unit/log-rotation.test.mjs

Analysis:

The PR correctly implements the follow-up cleanup tasks:

  • Removes SOURCE REQUEST from newly captured pipeline payloads
  • Removes the old 2_req_source.json translator whitelist entry
  • Renames the dashboard toggle from "Detailed Logs" to "Pipeline Logs"
  • Adds APP_LOG_MAX_FILES for rotated application log archives
  • Adds CALL_LOG_MAX_ENTRIES for per-request call log artifacts
  • Adds new cleanupOverflowLogs() and cleanupOverflowCallLogFiles() functions
  • Updates documentation and environment examples

The single warning is about the synchronous cleanup (rotateCallLogs()) running after every artifact write at line 233. This function performs directory cleanup and file count pruning on every request that persists to disk, which could cause latency spikes under high request throughput.


Fix these issues in Kilo Cloud

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request updates the logging system to version 3.4.0, introducing more granular control over log retention and rotation. Key changes include the removal of redundant 'Source Request' logs from the pipeline and UI, and the addition of new environment variables (APP_LOG_MAX_FILES, CALL_LOG_MAX_ENTRIES) to cap the total number of log files on disk. The rotation logic was updated for both application logs and call log artifacts, supported by new unit tests. Feedback highlights a performance concern regarding the synchronous execution of log rotation on every request and suggests optimizing the file pruning process by leveraging the existing database index instead of performing expensive disk scans.

Comment thread src/lib/usage/callLogs.ts
@@ -230,6 +230,7 @@ function writeCallArtifact(artifact: CallLogArtifact): string | null {
try {
fs.mkdirSync(path.dirname(absPath), { recursive: true });
fs.writeFileSync(absPath, JSON.stringify(artifact, null, 2));
rotateCallLogs();

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

Executing rotateCallLogs() synchronously on every request that persists to disk introduces a significant performance bottleneck. This function performs a full recursive scan of the call_logs directory (potentially thousands of files across multiple subdirectories) to enforce retention caps. In high-traffic scenarios, this will lead to substantial I/O overhead and increased request latency.

Consider moving this maintenance task to a background interval or a periodic schedule (e.g., once an hour) instead of running it on the hot path of every request.

Comment thread src/lib/usage/callLogs.ts
Comment on lines +321 to +341
const files = fs
.readdirSync(baseDir)
.flatMap((entry) => {
const entryPath = path.join(baseDir, entry);
try {
const stat = fs.statSync(entryPath);
if (!stat.isDirectory()) return [];

return fs
.readdirSync(entryPath)
.filter((file) => file.endsWith(".json"))
.map((file) => {
const filePath = path.join(entryPath, file);
const fileStat = fs.statSync(filePath);
return { filePath, mtimeMs: fileStat.mtimeMs };
});
} catch {
return [];
}
})
.sort((a, b) => b.mtimeMs - a.mtimeMs);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The implementation of cleanupOverflowCallLogFiles performs a full recursive scan of the disk (readdirSync + statSync on every file) to determine which files to prune. Since call logs are already indexed in the SQLite call_logs table, it would be much more efficient to query the database for the oldest entries exceeding the limit and delete those specific files. This would avoid expensive disk-crawling operations, especially as the number of logs approaches the 10,000 entry limit.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR refines the unified logging pipeline by removing the redundant SOURCE REQUEST stage, simplifying the dashboard toggle text, and adding count-based retention caps alongside existing time-based retention for both app logs and per-request call log artifacts.

Changes:

  • Removed sourceRequest/2_req_source.json from pipeline capture and related UI/API allowlists.
  • Added APP_LOG_MAX_FILES and CALL_LOG_MAX_ENTRIES env controls and implemented overflow cleanup logic.
  • Added unit tests covering log archive/file capping behavior.

Reviewed changes

Copilot reviewed 16 out of 16 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
tests/unit/log-rotation.test.mjs New unit tests for app log config parsing + retention/count cleanup behavior.
tests/unit/call-log-file-rotation.test.mjs New unit test ensuring call log pruning honors both retention days and max entries.
tests/unit/call-log-cap.test.mjs Asserts newly written artifacts no longer include sourceRequest.
src/shared/validation/schemas.ts Removes 2_req_source.json from translator filename validation.
src/shared/components/RequestLoggerV2.tsx Renames “Detailed Logs” → “Pipeline Logs” and simplifies UI copy.
src/shared/components/RequestLoggerDetail.tsx Removes “Source Request” section from the pipeline detail modal.
src/lib/usage/callLogs.ts Adds CALL_LOG_MAX_ENTRIES pruning + triggers rotation after artifact writes.
src/lib/logRotation.ts Adds APP_LOG_MAX_FILES and overflow cleanup for rotated app logs.
src/lib/logEnv.ts Adds env getters/defaults for APP_LOG_MAX_FILES and CALL_LOG_MAX_ENTRIES.
src/app/api/translator/save/route.ts Removes 2_req_source.json from server allowlist.
src/app/api/translator/load/route.ts Removes 2_req_source.json from server allowlist.
README.md Documents new env vars and updated rotation semantics.
docs/openapi.yaml Bumps OpenAPI version to 3.4.0.
CHANGELOG.md Notes follow-up logging cleanup and bumps release section to 3.4.0.
.env.example Updates logging env vars to the new APP_LOG_* / CALL_LOG_* model.
open-sse/utils/requestLogger.ts Removes sourceRequest payload capture and the logRawRequest method.
open-sse/handlers/chatCore.ts Stops emitting the redundant raw/source request stage into pipeline logs.
Comments suppressed due to low confidence (1)

src/shared/components/RequestLoggerDetail.tsx:102

  • The detail modal’s payloadSections list no longer includes sourceRequest, which means older call log artifacts that already have pipelinePayloads.sourceRequest will not display that stage in the UI. This conflicts with the PR note that historical artifacts remain readable. Consider rendering sourceRequest when present (or generating sections dynamically from keys) so older artifacts can still be fully inspected while new ones simply stop capturing it.
  const pipelinePayloads = detail?.pipelinePayloads || null;
  const payloadSections = pipelinePayloads
    ? [
        ["clientRawRequest", "Client Raw Request"],
        ["clientRequest", "Client Request"],
        ["openaiRequest", "OpenAI Request"],
        ["providerRequest", "Provider Request"],
        ["providerResponse", "Provider Response"],
        ["clientResponse", "Client Response"],
        ["error", "Pipeline Error"],
      ]

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread src/lib/usage/callLogs.ts
Comment on lines 230 to 234
try {
fs.mkdirSync(path.dirname(absPath), { recursive: true });
fs.writeFileSync(absPath, JSON.stringify(artifact, null, 2));
rotateCallLogs();
return relPath;

Copilot AI Apr 1, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

writeCallArtifact() now calls rotateCallLogs() after every artifact write. Since rotateCallLogs() + cleanupOverflowCallLogFiles() do synchronous directory scans + statSync over potentially many entries, this adds per-request filesystem work on the hot path and can increase request latency under load. Consider throttling/debouncing rotation (e.g., run at most once per N seconds / N writes), or moving pruning to a background interval/job so request handling isn’t blocked by cleanup.

Copilot uses AI. Check for mistakes.
Comment thread README.md
- **Translator Playground** — 4 debugging modes: Playground (format translation), Chat Tester (round-trip), Test Bench (batch), Live Monitor (real-time)
- **Request Telemetry** — p50/p95/p99 latency + X-Request-Id tracing
- **File-Based Logging with Rotation** — Console interceptor captures everything to JSON log with size-based rotation
- **File-Based Logging with Rotation** — App logs rotate by size, retention days, and archive count; call log artifacts rotate by retention days and file count

Copilot AI Apr 1, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This section documents the new rotation behavior, but other repo docs still describe the old request-logger pipeline/file layout (including 2_req_source.json and ENABLE_REQUEST_LOGS=true), e.g. docs/ARCHITECTURE.md and docs/CODEBASE_DOCUMENTATION.md. That drift can confuse operators upgrading to the unified logging model; please update or remove those older references (and any localized copies if applicable) to match the new pipeline stages and env var model.

Suggested change
- **File-Based Logging with Rotation** — App logs rotate by size, retention days, and archive count; call log artifacts rotate by retention days and file count
- **Unified File-Based Logging with Rotation** — Part of a single unified logging pipeline; app logs rotate by size, retention days, and archive count, and call log artifacts rotate by retention days and file count.
- **Modern Logging Env Vars** — Configurable via the unified logging env-var model; older request-logger files like `2_req_source.json` and the `ENABLE_REQUEST_LOGS` flag are no longer used and are superseded by this pipeline.

Copilot uses AI. Check for mistakes.
Comment on lines +19 to +23
process.env.APP_LOG_TO_FILE = "false";
process.env.APP_LOG_FILE_PATH = "/tmp/omniroute-test-app.log";
process.env.APP_LOG_MAX_FILE_SIZE = "64M";
process.env.APP_LOG_RETENTION_DAYS = "14";
process.env.APP_LOG_MAX_FILES = "12";

Copilot AI Apr 1, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This test hardcodes APP_LOG_FILE_PATH to /tmp/..., which will fail on Windows runners (no /tmp). Use os.tmpdir() + path.join(...) (or reuse the per-test temp dir pattern used below) to make the unit test cross-platform.

Copilot uses AI. Check for mistakes.
@diegosouzapw

Copy link
Copy Markdown
Collaborator

Merged manually into release/v3.4.2. Thanks for the contribution!

@rdself
rdself deleted the coder/log-rotation-clean-followup branch April 16, 2026 01:14
@diegosouzapw diegosouzapw mentioned this pull request Apr 22, 2026
This was referenced Apr 30, 2026
Poid-ZA pushed a commit to Poid-ZA/OmniRoute that referenced this pull request Aug 5, 2026
muhamadgalihsaputra pushed a commit to niyatna/NiyatnaRoute that referenced this pull request Sep 27, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants