Skip to content

fix: query_backtest_logs/query_component_logs level 双向 lower 归一#6430

Merged
Kaoruha merged 1 commit into
masterfrom
6433-fix/log-query-level-case
Jun 28, 2026
Merged

fix: query_backtest_logs/query_component_logs level 双向 lower 归一#6430
Kaoruha merged 1 commit into
masterfrom
6433-fix/log-query-level-case

Conversation

@Kaoruha

@Kaoruha Kaoruha commented Jun 24, 2026

Copy link
Copy Markdown
Owner

Summary

补全 #6232(search_logs level 双向 lower 修复)遗漏的同源方法:query_backtest_logs / query_component_logs 的 level 过滤仍是单边 level.upper(),传 "ERROR" 匹配不到 ClickHouse 小写 "error" 存储,按级别过滤漏数据。

根因

ClickHouse ginkgo_logs_backtest / ginkgo_logs_componentlevel混大小写存储(Master 大写 / Test 混 / 新写入小写),而 ClickHouse == 大小写敏感。单边 level.upper() 只匹配大写存储,漏掉小写那部分。search_logs 已由 #6232 用双向 func.lower(model.level) == level.lower() 修复,这两个同源方法遗漏。

修改

src/ginkgo/services/logging/log_service.py 两处(对齐 search_logs L403 范式):

  • query_backtest_logs: MBacktestLog.level == level.upper()func.lower(MBacktestLog.level) == level.lower()
  • query_component_logs: MComponentLog.level == level.upper()func.lower(MComponentLog.level) == level.lower()

Test plan

