Skip to content

fix(log): preserve quota in usage statistics - #7108

Merged
Calcium-Ion merged 2 commits into
QuantumNous:mainfrom
jimmyleocn:fix/preserve-usage-quota-stat
Aug 31, 2026
Merged

fix(log): preserve quota in usage statistics#7108
Calcium-Ion merged 2 commits into
QuantumNous:mainfrom
jimmyleocn:fix/preserve-usage-quota-stat

Conversation

@jimmyleocn

@jimmyleocn jimmyleocn commented Aug 31, 2026

Copy link
Copy Markdown
Contributor

Agent

  • Tool: Codex
  • Tool version: 0.150.1
  • Model (full id): gpt-5.6-sol
  • Host (CLI / IDE / GitHub coding agent / other): IDE
  • Date (UTC): 2026-08-31
  • AI assistance disclosure: 本变更由 AI 辅助定位、实现和验证,提交者已审阅代码及本 PR 描述,并对其准确性负责。

Links

User request

修复使用日志统计中 quota 始终为 0、但消费日志明细和 RPM/TPM 正常的问题,并确认问题存在于未修改的上游代码。

Out of scope — refuse

  • Matched: no
  • If yes, what was told to the user (stop here; do not open a PR): not applicable

本变更不涉及 Coding Plan、逆向渠道、第三方 API wrapper、Codex 协议、透传模式或第三方托管服务。

Kind

  • Bug fix
  • New feature
  • Performance / refactor
  • Docs
  • Other:

Issue facts

  • Actual behavior: /api/log/stat 返回的 quota 为 0,但 RPM/TPM、消费日志明细以及数据库中的 logs.quota 均为非零。
  • Impact: 管理员和用户会看到错误的用量汇总,可能误判为没有产生消费。底层消费日志和实际扣费数据没有丢失。
  • Frequency: 在当前 GORM v1.25.12 下,只要 quota 聚合结果非零并继续执行 RPM/TPM 扫描,该问题即可稳定复现。
  • Evidence that the problem is in new-api rather than the client or upstream:
    • 未修改的 upstream main 仍将两个不同投影的查询结果扫描到同一个 Stat
    • 数据库直接汇总 logs.quota 为非零,但统计接口返回的 data.quota 为 0。
    • 独立 GORM 最小复现证明第二次 Scan 会将第一次扫描得到的 Quota 清零。
    • 该统计流程不涉及上游模型请求。
  • Applicable types and their fields:
    • Relay: not applicable。
    • Billing: 消费日志和扣费记录正常,错误仅发生在只读统计结果。
    • Frontend: 前端直接显示统计接口返回的错误 quota;本 PR 不修改前端。
    • Deployment: 问题已在 PostgreSQL 部署中复现;回归测试使用 SQLite。

Change

SumUsedQuota 原先依次将 quota 查询和 RPM/TPM 查询扫描到同一个 Stat

tx.Scan(&stat)
rpmTpmQuery.Scan(&stat)

第一个查询只返回 quota,第二个查询只返回 rpmtpm。GORM v1.25.12 初始化第二次结构体扫描时会清零目标值,因此第一次查询写入的 Quota 被重置为 0。

本 PR 将 RPM/TPM 查询扫描到独立的局部结构体,然后只把 RpmTpm 赋回最终结果:

var rateStat struct {
    Rpm int
    Tpm int
}
rpmTpmQuery.Scan(&rateStat)
stat.Rpm = rateStat.Rpm
stat.Tpm = rateStat.Tpm

这样可以保留第一次聚合得到的 quota,同时维持原有 RPM/TPM 查询及最近 60 秒统计规则。

新增回归测试,验证一次统计请求能够同时返回正确的 quota、RPM 和 TPM。

Research

Duplicate / prior art

Docs and code

  • https://docs.newapi.ai/ : 未发现将使用日志 quota 汇总配置为 0 的选项或预期行为。
  • https://deepwiki.com/QuantumNous/new-api : 日志统计由后端接口提供 quota、RPM 和 TPM,没有要求存在消费记录时 quota 返回 0。
  • README / repo docs: 项目将用量统计和成本核算列为支持场景,没有与该现象对应的配置说明。
  • Code paths and what they imply for this change:
    • controller/log.goGetLogsStatGetLogsSelfStat 调用 model.SumUsedQuota
    • model/log.go:quota 查询和 RPM/TPM 查询原先扫描到同一个 Stat
    • web/src/features/usage-logs/api.ts:使用日志统计请求 /api/log/stat/api/log/self/stat
    • 前端直接使用接口返回的 quota,因此根因位于后端统计结果映射。

Alternatives considered

  • Option A: 使用独立的 RPM/TPM 结果结构体,再将两个字段赋回最终结果。
  • Option B: 使用条件聚合,将 quota 和最近 60 秒 RPM/TPM 合并为一条 SQL。
  • Why this approach: Option A 是最小、直接且跨数据库的正确性修复,不改变过滤条件和 RPM/TPM 最近 60 秒的业务语义。单查询性能优化应在独立 PR 中处理。

Files

