news 2026/9/8 20:01:57

ClickHouse CI 集成测试排障指南:logs.tar.gz 产物包结构、按失败类型定位日志与精准解包方法

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
ClickHouse CI 集成测试排障指南:logs.tar.gz 产物包结构、按失败类型定位日志与精准解包方法

ClickHouse CI 集成测试排障指南:logs.tar.gz 产物包结构、按失败类型定位日志与精准解包方法

【免费下载链接】ClickHouseClickHouse® is a real-time analytics database management system项目地址: https://gitcode.com/GitHub_Trending/cli/ClickHouse

本文基于 ClickHouse 仓库investigate-ci技能中的集成测试产物文档,完整解析 CI 集成测试失败时的日志产物包logs.tar.gz:它的生成机制、压缩包内的目录布局、pytest_parallel.jsonl的结构化结果查询方法,以及按失败类型(断言错误、服务端异常、容器启动失败、执行轨迹)选取正确日志文件的实操流程。读完后,你将掌握从一份 CI 集成测试报告中快速下载产物包、只解压需要的成员、并用grep/jq精确定位失败根因的完整工作流,理解这些产物在 集成测试作业脚本 中是如何被收集和上传的。

一、产物包从哪里来:logs.tar.gz 的生成与上传机制

集成测试失败时的首要证据来源是logs.tar.gz产物包(在.claude/tools/fetch_ci_report.js使用--links参数时,会列在=== Artifact Links ===小节下)。下载它有两种方式:

  • fetch_ci_report.js --download-logs <path>参数直接下载到指定文件路径
  • 或直接用curl抓取--links输出中的 URL。

注意:压缩格式取决于文件大小。产物包本身始终是 tar 归档,但内部成员文件的压缩可能各不相同;更重要的是,产物包 URL 可能是logs.tar.gz也可能是logs.tar.zst(取决于大小)。应以--links输出的实际 URL 为准,并统一使用tar -xf(自动探测压缩格式)来解包,而不是写死tar -xzf

产物包由 on_error_hook 在作业出错时打包

