feat: 全流程终端实时进度输出 + 步骤日志
- step_run 增加耗时统计(▶ 开始 / ✔ 完成 Ns / ✗ 失败 exit=N)与 STEP_LOG 支持 - domestic_full.sh / pipeline.sh 去掉 tail 截断,输出实时透传终端并 tee 到 logs/*.log - 退出码用 PIPESTATUS[0] 捕获(规避 pipefail/tee 吞码);全角标点后变量用花括号包裹 - 已同步 pi5 实测:M3 31s / M6 20s 耗时显示正常,日志文件生成
This commit is contained in:
@@ -175,6 +175,15 @@ ls -lt data/reports/
|
|||||||
- 步骤粒度:`M1_crawl` / `M2_extract` / `M3_dedup` / `M4_translate` / `M5_embed` / `M6_index` / `report`;某步失败不标记,`--resume` 从失败处重试
|
- 步骤粒度:`M1_crawl` / `M2_extract` / `M3_dedup` / `M4_translate` / `M5_embed` / `M6_index` / `report`;某步失败不标记,`--resume` 从失败处重试
|
||||||
- **文件级增量(各步骤内自动跳过已处理文件)**:M2 按 `data/processed/.../{url_hash}.json` 存在性、M3 按指纹库判重、M4 按 `data/events/.../{url_hash}.json` 存在性、M5 按 `data/embeddings/.../index.json`、M6 按 Qdrant upsert 幂等(点 id=url_hash)、日报按 MySQL 唯一键覆盖
|
- **文件级增量(各步骤内自动跳过已处理文件)**:M2 按 `data/processed/.../{url_hash}.json` 存在性、M3 按指纹库判重、M4 按 `data/events/.../{url_hash}.json` 存在性、M5 按 `data/embeddings/.../index.json`、M6 按 Qdrant upsert 幂等(点 id=url_hash)、日报按 MySQL 唯一键覆盖
|
||||||
|
|
||||||
|
### 终端进度与日志
|
||||||
|
|
||||||
|
执行全流程时,终端**实时显示完整进度**(每步 `▶ 开始` → 步骤内逐源/逐篇输出 → `✔ 完成(耗时 Ns)`,失败步骤显示 `✗` 与退出码),不再截断:
|
||||||
|
|
||||||
|
- `logs/domestic_full_{YYYYMMDD_HHMMSS}.log` — 全流程完整日志(M1 + 管道)
|
||||||
|
- `logs/pipeline_{YYYYMMDD_HHMMSS}.log` — 管道步骤完整日志
|
||||||
|
|
||||||
|
日志文件已加入 `.gitignore`。
|
||||||
|
|
||||||
### 日报入库(M9)
|
### 日报入库(M9)
|
||||||
|
|
||||||
日报内容结构化写入与 [news 项目](https://github.com/) 共用的 MySQL `myquant` 库(表 `news_report` / `news_event`,`report_type="intl"`,同一天重复生成幂等覆盖)。表结构与数据契约见 news 项目 `docs/db_schema.md`。
|
日报内容结构化写入与 [news 项目](https://github.com/) 共用的 MySQL `myquant` 库(表 `news_report` / `news_event`,`report_type="intl"`,同一天重复生成幂等覆盖)。表结构与数据契约见 news 项目 `docs/db_schema.md`。
|
||||||
|
|||||||
@@ -4,6 +4,24 @@
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
## 2026-08-12 会话成果(三):全流程终端进度输出
|
||||||
|
|
||||||
|
**背景:** `domestic_full.sh` / `pipeline.sh` 原用 `tail -5/-10` 截断输出,终端看不到中间进度。
|
||||||
|
|
||||||
|
**改动:**
|
||||||
|
|
||||||
|
| 文件 | 改动内容 |
|
||||||
|
|------|---------|
|
||||||
|
| `scripts/_step_state.sh` | `step_run` 增加耗时统计与进度日志(`▶ 开始` / `✔ 完成(耗时 Ns)` / `✗ 失败(exit=N,耗时)`);支持 `STEP_LOG` 环境变量——步骤全部输出实时显示终端并同时写入日志(用 `PIPESTATUS[0]` 取原命令退出码,规避 pipefail/tee 吞退出码) |
|
||||||
|
| `scripts/pipeline.sh` | 步骤输出透传终端(去掉 `tail -10`);日志写 `logs/pipeline_{ts}.log` |
|
||||||
|
| `scripts/domestic_full.sh` | M1 与管道输出透传终端(去掉 `tail -5/-10`);日志写 `logs/domestic_full_{ts}.log` |
|
||||||
|
|
||||||
|
**测试:** 无 pipefail / pipefail+条件 / pipefail+非条件 三环境下退出码捕获均正确(失败不 mark);pi5 实机 `--resume` 跑通(M3 31s、M6 20s 均显示耗时,日志文件生成)。
|
||||||
|
|
||||||
|
**注意:** 所有含 `${var}` 后跟全角标点的输出已用花括号包裹(bash 会把全角字符字节并入变量名,导致 unbound variable)。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
## 2026-08-12 会话成果(二):全流程 --resume 断点续跑
|
## 2026-08-12 会话成果(二):全流程 --resume 断点续跑
|
||||||
|
|
||||||
**背景:** `scripts/domestic_full.sh`(M1→M6→日报)中断(ssh 断线/断电)后只能从头重跑。
|
**背景:** `scripts/domestic_full.sh`(M1→M6→日报)中断(ssh 断线/断电)后只能从头重跑。
|
||||||
|
|||||||
+18
-4
@@ -44,17 +44,31 @@ step_run() {
|
|||||||
# $1: 步骤名,$2...: 要执行的命令(成功后标记完成)
|
# $1: 步骤名,$2...: 要执行的命令(成功后标记完成)
|
||||||
# 显式检查退出码:避免 bash set -e 在条件上下文(&&/||)调用函数时失效,
|
# 显式检查退出码:避免 bash set -e 在条件上下文(&&/||)调用函数时失效,
|
||||||
# 导致失败步骤被误标记为完成。
|
# 导致失败步骤被误标记为完成。
|
||||||
|
# 设置环境变量 STEP_LOG=路径 时,步骤全部输出同时写入该日志(终端仍实时显示)。
|
||||||
local name="$1"
|
local name="$1"
|
||||||
shift
|
shift
|
||||||
if ! step_should_run "$name"; then
|
if ! step_should_run "$name"; then
|
||||||
return 0
|
return 0
|
||||||
fi
|
fi
|
||||||
LOG "▶ $name"
|
local t0 rc t1
|
||||||
"$@"
|
t0=$(date +%s)
|
||||||
local rc=$?
|
LOG "▶ $name 开始"
|
||||||
|
# 显式取原命令退出码(PIPESTATUS[0]):
|
||||||
|
# - 无 pipefail 时管道码=tee 码(0),必须用 PIPESTATUS 还原真实结果;
|
||||||
|
# - pipefail + 非条件上下文时失败会触发 set -e 直接退出(此时不 mark,正确);
|
||||||
|
# - 条件上下文调用时 set -e 被抑制,这里仍能正确捕获并 return。
|
||||||
|
if [ -n "${STEP_LOG:-}" ]; then
|
||||||
|
"$@" 2>&1 | tee -a "$STEP_LOG"
|
||||||
|
rc=${PIPESTATUS[0]}
|
||||||
|
else
|
||||||
|
"$@"
|
||||||
|
rc=$?
|
||||||
|
fi
|
||||||
|
t1=$(date +%s)
|
||||||
if [ "$rc" -ne 0 ]; then
|
if [ "$rc" -ne 0 ]; then
|
||||||
LOG "✗ $name 失败(exit=$rc),未标记完成;可 --resume 重试该步骤"
|
LOG "✗ ${name} 失败(exit=${rc},耗时 $((t1 - t0))s);未标记完成,可 --resume 重试"
|
||||||
return "$rc"
|
return "$rc"
|
||||||
fi
|
fi
|
||||||
|
LOG "✔ $name 完成(耗时 $((t1 - t0))s)"
|
||||||
step_mark "$name"
|
step_mark "$name"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -30,26 +30,34 @@ source "$SCRIPT_DIR/_step_state.sh"
|
|||||||
|
|
||||||
LOG() { echo "[$(date '+%Y-%m-%d %H:%M:%S')] $*"; }
|
LOG() { echo "[$(date '+%Y-%m-%d %H:%M:%S')] $*"; }
|
||||||
|
|
||||||
|
# ── 全流程日志:所有输出实时显示到终端,同时完整写入日志文件 ──
|
||||||
|
LOG_DIR="logs"
|
||||||
|
mkdir -p "$LOG_DIR"
|
||||||
|
FULL_LOG="$LOG_DIR/domestic_full_$(date +%Y%m%d_%H%M%S).log"
|
||||||
|
: > "$FULL_LOG"
|
||||||
|
|
||||||
LOG "══════ 国内全流程开始(resume=${RESUME})═══════"
|
LOG "══════ 国内全流程开始(resume=${RESUME})═══════"
|
||||||
|
LOG "全流程日志: ${FULL_LOG}(终端实时显示完整进度)"
|
||||||
|
|
||||||
# ── 加载 .env ──
|
# ── 加载 .env ──
|
||||||
export $(grep -v '^#' .env | grep -v '^$' | xargs 2>/dev/null || true)
|
export $(grep -v '^#' .env | grep -v '^$' | xargs 2>/dev/null || true)
|
||||||
|
|
||||||
# ── 1. M1 Pi 抓取(headful Playwright + HTTP 代理)──
|
# ── 1. M1 Pi 抓取(headful Playwright + HTTP 代理)──
|
||||||
# 部分源抓取失败不阻塞管道(原语义);抓取本身按 URL 去重(index.jsonl),
|
# 部分源抓取失败不阻塞管道(原语义);抓取本身按 URL 去重(index.jsonl),
|
||||||
# 已抓取过的 URL 不会重复写入
|
# 已抓取过的 URL 不会重复写入;输出实时显示每源进度
|
||||||
if step_should_run M1_crawl; then
|
if step_should_run M1_crawl; then
|
||||||
LOG "[1/2] Pi M1 抓取(8G headful + HTTP 代理)..."
|
LOG "[1/2] Pi M1 抓取(8G headful + HTTP 代理)..."
|
||||||
bash "$SCRIPT_DIR/domestic_crawl_8g.sh" 2>&1 | tail -5 || LOG "WARNING: 部分源抓取失败,继续管道"
|
bash "$SCRIPT_DIR/domestic_crawl_8g.sh" 2>&1 | tee -a "$FULL_LOG" \
|
||||||
|
|| LOG "WARNING: 部分源抓取失败,继续管道"
|
||||||
step_mark M1_crawl
|
step_mark M1_crawl
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# ── 2. M2→M6 管道(含日报)──
|
# ── 2. M2→M6 管道(含日报)──
|
||||||
LOG "[2/2] 全链路管道..."
|
LOG "[2/2] 全链路管道..."
|
||||||
if [ "$RESUME" = "1" ]; then
|
if [ "$RESUME" = "1" ]; then
|
||||||
bash "$SCRIPT_DIR/pipeline.sh" --resume 2>&1 | tail -10
|
bash "$SCRIPT_DIR/pipeline.sh" --resume 2>&1 | tee -a "$FULL_LOG"
|
||||||
else
|
else
|
||||||
bash "$SCRIPT_DIR/pipeline.sh" 2>&1 | tail -10
|
bash "$SCRIPT_DIR/pipeline.sh" 2>&1 | tee -a "$FULL_LOG"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
LOG "══════ 国内全流程完成 ✅ ══════"
|
LOG "══════ 国内全流程完成 ✅ ══════"
|
||||||
|
|||||||
@@ -35,7 +35,13 @@ source "$SCRIPT_DIR/_step_state.sh"
|
|||||||
|
|
||||||
LOG() { echo "[$(date '+%Y-%m-%d %H:%M:%S')] $*"; }
|
LOG() { echo "[$(date '+%Y-%m-%d %H:%M:%S')] $*"; }
|
||||||
|
|
||||||
|
# ── 步骤日志:全部输出实时显示到终端,同时完整写入日志文件 ──
|
||||||
|
LOG_DIR="logs"
|
||||||
|
mkdir -p "$LOG_DIR"
|
||||||
|
STEP_LOG="$LOG_DIR/pipeline_$(date +%Y%m%d_%H%M%S).log"
|
||||||
|
: > "$STEP_LOG"
|
||||||
LOG "══════ 全链路管道开始(resume=${RESUME})═══════"
|
LOG "══════ 全链路管道开始(resume=${RESUME})═══════"
|
||||||
|
LOG "步骤日志: ${STEP_LOG}(终端实时显示完整进度)"
|
||||||
|
|
||||||
# 加载 .env
|
# 加载 .env
|
||||||
export $(grep -v '^#' .env | grep -v '^$' | xargs 2>/dev/null || true)
|
export $(grep -v '^#' .env | grep -v '^$' | xargs 2>/dev/null || true)
|
||||||
|
|||||||
Reference in New Issue
Block a user