feat: add server log file management to performance settings - #3369
Conversation
Add API endpoints (GET/DELETE /api/performance/logs) to list and clean up server log files by count or by age. Track the active log file path in the logger to prevent deleting the currently open log. Add a management UI section in the performance settings page with log directory info, file statistics, and cleanup controls. Includes i18n translations for all supported languages (en, fr, ja, ru, vi, zh-CN, zh-TW).
WalkthroughAdds server log inspection and cleanup endpoints, exposes current active log path in the logger, registers new API routes, updates frontend settings to display/manage logs, and adds i18n strings across multiple locales for log-management UI. Changes
Sequence Diagram(s)sequenceDiagram
participant UI as Frontend UI
participant Router as API Router
participant Controller as Performance Controller
participant Logger as Logger
participant FS as File System
rect rgba(100,150,200,0.5)
Note over UI,FS: Get Log Files Flow
UI->>Router: GET /api/performance/logs
Router->>Controller: GetLogFiles()
Controller->>Logger: GetCurrentLogPath()
Logger-->>Controller: current log path
Controller->>FS: scan `common.LogDir`
FS-->>Controller: file list
Controller->>Controller: filter/sort/aggregate
Controller-->>Router: LogFilesResponse
Router-->>UI: {enabled,count,totalSize,files[]}
end
rect rgba(200,100,100,0.5)
Note over UI,FS: Cleanup Log Files Flow
UI->>Router: DELETE /api/performance/logs?mode=X&value=Y
Router->>Controller: CleanupLogFiles(mode,value)
Controller->>Logger: GetCurrentLogPath()
Logger-->>Controller: current log path
Controller->>FS: identify eligible files (exclude active)
Controller->>FS: delete files per policy
FS-->>Controller: deletion results (deleted, failed, freed bytes)
Controller-->>Router: cleanup response
Router-->>UI: {deleted_count,freed_bytes,failed[]}
UI->>Router: GET /api/performance/logs (refresh)
end
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes Possibly related PRs
Suggested reviewers
Poem
🚥 Pre-merge checks | ✅ 2 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
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. Comment |
There was a problem hiding this comment.
Actionable comments posted: 5
🧹 Nitpick comments (1)
controller/performance.go (1)
223-226: Sort the “keep latest N files” list byModTime, not filename.
by_countis defined in time terms (“最近”), but the implementation currently relies on lexicographicNameordering. That couples retention correctness to the log filename format and can keep older files if naming ever drifts.💡 Suggested adjustment
- // 按文件名降序排列(最新在前) + // 按修改时间降序排列(最新在前) sort.Slice(files, func(i, j int) bool { - return files[i].Name > files[j].Name + if files[i].ModTime.Equal(files[j].ModTime) { + return files[i].Name > files[j].Name + } + return files[i].ModTime.After(files[j].ModTime) })Also applies to: 293-305
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@controller/performance.go` around lines 223 - 226, The retention sorting currently orders the files slice by Name; change both sort.Slice usages to sort by modification time so we keep the most recent files by ModTime (newest first). Replace the comparison using files[i].Name > files[j].Name with one that compares modification timestamps (e.g., files[i].ModTime().After(files[j].ModTime()) or compare UnixNano) for the files slice used in the "keep latest N files" logic, and apply the same change in the second occurrence around the later block (the other sort.Slice call).
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@controller/performance.go`:
- Around line 319-340: The current delete loop in the performance cleanup
handler always returns success: true and an empty message even when some
deletions failed; update the response logic (around variables toDelete,
deletedCount, freedBytes, failedFiles) so that if len(failedFiles) > 0 the JSON
response either sets "success": false or sets a non-empty "message" describing
the partial failure and listing/counting failed files; ensure the response still
includes deleted_count, freed_bytes and failed_files so the caller can show an
error/warning toast in SettingsPerformance.jsx.
In `@logger/logger.go`:
- Around line 60-69: There is a race where
gin.DefaultWriter/gin.DefaultErrorWriter are swapped and the old file closed
without synchronizing concurrent writes from logHelper and common/sys_log.go;
add a package-level logWriterMu sync.RWMutex and use it to protect the
swap/close sequence and all read/write uses: in the swap code around
currentLogPath/currentLogFile and gin.DefaultWriter/gin.DefaultErrorWriter (the
block that currently uses currentLogPathMu) acquire logWriterMu.Lock() before
changing writers and closing oldFile and release after close, and in logHelper
(and the six direct writes in common/sys_log.go) wrap accesses to
gin.DefaultWriter/gin.DefaultErrorWriter and the actual fmt.Fprintf calls with
logWriterMu.RLock()/RUnlock() so writers cannot be closed while being used.
In `@web/src/i18n/locales/en.json`:
- Line 2775: Update the English translation for the key "请输入有效的数值" to use
numeric-specific wording: change the value from "Please enter a valid value" to
"Please enter a valid number" so numeric validation messages are precise (locate
the mapping with key "请输入有效的数值" in en.json and replace the string value).
In `@web/src/i18n/locales/fr.json`:
- Line 1210: The French locale entry for the cleanup success message only has a
single form for the key "已清理 {{count}} 个日志文件,释放 {{size}}" but
SettingsPerformance (SettingsPerformance.jsx) passes a numeric count, so you
must provide plural variants for that key; update fr.json to include singular
and plural (and other locale-specific plural forms if your i18n library requires
them) that interpolate both {{count}} and {{size}} (e.g., a singular form for
count==1 and a plural form for other counts) so deleting one file uses the
singular wording and multiple files use the plural wording.
In `@web/src/pages/Setting/Performance/SettingsPerformance.jsx`:
- Around line 177-185: The component currently treats an empty initial logInfo
as “logging disabled” because fetchLogInfo leaves state empty on errors; change
the logic so the UI only shows the “未启用” warning after a successful API response
that explicitly indicates logging is disabled — e.g., initialize logInfo to null
(or add an isLogInfoLoaded boolean), update fetchLogInfo (the async function) to
setLogInfo only on success and set the loaded flag on both success/failure, and
update the render condition to show the disabled message only when logInfo is
non-null and its property indicates disabled (or when isLogInfoLoaded is true
and the response says disabled). Ensure references to setLogInfo and
fetchLogInfo are updated accordingly.
---
Nitpick comments:
In `@controller/performance.go`:
- Around line 223-226: The retention sorting currently orders the files slice by
Name; change both sort.Slice usages to sort by modification time so we keep the
most recent files by ModTime (newest first). Replace the comparison using
files[i].Name > files[j].Name with one that compares modification timestamps
(e.g., files[i].ModTime().After(files[j].ModTime()) or compare UnixNano) for the
files slice used in the "keep latest N files" logic, and apply the same change
in the second occurrence around the later block (the other sort.Slice call).
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 27ef6d68-4496-4b6c-b511-e931727abd4c
📒 Files selected for processing (11)
controller/performance.gologger/logger.gorouter/api-router.goweb/src/i18n/locales/en.jsonweb/src/i18n/locales/fr.jsonweb/src/i18n/locales/ja.jsonweb/src/i18n/locales/ru.jsonweb/src/i18n/locales/vi.jsonweb/src/i18n/locales/zh-CN.jsonweb/src/i18n/locales/zh-TW.jsonweb/src/pages/Setting/Performance/SettingsPerformance.jsx
| "已添加到白名单": "Ajouté à la liste blanche", | ||
| "已清空": "Vidé", | ||
| "已清空测试结果": "Résultats de test effacés", | ||
| "已清理 {{count}} 个日志文件,释放 {{size}}": "{{count}} fichiers journaux nettoyés, {{size}} libérés", |
There was a problem hiding this comment.
Add plural variants for the cleanup success message.
This key already receives count from web/src/pages/Setting/Performance/SettingsPerformance.jsx Lines 201-203, but the French locale only defines one form. Deleting a single file will still render the plural wording here.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@web/src/i18n/locales/fr.json` at line 1210, The French locale entry for the
cleanup success message only has a single form for the key "已清理 {{count}}
个日志文件,释放 {{size}}" but SettingsPerformance (SettingsPerformance.jsx) passes a
numeric count, so you must provide plural variants for that key; update fr.json
to include singular and plural (and other locale-specific plural forms if your
i18n library requires them) that interpolate both {{count}} and {{size}} (e.g.,
a singular form for count==1 and a plural form for other counts) so deleting one
file uses the singular wording and multiple files use the plural wording.
| async function fetchLogInfo() { | ||
| try { | ||
| const res = await API.get('/api/performance/logs'); | ||
| if (res.data.success) { | ||
| setLogInfo(res.data.data); | ||
| } | ||
| } catch (error) { | ||
| console.error('Failed to fetch log info:', error); | ||
| } |
There was a problem hiding this comment.
Don’t render the “logging disabled” warning until the API has actually said so.
logInfo starts out empty, and fetchLogInfo() leaves it that way on request errors. The current fallback therefore shows the “未启用” warning during first load and after /api/performance/logs failures.
💡 Minimal fix
- {logInfo && logInfo.enabled ? (
+ {logInfo?.enabled ? (
<>
...
</>
- ) : (
+ ) : logInfo?.enabled === false ? (
<Banner
type='warning'
description={t('服务器日志功能未启用(未配置日志目录)')}
/>
)}Also applies to: 411-500
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@web/src/pages/Setting/Performance/SettingsPerformance.jsx` around lines 177 -
185, The component currently treats an empty initial logInfo as “logging
disabled” because fetchLogInfo leaves state empty on errors; change the logic so
the UI only shows the “未启用” warning after a successful API response that
explicitly indicates logging is disabled — e.g., initialize logInfo to null (or
add an isLogInfoLoaded boolean), update fetchLogInfo (the async function) to
setLogInfo only on success and set the loaded flag on both success/failure, and
update the render condition to show the disabled message only when logInfo is
non-null and its property indicates disabled (or when isLogInfoLoaded is true
and the response says disabled). Ensure references to setLogInfo and
fetchLogInfo are updated accordingly.
…issues - Fix data race on gin.DefaultWriter during log rotation by adding LogWriterMu - Report partial failure when some log files fail to delete instead of always returning success - Fix misleading "logging disabled" banner shown before API responds - Fix en.json translation for numeric validation message
There was a problem hiding this comment.
Actionable comments posted: 2
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@controller/performance.go`:
- Around line 291-331: The deletion logic records activeLogPath once via
logger.GetCurrentLogPath() and can race with logger.SetupLogger() rotation;
instead, ensure the active-path exclusion is checked atomically at remove time
by calling a logger helper that queries the current active path under the same
lock used in logger.SetupLogger() (e.g., add logger.IsActivePath(path) or
logger.GetCurrentLogPathLocked()) and use that check immediately before
os.Remove in the deletion loop (inside the for _, f := range toDelete loop) to
skip removing any file that is currently active; alternatively move the
active-path update into the same critical section as the writer swap in
logger.SetupLogger() so GetCurrentLogPath() cannot advance before writers are
swapped.
In `@web/src/pages/Setting/Performance/SettingsPerformance.jsx`:
- Around line 198-214: The log card isn't refreshed when DELETE
/api/performance/logs returns success: false but still deletes some files;
ensure fetchLogInfo() is always called after the request so counts/sizes update:
in the handler in SettingsPerformance.jsx (the block using fetchLogInfo,
showSuccess, showError, setLogCleanupLoading), move or add a call to
fetchLogInfo() so it runs for both the success and failure branches (or call it
in the finally block before setLogCleanupLoading(false)); optionally use
res.data.data.deleted_count/freed_bytes to include a partial-success message but
always invoke fetchLogInfo() to refresh the UI.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 95cc60e2-549b-477b-9d0f-eb41e0c0b376
📒 Files selected for processing (5)
common/sys_log.gocontroller/performance.gologger/logger.goweb/src/i18n/locales/en.jsonweb/src/pages/Setting/Performance/SettingsPerformance.jsx
✅ Files skipped from review due to trivial changes (1)
- web/src/i18n/locales/en.json
🚧 Files skipped from review as they are similar to previous changes (1)
- logger/logger.go
There was a problem hiding this comment.
🧹 Nitpick comments (1)
web/src/pages/Setting/Performance/SettingsPerformance.jsx (1)
189-192: Consider using strict equality for null check.Line 189 uses loose equality (
== null), which also matchesundefined. While this may be intentional givenInputNumbercan return either, using strict checks with explicit handling is clearer.♻️ Optional: Use explicit strict checks
- if (logCleanupValue == null || isNaN(logCleanupValue) || logCleanupValue < 1) { + if (logCleanupValue === null || logCleanupValue === undefined || isNaN(logCleanupValue) || logCleanupValue < 1) {Or use
Number.isNaN()which is stricter and handlesnull/undefinednaturally:- if (logCleanupValue == null || isNaN(logCleanupValue) || logCleanupValue < 1) { + if (logCleanupValue == null || !Number.isFinite(logCleanupValue) || logCleanupValue < 1) {🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@web/src/pages/Setting/Performance/SettingsPerformance.jsx` around lines 189 - 192, The null check on logCleanupValue uses loose equality (logCleanupValue == null) which also matches undefined; update the validation in the SettingsPerformance.jsx handler to use strict checks: explicitly test for logCleanupValue === null || logCleanupValue === undefined (or use a single undefined check if null is impossible), and replace isNaN(logCleanupValue) with Number.isNaN(logCleanupValue) to avoid coercion; keep the existing conditions (logCleanupValue < 1) and call showError(t(...)) and return when any of these stricter checks fail.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Nitpick comments:
In `@web/src/pages/Setting/Performance/SettingsPerformance.jsx`:
- Around line 189-192: The null check on logCleanupValue uses loose equality
(logCleanupValue == null) which also matches undefined; update the validation in
the SettingsPerformance.jsx handler to use strict checks: explicitly test for
logCleanupValue === null || logCleanupValue === undefined (or use a single
undefined check if null is impossible), and replace isNaN(logCleanupValue) with
Number.isNaN(logCleanupValue) to avoid coercion; keep the existing conditions
(logCleanupValue < 1) and call showError(t(...)) and return when any of these
stricter checks fail.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: d7218971-ab08-410e-9c6c-bdc3fd1c1e66
📒 Files selected for processing (1)
web/src/pages/Setting/Performance/SettingsPerformance.jsx
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (2)
web/src/pages/Setting/Performance/SettingsPerformance.jsx (2)
177-186: Consider surfacing API error state to the user.When the API returns
success: falseor throws an error,logInforemainsnulland the user sees a blank section with no indication of failure. While this gracefully hides the feature, it may be confusing if the log management capability exists but fails to load.A simple enhancement would be to track an error state to optionally show a brief message.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@web/src/pages/Setting/Performance/SettingsPerformance.jsx` around lines 177 - 186, fetchLogInfo currently swallows API failures and leaves logInfo null, producing a blank UI; add an error state (e.g. logError via useState) and update fetchLogInfo to set logError when res.data.success is false or inside the catch block (clear logInfo when error occurs), then update the component render logic to display a concise error message when logError is set (and optionally a retry button that calls fetchLogInfo); refer to fetchLogInfo, setLogInfo and the logInfo state to locate where to set/clear the new logError state and where to render the message.
468-477: Consider using CSS for vertical alignment instead of a hidden placeholder.The hidden
Textelement is a workaround for aligning the button with adjacent inputs. This can be achieved more cleanly with flexbox alignment on the parent container.♻️ Alternative approach using flexbox
- <Col xs={24} sm={12} md={8}> - <div style={{ marginBottom: 12 }}> - <Text - strong - style={{ - display: 'block', - marginBottom: 8, - visibility: 'hidden', - }} - > - - </Text> + <Col xs={24} sm={12} md={8} style={{ display: 'flex', alignItems: 'flex-end' }}> + <div style={{ marginBottom: 12 }}> <Popconfirm🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@web/src/pages/Setting/Performance/SettingsPerformance.jsx` around lines 468 - 477, Replace the hidden Text placeholder used to vertically align the button by applying flexbox alignment on the parent container: remove the Text element with style visibility: 'hidden' and instead set the parent wrapper (the element containing the inputs and the button in SettingsPerformance.jsx) to display: 'flex' with alignItems: 'center' (or an appropriate alignItems value) and gap/margin adjustments so the button lines up with adjacent inputs; update any inline styles or classNames accordingly so Button and Text components align without dummy elements.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@web/src/pages/Setting/Performance/SettingsPerformance.jsx`:
- Around line 424-431: The date-range rendering can produce "Invalid Date" if
logInfo.oldest_time or logInfo.newest_time are invalid; update the ternary that
builds the object for key t('日志时间范围') to validate both values (e.g. use
Date.parse(...) or new Date(...).toString() !== 'Invalid Date') before
formatting with toLocaleDateString(); if either date is invalid, show a safe
fallback (empty string or '-' or localized "未知") instead of calling
toLocaleDateString() directly so the UI never displays "Invalid Date".
---
Nitpick comments:
In `@web/src/pages/Setting/Performance/SettingsPerformance.jsx`:
- Around line 177-186: fetchLogInfo currently swallows API failures and leaves
logInfo null, producing a blank UI; add an error state (e.g. logError via
useState) and update fetchLogInfo to set logError when res.data.success is false
or inside the catch block (clear logInfo when error occurs), then update the
component render logic to display a concise error message when logError is set
(and optionally a retry button that calls fetchLogInfo); refer to fetchLogInfo,
setLogInfo and the logInfo state to locate where to set/clear the new logError
state and where to render the message.
- Around line 468-477: Replace the hidden Text placeholder used to vertically
align the button by applying flexbox alignment on the parent container: remove
the Text element with style visibility: 'hidden' and instead set the parent
wrapper (the element containing the inputs and the button in
SettingsPerformance.jsx) to display: 'flex' with alignItems: 'center' (or an
appropriate alignItems value) and gap/margin adjustments so the button lines up
with adjacent inputs; update any inline styles or classNames accordingly so
Button and Text components align without dummy elements.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 6a65f997-c65e-440f-b7ef-cf10a56f7cf1
📒 Files selected for processing (1)
web/src/pages/Setting/Performance/SettingsPerformance.jsx
| ...(logInfo.oldest_time && logInfo.newest_time | ||
| ? [ | ||
| { | ||
| key: t('日志时间范围'), | ||
| value: `${new Date(logInfo.oldest_time).toLocaleDateString()} ~ ${new Date(logInfo.newest_time).toLocaleDateString()}`, | ||
| }, | ||
| ] | ||
| : []), |
There was a problem hiding this comment.
Add defensive check for date parsing.
If oldest_time or newest_time contain invalid values, new Date(...).toLocaleDateString() will render "Invalid Date" in the UI. Consider validating the dates before displaying.
🛡️ Proposed defensive fix
- ...(logInfo.oldest_time && logInfo.newest_time
- ? [
- {
- key: t('日志时间范围'),
- value: `${new Date(logInfo.oldest_time).toLocaleDateString()} ~ ${new Date(logInfo.newest_time).toLocaleDateString()}`,
- },
- ]
- : []),
+ ...(() => {
+ const oldest = new Date(logInfo.oldest_time);
+ const newest = new Date(logInfo.newest_time);
+ if (logInfo.oldest_time && logInfo.newest_time && !isNaN(oldest) && !isNaN(newest)) {
+ return [{
+ key: t('日志时间范围'),
+ value: `${oldest.toLocaleDateString()} ~ ${newest.toLocaleDateString()}`,
+ }];
+ }
+ return [];
+ })(),📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| ...(logInfo.oldest_time && logInfo.newest_time | |
| ? [ | |
| { | |
| key: t('日志时间范围'), | |
| value: `${new Date(logInfo.oldest_time).toLocaleDateString()} ~ ${new Date(logInfo.newest_time).toLocaleDateString()}`, | |
| }, | |
| ] | |
| : []), | |
| ...((() => { | |
| const oldest = new Date(logInfo.oldest_time); | |
| const newest = new Date(logInfo.newest_time); | |
| if (logInfo.oldest_time && logInfo.newest_time && !isNaN(oldest) && !isNaN(newest)) { | |
| return [{ | |
| key: t('日志时间范围'), | |
| value: `${oldest.toLocaleDateString()} ~ ${newest.toLocaleDateString()}`, | |
| }]; | |
| } | |
| return []; | |
| })()), |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@web/src/pages/Setting/Performance/SettingsPerformance.jsx` around lines 424 -
431, The date-range rendering can produce "Invalid Date" if logInfo.oldest_time
or logInfo.newest_time are invalid; update the ternary that builds the object
for key t('日志时间范围') to validate both values (e.g. use Date.parse(...) or new
Date(...).toString() !== 'Invalid Date') before formatting with
toLocaleDateString(); if either date is invalid, show a safe fallback (empty
string or '-' or localized "未知") instead of calling toLocaleDateString()
directly so the UI never displays "Invalid Date".
commit dbf900a Author: CaIon <i@caion.me> Date: Wed Mar 25 00:04:01 2026 +0800 fix: restore doubao coding plan deprecation and regex ignored models lost during conflict resolution commit 7399e47 Author: CaIon <i@caion.me> Date: Tue Mar 24 23:56:10 2026 +0800 feat: add slide-in animations and update translations for new UI elements # Conflicts: # web/src/components/table/channels/modals/EditChannelModal.jsx commit a5e2026 Author: CaIon <i@caion.me> Date: Tue Mar 24 23:53:50 2026 +0800 security: harden Docker and release CI workflows - Pin all GitHub Actions to commit SHA to prevent supply chain attacks - Enable SLSA provenance attestation (mode=max) and SBOM generation - Add cosign keyless signing for Docker images via GitHub OIDC - Capture and output image digests to GitHub Job Summary - Pin Dockerfile base images to digest (bun:1, golang:1.26.1-alpine, debian:bookworm-slim) - Add SHA256 checksum generation for binary releases (Linux/macOS/Windows) - Update actions/checkout v3->v4, actions/setup-go v3->v5 in release.yml commit 9ae9040 Merge: 0191a68 ded4a12 Author: Calcium-Ion <i@caion.me> Date: Mon Mar 23 15:04:06 2026 +0800 Merge pull request QuantumNous#3401 from seefs001/fix/convert-openai-detail-field fix: the "detail" field is empty, an empty field was sent to upstream commit 0191a68 Merge: 16221f8 9ecad90 Author: Calcium-Ion <i@caion.me> Date: Mon Mar 23 15:03:57 2026 +0800 Merge pull request QuantumNous#3400 from seefs001/fix/openai-usage refactor: optimize billing flow for OpenAI-to-Anthropic convert commit 16221f8 Merge: 763c3ff 929b506 Author: Calcium-Ion <i@caion.me> Date: Mon Mar 23 15:03:47 2026 +0800 Merge pull request QuantumNous#3399 from seefs001/refactor/codex-usage Refactor/codex usage commit 763c3ff Merge: c667e47 e520977 Author: Calcium-Ion <i@caion.me> Date: Mon Mar 23 15:03:36 2026 +0800 Merge pull request QuantumNous#3331 from seefs001/fix/claude-beta-query fix: apply forced beta query at final upstream URL stage commit c667e47 Merge: 216b94d b09337e Author: Calcium-Ion <i@caion.me> Date: Mon Mar 23 15:03:23 2026 +0800 Merge pull request QuantumNous#3333 from seefs001/fix/channel-affinity-disable fix: honor channel affinity skip-retry when channel is disabled commit 216b94d Merge: 49eb533 e9f8f62 Author: Calcium-Ion <i@caion.me> Date: Mon Mar 23 15:03:01 2026 +0800 Merge pull request QuantumNous#3335 from seefs001/chore/adjuct-default-settings adjuct default settings commit 49eb533 Merge: 7693eda 45f65c2 Author: Calcium-Ion <i@caion.me> Date: Mon Mar 23 15:02:44 2026 +0800 Merge pull request QuantumNous#3381 from seefs001/feature/regex-ignored-upstream-models feat: support regex-prefixed ignored upstream models commit 7693eda Merge: d6982c8 f40eb4e Author: Calcium-Ion <i@caion.me> Date: Mon Mar 23 15:02:34 2026 +0800 Merge pull request QuantumNous#3393 from seefs001/fix/oauth-bind fix: oauth bind callback handling commit ded4a12 Author: Seefs <i@seefs.me> Date: Mon Mar 23 15:00:20 2026 +0800 fix: the "detail" field is empty, an empty field was sent to the upstream system. commit d6982c8 Merge: deff59a 6c074ef Author: Calcium-Ion <i@caion.me> Date: Mon Mar 23 14:53:13 2026 +0800 Merge pull request QuantumNous#3379 from seefs001/refactor/rm-coding-plan fix: disable doubao coding plan selection commit 9ecad90 Author: Seefs <i@seefs.me> Date: Mon Mar 23 14:22:12 2026 +0800 refactor: optimize billing flow for OpenAI-to-Anthropic convert commit 929b506 Author: Seefs <i@seefs.me> Date: Mon Mar 23 13:54:54 2026 +0800 refactor: simplify codex account modal and collapse raw json by default commit 755ece2 Author: Seefs <i@seefs.me> Date: Mon Mar 23 00:58:59 2026 +0800 refactor: simplify codex account modal and collapse raw json by default commit f40eb4e Author: Seefs <i@seefs.me> Date: Mon Mar 23 00:48:55 2026 +0800 fix: oauth bind callback handling commit 45f65c2 Author: Seefs <i@seefs.me> Date: Sun Mar 22 15:43:03 2026 +0800 feat: support regex-prefixed ignored upstream models commit 6c074ef Author: Seefs <i@seefs.me> Date: Sun Mar 22 15:01:09 2026 +0800 fix: disable doubao coding plan selection commit deff59a Author: CaIon <i@caion.me> Date: Sun Mar 22 13:55:03 2026 +0800 fix: increase StreamScannerMaxBufferMB limit and add handling for gpt-5.4-nano prefix commit 3c51608 Merge: 4d675b4 e80d867 Author: Seefs <40468931+seefs001@users.noreply.github.com> Date: Sun Mar 22 00:43:13 2026 +0800 Merge pull request QuantumNous#3360 from lcq225/docs/improve-bt-installation-guide docs: 完善宝塔面板部署教程并修复链接错误 commit 4d675b4 Merge: 87b426f 2c3ae32 Author: Seefs <40468931+seefs001@users.noreply.github.com> Date: Sun Mar 22 00:39:49 2026 +0800 Merge pull request QuantumNous#3357 from wenyifancc/cache_llama_cpp feat: Add support for counting cache-hit tokens in llama.cpp commit 87b426f Merge: 42846c6 49db514 Author: Seefs <40468931+seefs001@users.noreply.github.com> Date: Sun Mar 22 00:32:01 2026 +0800 Merge pull request QuantumNous#3369 from RedwindA/feat/logsManagement feat: add server log file management to performance settings commit 49db514 Author: RedwindA <austinaosid@gmail.com> Date: Sat Mar 21 21:48:31 2026 +0800 fix: align log cleanup button with other controls in the row commit 13122aa Author: RedwindA <austinaosid@gmail.com> Date: Sat Mar 21 21:11:52 2026 +0800 fix: refresh log info on partial delete failure commit dcd0911 Author: RedwindA <austinaosid@gmail.com> Date: Sat Mar 21 20:40:39 2026 +0800 fix: log management race condition, partial delete reporting, and UX issues - Fix data race on gin.DefaultWriter during log rotation by adding LogWriterMu - Report partial failure when some log files fail to delete instead of always returning success - Fix misleading "logging disabled" banner shown before API responds - Fix en.json translation for numeric validation message commit e904579 Author: RedwindA <austinaosid@gmail.com> Date: Sat Mar 21 20:06:49 2026 +0800 feat: add server log file management to performance settings Add API endpoints (GET/DELETE /api/performance/logs) to list and clean up server log files by count or by age. Track the active log file path in the logger to prevent deleting the currently open log. Add a management UI section in the performance settings page with log directory info, file statistics, and cleanup controls. Includes i18n translations for all supported languages (en, fr, ja, ru, vi, zh-CN, zh-TW). commit e80d867 Author: mm413 <lcq225@163.com> Date: Fri Mar 20 20:13:30 2026 +0800 Update docs/installation/BT.md Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> commit cf86fe5 Author: lcq225 <lcq225@163.com> Date: Fri Mar 20 20:06:09 2026 +0800 docs: 完善宝塔面板部署教程并修复链接错误 - 完善 docs/installation/BT.md,从 2 行扩展为完整教程 - 包含前置要求、安装步骤、配置说明、常见问题 - 修复 README.zh_CN.md 中的链接错误 - 所有内容基于官方文档 https://docs.newapi.pro 编写 commit 2c3ae32 Author: wenyifan <yifan.wen@eisgroup.com> Date: Fri Mar 20 16:48:04 2026 +0800 fix map commit 498199b Author: wenyifan <yifan.wen@eisgroup.com> Date: Fri Mar 20 16:38:48 2026 +0800 fix code quality commit ff29900 Author: wenyifan <yifan.wen@eisgroup.com> Date: Fri Mar 20 16:10:18 2026 +0800 feat: Add support for counting cache-hit tokens in llama.cpp OpenAI-Compatible API commit eff5185 Author: Seefs <i@seefs.me> Date: Fri Mar 20 16:00:36 2026 +0800 refactor: show codex account info tag and highlight plan type in usage modal commit e9f8f62 Author: Seefs <i@seefs.me> Date: Thu Mar 19 16:58:13 2026 +0800 fix: raise default overload disk threshold to 95% commit 5fe8e98 Author: Seefs <i@seefs.me> Date: Thu Mar 19 16:56:28 2026 +0800 fix: default codex and claude channel affinity templates to skip retry on failure commit e520977 Author: Seefs <i@seefs.me> Date: Thu Mar 19 15:49:50 2026 +0800 fix: apply forced beta query at final upstream URL stage commit b09337e Author: Seefs <i@seefs.me> Date: Wed Mar 18 16:08:31 2026 +0800 fix: honor channel affinity skip-retry when preferred channel is disabled
feat: add server log file management to performance settings
📝 变更描述 / Description
在性能设置中新增了服务器日志文件管理功能。后端新增两个 API:查询日志文件列表(
GET /performance/logs)和清理日志文件(DELETE /performance/logs),支持按文件数量保留和按天数保留两种清理模式,清理时会跳过当前正在写入的日志文件。前端在性能设置页面中新增日志管理卡片,展示日志目录、文件数 、总大小、时间范围等信息,并提供可视化的清理操作入口。🚀 变更类型 / Type of change
✅ 提交前检查项 / Checklist
📸 运行证明 / Proof of Work
开发环境:
PixPin_2026-03-21_19-56-39.mp4
容器环境:
PixPin_2026-03-21_20-04-05.mp4
Summary by CodeRabbit
New Features
New API
Bug Fixes / Reliability
Documentation