Path Why
model/log.go 防止 RPM/TPM 查询覆盖已经聚合得到的 quota
model/log_stat_test.go 验证 quota、RPM 和 TPM 可以在同一次统计中正确返回

Behavior

Verification

Only what was actually run.

  • Commands and results:
    • go test ./model -run TestSumUsedQuotaPreservesQuotaWhenLoadingRateStats -count=1 -p 1 -parallel 1
      • PASS
    • go test ./model -count=1 -p 1 -parallel 1
      • PASS
    • go test ./controller -count=1 -p 1 -parallel 1
      • PASS
    • git diff --cached --check
      • PASS
    • GitNexus impact analysis:
      • Risk: LOW
      • Direct callers: GetLogsStat, GetLogsSelfStat
      • No affected execution flows detected
  • Manual steps and observed result:
    • 使用相同扫描结构分别测试 GORM v1.25.2v1.25.12
    • v1.25.2 第二次扫描后保留 Quota: 12345
    • v1.25.12 第二次扫描后将其重置为 Quota: 0
    • 改用独立 RPM/TPM 结构体后,回归测试得到 Quota: 12345Rpm: 1Tpm: 30
  • UI: 本 PR 不包含前端变更;问题及根因证据已记录在 bug: 使用日志顶部用量显示 ¥0,但消费明细 quota 非零 #7106
  • Tests added or updated, or why none:
    • 新增 TestSumUsedQuotaPreservesQuotaWhenLoadingRateStats
  • Databases / providers / platforms exercised:
    • SQLite:自动化回归测试。
    • PostgreSQL:Issue 中的实际问题复现环境。
    • Provider: not applicable。
    • Platform: Windows amd64 开发环境。

Risks

Scope check

  • Single focused change: yes
  • Secrets included: no
  • Out of scope (Coding Plan / reverse-engineered channel / third-party wrapper / Codex): no

Summary by CodeRabbit

  • Bug Fixes

    • Fixed quota reporting so logged quota values are preserved while request and token usage metrics are calculated.
    • Improved accuracy of aggregate usage statistics for matching consumption records.
  • Tests

    • Added coverage to verify quota, request, and token metrics are reported together correctly.

@coderabbitai

coderabbitai Bot commented Aug 31, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: d534e23b-9887-4be0-8576-4297e4111c09

📥 Commits

Reviewing files that changed from the base of the PR and between 2b6f1df and 96daf7a.

📒 Files selected for processing (2)
  • model/log.go
  • model/log_stat_test.go

Included review availability: Your plan provides up to 10 included reviews per hour; 9 remain after this review.


Walkthrough

SumUsedQuota now loads RPM and TPM into a separate structure, preserving the quota from the earlier query. A regression test verifies quota, RPM, and TPM values for matching consumption logs.

Changes

Quota statistics

Layer / File(s) Summary
Preserve quota during rate aggregation
model/log.go, model/log_stat_test.go
SumUsedQuota copies RPM and TPM from a local structure without overwriting quota. The test verifies all three returned values.

Estimated code review effort: 2 (Simple) | ~10 minutes

Merge Risk: ⚪ Minimal · up to 96daf

This change corrects usage statistics so quota is preserved while RPM and TPM remain available, without changing billing, authorization, logging, API shape, or deployment behavior. No actionable merge-blocking risk remains beyond normal checks and review.

Suggested reviewers: calcium-ion

Poem

A rabbit checked the quota stack
RPM and TPM came hopping back
The saved total stayed in sight
A test kept every number right
“No more zero,” whispered the night

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 2 functions across 2 files. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly describes the primary change: preserving quota in usage statistics.
Linked Issues check ✅ Passed The changes address issue #7106 by preventing the RPM/TPM query from overwriting the aggregated quota. The regression test verifies that quota, RPM, and TPM remain available together.
Out of Scope Changes check ✅ Passed The changes are limited to the usage-statistics aggregation fix and its regression test. No unrelated code changes are present.
  • Fix all pre-merge checks with AI
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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.

@Calcium-Ion
Calcium-Ion merged commit 8c8c415 into QuantumNous:main Aug 31, 2026
1 check was pending
ChinaToyHunter added a commit to ChinaToyHunter/new-api that referenced this pull request Sep 1, 2026
…tions

Upstream picks: quota preservation in usage stats (QuantumNous#7108), legacy token
key constraint migration, README Video API link fixes.

Conflict resolutions:
- model/log.go: combine both halves of the same double-Scan fix (fork
  scans quota into quotaStat, upstream scans rpm/tpm into rateStat)
- 6x README: keep fork condensed version (ours); upstream link fix
  targets the upstream doc list section that the fork README replaced

Co-Authored-By: Claude <noreply@anthropic.com>
drwoodck pushed a commit to drwoodck/new-api that referenced this pull request Sep 2, 2026
* fix(log): preserve quota in usage statistics
yiranxiaohui pushed a commit to yiranxiaohui/new-api that referenced this pull request Sep 2, 2026
* fix(log): preserve quota in usage statistics

(cherry picked from commit 8c8c415)
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.

bug: 使用日志顶部用量显示 ¥0,但消费明细 quota 非零

2 participants