# 日志与诊断 本页说明异常日志、浏览器错误上报、诊断导出与可选远程诊断的边界。正常取消、缓存回退、来源未命中和任务互斥保留各自状态。 桌面制品验收在临时 Peach 数据目录显式关闭版本统计与错误上传,并在首启提交中保持关闭,避免合成测试进入正式遥测。 ## 反馈入口 馆藏处理失败时,重试失败项,再从托盘「导出诊断报告」或系统诊断页「下载诊断报告」取得 ZIP。用户只需提供一个 ZIP。下载限运行 Peach 的本机,已登录的同源设备可以上报浏览器错误;开放访问模式不提供匿名远程上报。 错误发生时必须实际记录底层证据。完整问题清单位于 `state/library-processing-.issues.jsonl`。通用问题清单不能还原被丢弃的 FFmpeg 错误;没有原始记录的历史失败需要重试取证。 ## 证据链 | 链路 | 持久证据与核验 | | --- | --- | | 启动、CLI、托盘 | 配置及可选依赖加载前安装异常钩子;主线程、后台线程、unraisable、asyncio 和 warning/error 日志写入 `errors-*.log`,原生故障写入 `crash-*.log`;不可写时使用备用目录 | | HTTP 请求 | 未处理异常与 HTTP 5xx 记录 traceback、方法、路由模板、状态码和 `error_id`;响应头 `X-Peach-Error-ID` 与记录关联;请求参数、正文和鉴权头不作为上下文采集 | | 后台任务 | 异常记录任务键、job/run 编号、线程与 traceback;显式返回失败的操作记录失败消息;暂停、互斥和取消沿用任务协议 | | 抽帧、拼图、探测 | 保留退出码、超时、采样位置、时长、工具来源、色彩重试和有界 stderr;`media-probe`、`preview`、`frame-capture`、`frame-tile` 与 `library-preview` 覆盖各入口 | | 图片有效性 | Pillow 完整解码确认图片;纯色小 JPEG 可用,残片、非零退出和陈旧输出不能算生成成功 | | 外部来源、下载 | 来源授权、限流、冷却与未命中使用领域状态;意外失败使用现有异常日志和任务回执;ZIP 包含来源健康状态与时间,来源响应原文留在本机 | | 更新与回滚 | 安装、回滚失败保留 traceback;ZIP 包含启动准备、更新状态、源码更新日志、托盘重启日志及近期迁移日志 | | 隧道 | ZIP 包含 `cloudflare-tunnel.log` 与脱敏运行状态 | | 浏览器 | 保存消息、堆栈、脚本文件名、行列、页面与浏览器标识;查询参数不进入页面字段;同源、有效登录、每分钟条数和请求体积门槛有回归 | | 媒体工具 | 诊断报告与 ZIP 检查实际版本、可执行性及 AV1 软件解码器;`/healthz` 只使用轻量路径检查,不执行外部工具 | ## 可选远程诊断 安装器、首次设置和设置页「应用与维护」提供「发送版本统计与错误诊断(推荐)」单个选项,默认勾选,同时控制版本统计与错误诊断,可取消勾选或在设置页关闭。静默安装保留已有选择。选项保存在本机 `state/remote-reporting.json`;没有记录时两项默认开启,已保存的关闭选择持续生效,损坏或只开启一项的记录均不发送。不写 ledger。缺少接收端时页面明确提示不会发送,仍可保存选择。 | 类别 | 发送内容与筛选 | | --- | --- | | 版本统计 | Peach 版本与操作系统类型,每机 UTC 自然日最多一次;在进程启动时尝试,没有安装标识,不能据此统计独立用户 | | Python 错误 | 版本、平台、Python、CPU 架构、故障环节、异常类型链、Peach 文件名/函数名/行号、整数错误码;错误文本、变量、源码上下文与用户目录不发送 | | HTTP 5xx | 追加方法、路由模板与关联错误编号;不含实例参数、查询参数、正文、鉴权头或用户网址 | | 媒体工具 | 退出码,以及确定匹配的 AV1 解码器缺失、非法媒体、权限、磁盘空间或未知解码器类别;stderr 与媒体名称留在本机 | | 浏览器错误 | 仅发送 Peach 正式脚本的行列位置;没有可定位堆栈的错误与扩展脚本不发送 | 正常取消、来源未命中/暂不可用、HTTP 4xx、互斥、普通 warning 和无堆栈的泛化日志不发送,也不计入故障次数。后台任务的纯文本失败回执仍保留在本机;有异常链的意外失败可发送。SDK 内部日志不进入远程钩子。 同类故障首次在额度内立即上传,重复次数每小时或正常退出时合并提交。`occurrence_count` 是本批增量次数;例如先上传 1 次,随后又发生 9 次,下一批上传 9,合计 10。`occurrence_day` 是实际发生的 UTC 日期,`diagnostic_key` 由脱敏技术字段计算,包含版本但排除每次 HTTP 错误编号;相同代码故障可跨机器对应,不是安装标识。Sentry 的事件数代表上传批次,频率需按统计日期汇总 `occurrence_count`,不能把最新一批当累计总数。普通标签不提供 Sentry 原生的数值求和;汇总需读取事件字段后计算,不能把原生事件趋势图当成真实触发趋势。 每机每天最多接收 20 类故障的本机计数,远程每天最多提交 20 批,重复补报与首次诊断共用批次上限。托盘与子服务使用同一文件锁及聚合文件 `state/remote-reporting-frequency.json`,保留至多 7 个 UTC 日期的技术样本、累计数和已提交数;不读取历史日志。额度不足的待提交次数可在后续启动或定时检查时继续提交,超过保留期失效。SDK 接受入队后更新已提交数;连接失败、服务端丢弃、强制退出、锁争用或超过种类及保留上限均可能造成缺口,因此这是尽力交付的已接收次数,不是完整运行审计。SDK 尚未接受的次数保留在聚合文件中。 两项均通过公开 DSN 发送到 Sentry 托管服务,接收服务会接触连接 IP。客户端不发送 IP 字段、用户身份、设备标识、观看记录、媒体信息、凭据、完整日志或诊断 ZIP。SDK 发送队列不落盘,本机聚合文件仅存技术投影和次数;后台发送前复查本机同意版本。关闭或重新选择会清除未提交聚合,并让排队旧事件失效;已在途或已接收的请求无法撤回。本机 ZIP 导出独立可用。 接收端由维护者配置:源码与 Docker 使用 `PEACH_SENTRY_DSN`;Windows 发行构建从同名环境变量写入包内 `sentry.json`,GitHub Release 使用仓库变量 `PEACH_SENTRY_DSN`。只接受 Sentry 的公开 HTTPS DSN(含 US / DE 区域),不需要 API token。没有 DSN 时不会创建 SDK 客户端。SDK 自动框架集成、日志、性能追踪和指标均关闭;版本统计作为普通事件计入 Sentry 错误事件额度。账号套餐和总量以 [Sentry 订阅页](https://sentry.io/settings/) 为准。 回归验收使用临时 Peach 数据目录和 SDK 内存接收端。实际接收与发行制品的验收记录保存在仓库外。技术诊断选择见 [ADR-0110](adr/0110-recommended-diagnostics-choice.md)。安装辅助进程只在本机取证,不初始化远程客户端或发送事件;应用进程按用户选择发送。 `asyncio` 连接清理只在同时满足以下条件时识别为连接重置收尾:`ConnectionResetError` 的 `winerror` 为 `10054`,回调为标准库 `_ProactorBasePipeTransport._call_connection_lost`,调用栈只含该回调与 `asyncio.events._run`,且没有关联异常。处理器核对真实 Proactor transport 处于清理状态,关闭 socket、解除服务端登记并完成关闭状态;不重复通知协议。成功记录 `classification=connection-cleanup` 与 `cleanup_recovered=true`,仅保留本机证据。收尾自身失败则保留原始异常链、上报技术故障并交给默认处理器;不能确认对象状态时也沿用默认处理器。没有全局修改 Python 类或替换事件循环。 本机记录保留异常与标准库帧,并补充回调、协议类、可识别的服务端类别和 TLS 标志;这些上下文字段不进入远程载荷,不访问连接地址、请求内容或对象文本。资源收尾使用 CPython 3.14.7 的私有对象协议,升级需验证实际 socket、`asyncio.Server`、重复关闭与收尾失败。原始竞争时序在 33 次回环实验中未复现;合成故障验证了资源实际关闭与服务端释放,不能据此推断原始客户端来源。 ### 远程错误筛选核验 核验覆盖异常钩子、日志、后台任务、来源、HTTP、媒体、浏览器、启动与更新入口。筛选依据结构化状态和实际异常继承关系,不按错误原文、任意同名类或所有网络异常统一过滤。 | 状态 | 本机与远程处理 | | --- | --- | | 任务取消、暂停、互斥、计费与磁盘策略门槛 | 保留本机异常和任务回执,不占用错误上传额度 | | 来源冷却、动作预算、授权、未命中、明确的临时故障 | 复用来源异常与分类,保留本机状态;来源解析错误和未知失败继续上报 | | HTTP 客户端错误 | 识别直接状态码、httpx 响应及 urllib HTTPError;4xx 留在本机,未分类的 5xx 继续上报;`0` 不作为 HTTP 状态码 | | warning 与重试日志 | 低于 error 的日志留在本机;error/critical 携带 Peach 栈时上报 | | 媒体输入与环境条件 | 坏媒体、输入缺失、权限、空间与媒体工具超时留在本机;工具执行文件缺失、解码器能力缺失和未知技术错误继续上报;预览前置条件保留提示和可重试问题项 | | 浏览器取消与扩展 | 主动取消请求的 AbortError 不发起记录请求;后端收到该类型仍仅写本机;扩展 URL 帧不上传,Peach 带构建参数的脚本帧保留行列位置 | | 客户端中途断开 | Starlette 的 ClientDisconnect 留在本机,不当作服务端程序故障 | | 启动、CLI、托盘、更新与回滚 | 未处理的技术故障继续上报;安装辅助进程沿用仅本机诊断边界 | | SDK、无堆栈日志与不透明浏览器错误 | 不递归上报 SDK 自身问题;无法取得 Peach 代码位置的日志和浏览器错误仅保留本机 | 本机策略不清除已有 Sentry 事件,也不控制邮件;邮件摘要与即时通知分别在接收端设置。 ### 馆藏与口味群体研究 「上传馆藏与口味明细」是独立默认关闭的选项,位于「应用与维护 → 数据上传」,与技术诊断使用各自的开关。开关始终可见。设置页由用户生成本机预览,查看实际字段与内容后明确同意;预览数量、大小与排除的个人数据合并为一段说明。服务端要求当前进程生成、10 分钟内有效的一次性预览凭据、同意值与字段版本。单独操作开关或开启错误诊断不构成馆藏上传同意,关闭不要求预览。安装器提供默认不勾选的独立选项,短标签概括内容与风险;主动勾选后展示可滚动的完整字段、用途与风险说明页,继续表示同意,返回可取消选择。辅助进程只保存选择,不读取馆藏或初始化 SDK。静默安装保留已有选择。字段版本为 `4`,其他版本的同意无效。 附件 `peach-library-taste.json.gz` 无损压缩以下完整 JSON: - `schema`、`peach`、`period`:字段版本、Peach 版本和 UTC 自然周。 - `library`:每个规范作品编号一条;存在用户信号时附评分、喜欢、不喜欢或已看、稍后看、累计播放次数、观看比例与手动标签。无反馈的作品只发编号,供跨部署统计收藏覆盖。无编号条目不进入逐作品列表。 - `preferences`:出演者、创作者、厂牌、系列、手动标签、五年发行年代段与时长段,均在本机分组。每个分组包含 `name`,以及存在对应馆藏时的 `works`(有编号去重作品)和 `uncoded`(无编号条目)。两种范围分别包含 `collected`、`liked`、`disliked`、`watched` 与 `ratings`(0–100 分评分到数量的直方图),不得相加当成作品数量。主动收藏的实体另有 `favorite: true`。明确登记的男优不参与人物偏好。时长段 `0`、`1`、`2`、`3` 分别为小于 30 分钟、30–90 分钟、90–150 分钟、150 分钟及以上。 - `coverage`:`active_files`、`coded_files`、`coded_works`、`uncoded_items`,供判断收藏与评分样本的覆盖范围。 标签仅取设置页逐条添加的 `web-user` 证据,遵守隐藏标签偏好;实体收藏中的标签是用户主动选择,也保留。自动刮削、技术标签及从浏览行为推断的标签不参与本投影。同编号各文件合为一部作品:喜欢和稍后看取任一文件的选择,播放次数累加,观看比例取已保存观看比例、最远播放位置与累计播放时长比例中的最大值并限制到 1;反馈取时间最新的明确标记。评分沿用 0–100 分,空值和 0 不计评分,不同副本的不同有效评分取均值,每部作品每次快照只贡献一份评分。年代与人物关联仅用于本机分组,不逐作品重复发送。 不发送账号、设备或安装标识、文件名、路径、媒体、网址、搜索词或逐条浏览/观看记录。标签和规范名称中的网址、绝对路径与凭据样式经过现有脱敏函数。作品组合、评分和分组偏好仍可能跨次关联,或与其他资料匹配后再识别;Sentry 会接触连接 IP。界面的「匿名处理」指移除直接标识,不构成不可关联或无法识别来源的保证。关联上传与知道真实姓名是不同的判断,两者均不能作绝对保证。 预览与后台采集只读 ledger,不读取浏览历史、书签或写入偏好缓存。大预览在代码块展示前 24,000 个字符,可复制或下载完整本机 JSON。预览不是发送,也不会开启上传;同意覆盖每周发送相同字段的最新快照。同意后收起预览说明、数据预览和同意框;预览入口仍可重新打开,已开启时不重复要求同意。契约改变须推进 `SCHEMA` 并重新取得同意。 后台只有在有效同意和独立接收端同时存在时才读取明细并初始化 SDK。每机每 UTC 自然周最多尝试一份,跨进程共用带字段版本的尝试记录;不补传历史快照。原始 JSON 上限 100 MiB,gzip 附件上限 18 MiB;任一超限均整份拒绝,不发送截断数据。gzip 头不含源文件名和生成时间。传输只接受固定用途事件、固定文件名附件与字段白名单,后台真正发送前复查同意版本。关闭让排队记录失效,已发送数据无法经本机开关撤回。发送尝试不表示服务端接收成功。 维护者另设 `PEACH_LIBRARY_SENTRY_DSN`,Windows Release 读取同名仓库变量并写入包内 `library_dsn`。该 DSN 的项目必须与错误诊断项目不同,同项目配置视为未配置。研究快照作为 Sentry 附件接收,每次也产生一条事件;组织内的事件和附件额度仍共享。见 [Sentry 附件说明](https://docs.sentry.io/platforms/python/enriching-events/attachments/)。 群体分析按 `period` 分开汇总作品持有率、作品评分分布、人物及系列偏好和手动标签;每份快照每部作品只贡献一次持有,实体的 `favorite` 表示主动收藏,`collected` 表示持有相关作品,不能混用。评分使用有效评分人数或数量作分母,不能把未评分当作 0 分,也不能把文件数量当用户数量。每周快照是累计状态,不能跨周累加成新增收藏或播放。没有跨周期标识,但不能据此宣称明细无法关联;每机每周一次也不能识别同一人多安装。结果只代表自愿参与样本,须说明安装覆盖与选择偏差。接收端分析看板不属于客户端上传功能。 ## ZIP 内容 - `report.json`:系统和版本信息、检查结果、媒体工具能力、来源健康摘要及文件收集回执。 - `logs/<目录序号>/`:托盘、服务、重启、首次扫描、源码更新、隧道、错误及崩溃日志;固定日志包含近期自然月分段。 - `processing/`:馆藏处理状态与近期问题清单、启动准备、自动更新、独立包更新及隧道状态。 - `updates/`:近期更新迁移日志。 每个文件读取尾部最多 96 KiB;错误日志最多 8 份、崩溃日志最多 4 份、处理问题清单最多 8 份、迁移日志最多 2 份。截断和读取失败进入收集回执,单个不可读文件不影响其他证据。JSON 与 JSONL 分别解析,正在写入的残行不进入共享报告。日志保留周期沿用半年及自然月分段策略。 ZIP 不包含 ledger、配置文件、私钥、登录 Cookie 或媒体文件。路径、网址、地址、凭据字段及命令行凭据值脱敏;处理记录中的媒体名称隐藏。故障注入的默认日志落在测试进程临时目录。 ## 媒体工具 AV1 抽帧需要可用的软件解码器。`scripts/build_ffmpeg_windows.sh` 静态编入固定版 dav1d;完整源码归档、许可证和 SHA256 清单通过 `media_tool_bundle.py --validate-only` 核验。 发行验收使用内嵌的合成 AV1 片段,在 CPU 上完成解码和抽帧,不依赖机器显卡或 AV1 编码器。真实媒体的失败记录、文件指纹与重试结果保存在仓库外的私有诊断记录中。