TDD RED→GREEN(tests/unit/services/logging/test_log_service_level_case.py):

  • object.__new__ 装配 LogService 避开 DB 连接,mock session 捕获 execute 收到的 query
  • 编译 WHERE clause(literal_binds),三断言交叉锁区分单边 .upper() 与双向 func.lower
    1. lower( 函数名存在(列侧归一)
    2. 参数小写 'error'(参数侧归一)
    3. 参数非大写 'ERROR'(反向锁)
  • 回归锁:level=None 不注入级别过滤

三层冒烟全绿:

  • L1 py_compile (src+api) ✅
  • L2 启动路径 (user_crud_mock + containers + user_cli) ✅
  • L3 log_service 回归 39 passed(新建 3 + like_escape 7 + L2 启动 29)零回归 ✅

关联

相关 issue #5511#6222 review 要求一并修同源 query_logs;#6232 已修 search_logs)。本 PR 补全遗漏的 query_logs 部分,不重复 #6232 已做的 search_logs 修复。

🤖 Generated with Claude Code

@Kaoruha

Kaoruha commented Jun 24, 2026

Copy link
Copy Markdown
Owner Author

Code review

No issues found in the two methods this PR targets. Checked for bugs and CLAUDE.md compliance. One out-of-scope same-root bug noted below (non-blocking, follow-up recommended).

Verified(补全 #6232 search_logs 双向 lower 范式遗漏的同源方法 query_backtest_logs / query_component_logs):

  • 切片定位准确(非重复)fix: 日志告警漏报与通知内容注入修复 (#5511, #5556) #6222(OPEN)、fix: LogService.search_logs 扩展 level/time 过滤,修复告警静默归零 (#5553) #6193(OPEN) 均改 log_service.py 但只动 search_logs(L340-379),亲验 gh pr diff 6222/6193 -- log_service.py | grep query_backtest_logs|query_component_logs|level.upper|func.lower ——与本 PR 的 query_logs(L113/L183) hunk 不重叠,非重复。本 PR 是 fix: 日志告警漏报与通知内容注入修复 (#5511, #5556) #6222 review 评论要求的同源 follow-up(fix: 日志告警漏报与通知内容注入修复 (#5511, #5556) #6222 改 alert_service + search_logs,未碰 query_logs)
  • 【linchpin P0】修复范式逐字符对齐 fix(data,logging): DI 容器错注入 + search_logs 签名缺过滤 #6232:亲验 master search_logs L407 是 func.lower(model.level) == level.lower(),本 PR 两处 func.lower(MBacktestLog.level) == level.lower() / func.lower(MComponentLog.level) == level.lower() 与之列侧 func.lower + 参数侧 .lower() 双向归一完全一致func 已在 L7 import,无新增导入风险
  • 根因正确(非创可贴):level 混大小写由双写入路径造成(logger.py:744 level_map 映射小写 vs log_ingester.py:143 fallback "INFO" 大写),列是 String 非枚举无归一约束。func.lower 查询端双向归一是 fix(data,logging): DI 容器错注入 + search_logs 签名缺过滤 #6232 确立的项目级范式,根治大小写敏感 ==
  • 既有调用方无回归:亲验 4 调用点——portfolio_service:1320 不传 level(不受影响);logging_cli:199 传 level.upper() 修复后侧再 .lower() 归一(冗余往返但语义正确);logging_cli:263 view_errors 传字面量 "ERROR"(修复后正好匹配小写存储,这就是 issue 核心场景);api/backtest:804 透传用户输入(修复后统一归一,仅增强)
  • 【P0】测试真实非假绿object.__new__(LogService) 装配避开 init 的 get_db_connection,mock _logger/_engine/_log_operation_* 全覆盖方法体 self.* 访问。变异测试思维核验——代码回退为单边 level.upper() 时三断言(lower( 存在 + 参数 'error' 小写 + 反向锁参数非 'ERROR'全 FAIL,修复版全 PASS,区分有效。_compiled_sql 刻意保留原始大小写(参数字面量断言用原 sql 非 .lower()),落实防假绿
  • CLAUDE.md 合规:分层不违规(Service 层既有 select(Model) 模式,仅改 WHERE);未触碰 Base 类(object.new 是测试装配技巧);测试位置 tests/unit/services/logging/ 合规;非 sed 批量(2 处手工)

⚠️ 显著附注(范围外同源 bug,非本 PR 阻塞项,建议 follow-up)

#6222 review 评论同时点名的第三处同源 bug 未覆盖——get_error_statsMBacktestLog.level.in_(['ERROR', 'CRITICAL']) 硬编码大写字面量,对混大小写存储同样失效(小写 'error'/'critical' 不被 IN ('ERROR','CRITICAL') 匹配 → 错误统计偏低 → 告警静默风险,正是 #5511/#5556 根因域)。

with self._engine.get_session() as session:
# 查询 ERROR 和 CRITICAL 级别的日志
conditions = [
MBacktestLog.timestamp >= start_time,
MBacktestLog.level.in_(['ERROR', 'CRITICAL'])
]

本 PR 标题/body 明确限定 query_backtest_logs/query_component_logs,get_error_stats 是第三个独立方法,不修不构成本 PR 缺陷。但为闭环 level 大小写问题,建议:要么本 PR 扩展范围一并改为 func.lower(MBacktestLog.level).in_(['error', 'critical']),要么开 follow-up issue 追踪。

🤖 Generated with Claude Code

- If this code review was useful, please react with 👍. Otherwise, react with 👎.

ClickHouse level 列混大小写存储,== 大小写敏感。query_backtest_logs /
query_component_logs 的单边 level.upper() 传 "ERROR" 匹配不到小写 "error"
存储,按级别过滤漏数据。

对齐 search_logs(已修)范式:func.lower(model.level) == level.lower()。

TDD: 3 测试 RED->GREEN(session mock 捕获 query 对象,编译 WHERE clause,
三断言交叉锁区分单边 .upper() 与双向 func.lower)。

三层冒烟:L1 py_compile / L2 启动路径 / L3 log_service 回归 39 passed 零回归。
@Kaoruha Kaoruha force-pushed the 6433-fix/log-query-level-case branch from 042d624 to 0b99825 Compare June 27, 2026 17:16
@Kaoruha Kaoruha merged commit 1550581 into master Jun 28, 2026
2 checks passed
@Kaoruha Kaoruha deleted the 6433-fix/log-query-level-case branch June 28, 2026 02:57
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.

1 participant