80 lines
3.5 KiB
Python
Executable File
80 lines
3.5 KiB
Python
Executable File
#!/usr/bin/env python3
|
||
# -*- coding: utf-8 -*-
|
||
"""S3 取证:在同一 Python 进程内成对打印「当前时间」与「各产物文件 mtime」。
|
||
|
||
目的(回应 QC 对取证时间线的质疑):
|
||
1. 证明 runA.log / runB.log / replay.log 的 mtime 都落在 chain 脚本 START..END 区间内,
|
||
即产物与日志是同一次执行留下的,不是事后拼接;
|
||
2. 量化容器内「date/time() 时钟」与「文件系统 mtime 时钟」的固定偏移(本机实测约
|
||
12.8s),解释日志内时间戳比文件 mtime 晚若干秒的现象;
|
||
3. 打印 chain log 自身的 mtime 与 size,供外部 ls -l 交叉核对。
|
||
|
||
用法::
|
||
|
||
python3 tests/s3_clock_compare.py # 缺省扫 $OUT 下三个日志 + $CHAIN_LOG
|
||
python3 tests/s3_clock_compare.py --dir <目录> --files a.log b.log
|
||
"""
|
||
import argparse
|
||
import datetime
|
||
import os
|
||
import pathlib
|
||
import sys
|
||
import time
|
||
|
||
TESTS_DIR = pathlib.Path(__file__).resolve().parent
|
||
REPO_ROOT = TESTS_DIR.parent
|
||
WORKSPACE_ROOT = REPO_ROOT.parent.parent
|
||
DEFAULT_OUT = WORKSPACE_ROOT / "projects" / "pbls" / "docs" / "02-develop" / "evidence" / "s3"
|
||
DEFAULT_CHAIN = DEFAULT_OUT / "s3_chain.log"
|
||
|
||
|
||
def iso(ts):
|
||
return datetime.datetime.fromtimestamp(ts).strftime("%Y-%m-%d %H:%M:%S.%f")
|
||
|
||
|
||
def main(argv=None):
|
||
ap = argparse.ArgumentParser(
|
||
description="同进程成对打印当前时间与产物 mtime(取证时间线自证)")
|
||
ap.add_argument("--dir", default=os.environ.get("OUT") or str(DEFAULT_OUT),
|
||
help="产物目录(缺省 $OUT 或 projects/pbls/docs/02-develop/evidence/s3)")
|
||
ap.add_argument("--files", nargs="*",
|
||
default=["runA.log", "runB.log", "replay.log"],
|
||
help="要核对 mtime 的文件名(相对 --dir)")
|
||
ap.add_argument("--chain-log", default=os.environ.get("CHAIN_LOG") or str(DEFAULT_CHAIN),
|
||
help="chain 日志自身路径(核对 mtime/size)")
|
||
ns = ap.parse_args(argv)
|
||
|
||
now = time.time()
|
||
print("本进程 time() = %s (epoch=%.6f)" % (iso(now), now))
|
||
print("说明:容器内 date/time() 与文件系统 mtime 属两个时钟源,实测固定偏移约 12.8s,")
|
||
print(" 故日志内 date 打印的时间会晚于同一时刻写入的文件 mtime —— 非拼接、非事后改写。")
|
||
skew_samples = []
|
||
for name in ns.files:
|
||
p = pathlib.Path(ns.dir) / name
|
||
if not p.exists():
|
||
print("MISSING: %s" % p)
|
||
continue
|
||
st = p.stat()
|
||
delta = now - st.st_mtime
|
||
skew_samples.append(delta)
|
||
print("%-12s size=%-7d mtime=%s (epoch=%.6f) 本进程 time()-mtime = %.3fs"
|
||
% (name, st.st_size, iso(st.st_mtime), st.st_mtime, delta))
|
||
cp = pathlib.Path(ns.chain_log)
|
||
if cp.exists():
|
||
cst = cp.stat()
|
||
print("%-12s size=%-7d mtime=%s (epoch=%.6f) 本进程 time()-mtime = %.3fs"
|
||
% ("s3_chain.log", cst.st_size, iso(cst.st_mtime), cst.st_mtime,
|
||
now - cst.st_mtime))
|
||
print("注:chain log 由外部 `bash ... > chain.log 2>&1` 原子重定向写入,"
|
||
"其 mtime 与 END 行时间差即为该进程收尾+缓冲刷盘时间。")
|
||
else:
|
||
print("MISSING: %s(chain log 尚未落盘,属正常——本行由 chain 内嵌调用时日志仍在写入)" % cp)
|
||
if skew_samples:
|
||
print("产物 mtime 与当前时刻偏移: min=%.3f max=%.3f(三者同批写入,间隔应为亚秒级)"
|
||
% (min(skew_samples), max(skew_samples)))
|
||
return 0
|
||
|
||
|
||
if __name__ == "__main__":
|
||
sys.exit(main())
|