从 集成测试作业脚本 的源码可以看到,main()一开始就为作业注册了一个on_error_hook(ci/jobs/integration_test_job.py#L1494-L1512),在硬性超时或作业出错时收集现场:

dmesg -T > ./ci/tmp/dmesg.log sudo chown -R $(id -u):$(id -g) ./tests/integration tar -czf ./ci/tmp/logs.tar.gz \ ./tests/integration/test_*/_instances*/ \ ./ci/tmp/*.log \ ./ci/tmp/*.jsonl || :

也就是说,产物包内容正好是三类:每个测试模块下 pytest 工作实例目录_instances*/(含各节点的 ClickHouse 服务器日志)、ci/tmp/下的全部.log(各 pytest 输出与作业日志)和全部.jsonl(结构化测试结果)。随后set_files()./ci/tmp/logs.tar.gz./ci/tmp/dmesg.log、dmesg 跟随日志和 docker-in-docker 日志 声明为要上传的附件(strict=False,缺失不致命)。这解释了产物包为什么以相对仓库根的路径(ci/tmp/...tests/integration/...)组织成员——tar 就是以相对路径./ci/tmp/...打进去的。

脚本中还有一处细节与排障相关:作业在收尾阶段会把失败测试的独立日志文件与logs.tar.gz一起附加上报(ci/jobs/integration_test_job.py#L2169),因此--links中除整包外可能还有零散的日志文件可直接抓取。

二、完整归档布局:Archive Layout

解包后,logs.tar.gz的内部布局如下(来自 产物文档):

ci/tmp/ pytest_parallel.jsonl # 结构化逐测试结果(每行一个 JSON 对象) pytest_parallel.log # 人类可读的合并输出 pytest_parallel-gw0.log # 逐 worker 输出:完整的 docker/cluster 调用 DEBUG 日志 pytest_parallel-gw1.log ... parallel.log # 顶层并行运行器日志 job.log # CI 作业脚本执行日志 docker-in-docker.log # Docker 守护进程输出 tests/integration/<test_module>/ _instances-conftest.py-gw<N>/ docker.log # 本 worker 的 docker compose up/down 输出 node1/logs/ clickhouse-server.log # node1 的 ClickHouse 服务器日志 clickhouse-server.err.log node2/logs/ clickhouse-server.log ...

各成员文件的来源可以在源码中找到对应关系:

  • ci/tmp/pytest_parallel.jsonl/pytest_parallel.log:由并行阶段调用run_pytest_and_collect_results(command=..., report_name="parallel", ...)产生(ci/jobs/integration_test_job.py 中并行批次以report_name="parallel"运行 pytest),report_name决定了ci/tmp/pytest_<report_name>.*系列文件的命名。
  • pytest_parallel-gw<N>.log:pytest-xdist 为每个 worker(gw0gw1、…)生成的独立日志。worker 数量由--dist=loadfile -n {workers}决定,而workers在脚本中按“每 worker 最多 5 核、11 GiB 内存”的预算模型推导(MAX_CPUS_PER_WORKER/MAX_MEM_PER_WORKER,见 ci/jobs/integration_test_job.py#L114-L115)。所以产物包里gw<N>的下标上限与作业跑在多大的 runner 上直接相关。
  • tests/integration/<test_module>/_instances-conftest.py-gw<N>/:pytest 为每个 worker 在测试模块目录下创建的 conftest 实例目录(目录名含conftest.py与 worker 编号),其中docker.log记录该 worker 的docker compose启停输出,node<M>/logs/clickhouse-server.log(及.err.log)则是该集群每个节点上 ClickHouse 服务进程的完整日志。
  • ci/tmp/docker-in-docker.log:CI 容器内嵌套启动 dockerd 的输出。脚本中常量DOCKER_IN_DOCKER_LOG = "./ci/tmp/docker-in-docker.log"(ci/jobs/integration_test_job.py#L66)声明了它的路径,start_docker_in_docker()docker_in_docker.sh的全部 stdout/stderr 重定向写入该文件;若 daemon 20 次docker info探测后仍无响应,会直接抛出 "Docker daemon didn't responded after 20 attempts" 并指向这个文件。

三、按失败类型选取关键文件

3.1 断言 / 结果错误(AssertionError、行数不对等)

首选pytest_parallel.jsonl——它是结构化的逐测试结果,每个失败一行 JSON。按测试名(nodeid)查询并抽取关键信息:

grep -F '<test_name>' "tmp/investigate/$SHA/ci/tmp/pytest_parallel.jsonl" \ | jq 'select(.outcome == "failed") | { crash: .longrepr.reprcrash.message, lines: [.longrepr.reprtraceback.reprentries[].data.lines[]?], stderr: (.sections[] | select(.[0] == "Captured stderr call") | .[1])?, captured: (.sections[] | select(.[0] == "Captured log call") | .[1])? }'

两个关键的字段陷阱:

  1. longrepr是 JSON 对象,不是字符串。断言文本在.longrepr.reprcrash.message,回溯逐行内容在.longrepr.reprtraceback.reprentries[].data.lines[]
  2. pytest 捕获的输出在.sections[],形如[标题, 内容]二元组,其中"Captured stderr call""Captured log call"两类标题分别包含 docker 调用、ClickHouse 查询、Spark 协议交互等测试期间捕获的 stderr 与日志。

另外,若只想粗看失败详情,可先拉出 longrepr 原文:

grep -F -- "<test_name>" "tmp/investigate/$SHA/ci/tmp/pytest_parallel.jsonl" \ | jq -r 'select((.longrepr // "") != "") | .longrepr'

必须使用grep -F(固定字符串匹配):参数化测试名如test_foo[a]含有正则元字符,普通grep不会按字面匹配。

3.2 服务端异常 / 数据错误

目标文件是各节点的服务器日志:

tests/integration/<test_module>/_instances-conftest.py-gw<N>/node<M>/logs/clickhouse-server.log

这是纯文本,位于归档内部。先只解压该成员再 grep:

tar -xf "tmp/investigate/$SHA/logs.tar.gz" -C "tmp/investigate/$SHA/" \ 'tests/integration/<test_module>/_instances-conftest.py-gw1/node1/logs/clickhouse-server.log' grep -i 'error\|exception\|fatal' \ "tmp/investigate/$SHA/tests/integration/<test_module>/_instances-conftest.py-gw1/node1/logs/clickhouse-server.log" \ | tail -50

注意<N>(worker 编号)和<M>(节点编号)都要替换成实际值;一次失败的集群往往有 node1/node2 等多个节点,跨节点问题(如分布式表、副本同步)需要对照多个节点的日志时间戳。

3.3 Docker / 容器启动失败

_instances-conftest.py-gw<N>/docker.log——这是该 worker 上docker compose up/down的原始输出,镜像拉取失败、端口冲突、compose 语法问题都会体现在这里。

结合 集成测试作业脚本 的源码可以推断出这类失败在 CI 侧的自动归类逻辑:脚本维护了一份基础设施错误模式表INFRASTRUCTURE_ERROR_PATTERNS(ci/jobs/integration_test_job.py#L639-L652),包括"Cannot connect to the Docker daemon""Error response from daemon""Connection reset by peer""No space left on device""OCI runtime create failed"等,以及超时模式"timed out after"/"TimeoutExpired"_mark_infrastructure_errors()(ci/jobs/integration_test_job.py#L796-L809)会扫描每个测试结果,命中这些模式的失败会被打上INFRA标签并改判为SKIPPED——也就是说,如果你在 CI 报告里看到失败被标记为基础设施错误而状态是 SKIPPED,真正的证据仍在产物包的docker.logdocker-in-docker.log里,而不是测试断言本身。

3.4 详细测试轨迹(哪些查询、以什么顺序执行)

定位执行该测试的 worker 日志:

grep -l '<test_name>' tmp/investigate/$SHA/ci/tmp/pytest_parallel-gw*.log

打开对应的pytest_parallel-gw<N>.log:它是该 worker 的完整 DEBUG 级输出,包含所有 docker/cluster 调用、下发的 SQL 及其顺序,适合回答"测试到底执行到了哪一步"这类问题。

四、只解压需要的成员,不全量解包

产物包可能很大(源码注释中提到一次普通归档约为 413 MiB 量级的日志,ci/jobs/integration_test_job.py#L75-L78),且部分上传可能被截断,因此推荐按成员名精确解压。例如只取 JSONL 和一个节点的服务器日志:

# 只解压 JSONL 和某个节点的 server 日志 tar -xf "tmp/investigate/$SHA/logs.tar.gz" -C "tmp/investigate/$SHA/" \ ci/tmp/pytest_parallel.jsonl \ 'tests/integration/<test_module>/_instances-conftest.py-gw1/node1/logs/clickhouse-server.log'

配套的最佳实践:

  • 解压失败本身就是一个发现。tar报错(产物过期、包损坏、缺少zstd支持、成员不存在)应当作为结论上报,而不是让后续grep | jq静默产出空结果、被误判为"查无实据"。可以在解压后加一道校验:

    test -f "tmp/investigate/$SHA/ci/tmp/pytest_parallel.jsonl" \ || { echo "extraction FAILED — report the artifact problem"; false; }
  • 统一用tar -xf自动探测格式。如前所述,URL 可能是.tar.zst;成员内容即使名为.log也可能实际是 zstd 压缩的,遇到二进制乱码时可用file命令确认。

  • 工作目录按 SHA 隔离。技能文档约定所有调查文件放在tmp/investigate/<sha>/下(<sha>为报告 commit 的前 7 位),同一调查可重复访问而无需重新下载,不同 PR 的产物互不覆盖。

五、延伸:与整个 investigate-ci 工作流的关系

本文覆盖的产物包属于 investigate-ci 技能 中第 4 步"按需下载 harness 产物"的内容。该技能的完整流程是:从 PR / S3 报告 URL / flaky-test issue 出发,先抓取失败测试列表(node .claude/tools/fetch_ci_report.js <url> --failed --cidb),再对每个失败测试检索既有跟踪 issue 与修复 PR,然后用play.clickhouse.comchecks表查询 master 历史来区分 flaky 与真实回归,最后只对 REAL / UNCERTAIN / INFRA/BUILD 三类失败才下载并解压本文描述的产物包做根因分析。

同一技能目录下还有按作业家族划分的兄弟文档,可按需对照:

  • artifacts-stateless.md —— 无状态 / Fast 测试:产物是独立文件而非整包(clickhouse-server.log[.zst]clickhouse-server.err.log[.zst]stderr.logjob.log等),按--links列出的 URL 逐个抓取;
  • artifacts-stress.md —— 压力测试:关注clickhouse-server.initial.logfatal.loghung_check.log等;
  • fetch_ci_report.js —— 提供--failed--links--download-logs <path>--binary--report N等参数的报告/产物抓取工具;
  • 集成测试作业脚本 —— 产物包生成(on_error_hook打包)、worker 预算模型、基础设施错误自动标注(INFRA/SKIPPED)等实现所在。

掌握以上内容后,面对任何一次 ClickHouse 集成测试 CI 失败,你都可以按"下载产物包 → 看归档布局 → 按失败类型选文件 → 精确解包 +grep/jq定位"的路径,在不需要全量解压的情况下拿到根因证据。

【免费下载链接】ClickHouseClickHouse® is a real-time analytics database management system项目地址: https://gitcode.com/GitHub_Trending/cli/ClickHouse

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/8 19:57:57

FPGA基带与中频处理实战:从DDC到同步环路的工程实现

1. 基带与中频处理&#xff1a;为什么FPGA是绕不开的一块硬骨头做通信、雷达、电子对抗这一类系统&#xff0c;如果你绕开基带和中频去谈FPGA&#xff0c;那基本就等于绕开了FPGA最核心的价值。我接触FPGA开发十年出头&#xff0c;从最开始的SPI控制器、接口逻辑&#xff0c;一…

作者头像 李华
网站建设 2026/9/8 19:54:11

降AI率工具哪个好用?亲测2026年8款免费降AI率工具

自己辛苦码字大半个月完成的稿件&#xff0c;被系统判定含有机器生成痕迹&#xff0c;这种感觉真的很无奈。为了找到靠谱的免费降ai率工具&#xff0c;我把市面上的主流产品逐一测试了一遍。 这段时间我经历过字数大幅增加的情况&#xff0c;也遇到了排版完全错乱的麻烦。今天就…

作者头像 李华
网站建设 2026/9/8 19:52:40

深度学习恶意软件检测实战:基于CNN的源码与数据集解析

简介&#xff1a;面向深度学习与信息安全交叉领域学习者&#xff0c;这份恶意软件检测项目提供完整源码与配套数据&#xff0c;可满足课程设计、毕业设计或入门基准项目的需要。压缩包内含163个文件&#xff0c;共34.66MB&#xff0c;其中18个Python脚本负责模型训练、预测与评…

作者头像 李华