控制台总览
读完这篇,你就能完成首次进入控制台的全过程、看懂侧边栏的组织方式,并读懂四个用来判断实例是否健康的页面——总览、系统信息、日志、诊断——包括每个面板的含义,以及看到某个结果之后该做什么。
本页提到的每个页面,上面这段录屏里都走了一遍。
控制台是什么
Section titled “控制台是什么”控制台是一个 React 单页应用,由 api 容器自己提供。它不是独立服务,没有自己的端口,和 API 同源——这也是会话 Cookie 对两者都生效的原因。使用默认的 compose 文件时,整套东西都在 http://127.0.0.1:8000/。
docker compose -p dtk -f docker/compose.yml up -d# 然后打开 http://127.0.0.1:8000/这种部署方式带来几个后果,先知道可以少查一个不存在的 bug:
- 路由在浏览器里。 任何 API 没有认领的路径都会回落到
index.html,所以控制台的深链接和刷新都能正常工作。 - API 的前缀是保留的。
/api、/healthz、/readyz、/swagger、/redoc、/openapi.json和/mcp一律不会返回控制台页面。/api下写错路径返回的是 JSON 404,不是一个页面。 /docs属于控制台。 那是控制台自带的接口文档页,会按你当前的界面语言渲染 Swagger UI。不需要凭据的原始文档在/swagger。- 源码开发环境里根本没有控制台。 构建产物是在镜像里复制进去的;如果
web/dist不存在,上面这些路由就完全不存在,此时npm run dev会把请求代理给 API 进程。
控制台做的每一件事,都是通过 REST API 指南 里描述的那套公开 REST API 完成的。没有私有通道:控制台能展示给你的任何东西,你自己的脚本也能取到。
首次启动:初始化向导
Section titled “首次启动:初始化向导”全新部署没有任何账号。这就留下了一个「谁先到谁就是管理员」的窗口,而最直觉的修法——「只接受内网地址」——并不成立:Docker 的用户态端口代理会把来源地址改写成网桥网关,于是全世界的请求看起来都是 172.17.0.1。因此这道门用的是一次性令牌,而且只出现在容器日志里。
启动时,只要 users 表还是空的,api 容器就会打印一段横幅:
========================================================================== dtk is not initialized yet. Open this URL to create the administrator account:
http://127.0.0.1:8000/setup?token=...
The token expires in 24 hours. To issue a new one: docker compose restart api==========================================================================横幅最后那一行是简写,照抄到仓库根目录是跑不起来的:那里没有 compose.yml,只有
docker/compose.yml。请用下面「重新签发」那一行里的完整形式——
docker compose -p dtk -f docker/compose.yml restart api。
用这条命令查看:
docker compose -p dtk -f docker/compose.yml logs api关于这个令牌的几个事实,全部由服务端强制:
| 属性 | 取值 | 为什么 |
|---|---|---|
| 有效期 | 自令牌签发那一刻起 24 小时——重启只会把同一个令牌重新打印一遍,不会延长它 | 足够你翻到那行日志,又不至于让一个被遗弃的部署长期可被认领 |
| 存储位置 | 只在 Redis 里 | 它不进数据库、不落盘,也永远不出现在任何 HTTP 响应里 |
| 允许输错次数 | 4 次 | 第 5 次失败会直接删除该令牌。威胁不是有人去猜 32 字节随机数,而是脚本猛刷这个接口 |
| 重新签发 | docker compose -p dtk -f docker/compose.yml restart api |
未过期的令牌在重启时会被复用并重新打印,所以重启不会让你手上的链接失效 |
| 账号创建之后 | 永久关闭 | POST /api/setup/init 会在看令牌之前就返回 409 |
在实例尚未初始化期间,控制台的每一条路由都会重定向到 /setup。如果这个状态查询本身遇到网络错误,控制台会放行并显示一个带重试按钮的面板,同时保留语言与主题切换,而不是把你锁在能解释问题的页面之外。
向导有四步,只有第一步是必须的。
| 步骤 | 做什么 | 可否跳过 |
|---|---|---|
| 1. 创建管理员 | 消耗令牌,创建第一个 admin 账号,然后立刻用你刚输入的凭据登录(init 接口本身不签发会话) |
否 |
| 2. 配置代理 | 粘贴代理列表并导入,随后逐个探测导入的代理,按行显示出口国家与延迟 | 是 |
| 3. 铸造首个身份 | 通过无头浏览器在所选平台上铸造 1–5 个身份 | 是 |
| 4. 冒烟测试 | 用你提供的一条真实链接调用 POST /api/v1/parse 走完整链路,并显示平台、作品 ID、耗时与请求 ID |
是 |
几个容易踩的细节:
-
用户名规则比看上去严格。 3 到 64 个字符,字母、数字、点、短横或下划线,且必须以字母或数字开头。
-
向导要求 12 位密码,服务端下限是 8 位。 多出来的 4 位是向导自己的策略,因为这个账号没有邮件找回。
-
令牌输错会告诉你还剩几次机会。 服务端返回
SETUP_TOKEN_INVALID并带上attempts_remaining,向导会把它显示出来。 -
第 2 步的导入与探测是一个动作。 「列表被接受了但从没真正拨通过」正是这一步要抓的失败。支持的行格式为
host:port、host:port:user:pass、user:pass@host:port和scheme://user:pass@host:port。 -
没有浏览器容器时第 3 步会换一副样子。 铸造要驱动真实浏览器,而浏览器在一个可选的 compose profile 后面。当
browser_rpc报告configured: false时,这一步会直说,并给出命令而不是直接失败:终端窗口 echo 'DTK_BROWSER_RPC_URL=http://browser-rpc:9000' >> .envCLOAKBROWSER_COMMIT=<40 位 sha> \docker compose -p dtk -f docker/compose.yml --profile browser up -d --build控制台只打印其中
docker compose那一行,而它省掉的两样东西都很关键。CLOAKBROWSER_COMMIT是决定镜像里到底有没有浏览器的构建参数——它默认为空, 缺了它构建出来的镜像照样能起来、健康检查照样通过,却一个身份也铸造不出来;.env.example里写着本仓库端到端验证过的那个 commit。DTK_BROWSER_RPC_URL则是api与worker得知这个容器存在的唯一途径。见安装与部署。不启用它也是受支持的运行方式——改为在「身份池」页面手动导入 Cookie。见身份与代理。
-
第 4 步用的是你给的链接,不是内置链接。 这一点和诊断页第 6 步正好相反,后者用的是服务端自带的固定公开链接。如果这一步失败,向导会把你指向诊断页——它把同一条链路拆成一步一步跑,并指出坏在哪一步。
/login 是控制台唯一的入口。没有 OAuth,没有免密登录链接,也没有注册表单。
-
所有凭据类失败的提示都一样。 「用户不存在」和「密码错误」是两个不同的事实,把它们区分开就等于免费送给攻击者一个账号枚举探针。措辞不同的只有你真的能采取行动的那两种:账号被锁(会给出剩余秒数)和 API 不可达。
-
失败次数按账号和按来源地址分别计数。 同一用户名失败 5 次会锁定 15 分钟。按地址的阈值高得多(20 次),而且只有在该地址确实代表单一调用方时才生效——在 TLS 终端或 Docker 发布端口的代理后面,全世界的登录共用一个对端地址,此时按地址拒绝就意味着陌生人 20 次乱试即可把唯一的管理员反复关在自己的控制台外面。
-
登录成功后会种下有效期 7 天的会话 Cookie,带
HttpOnly、SameSite=Lax,只有请求确实走 HTTPS 时才带Secure。 -
没有邮件重置密码。 找回方式是在运行 api 容器的宿主机上执行命令:
终端窗口 docker compose -p dtk -f docker/compose.yml exec api dtk user passwd <username>
登录页上带有语言与主题切换,以及指向源码仓库和许可协议的外链——一个意外撞见这个登录页的人,应该不用先有账号就能弄清这是什么。它故意不链接控制台自己的「关于」页:那个页面需要会话,点过去只会把未登录的人弹回这里。
控制台内部的每个页面都在同一副框架里:左侧边栏、吸顶的顶栏,以及最宽 1440px 的内容列。
宽 240px,可折叠成 56px 的图标条,折叠状态会记在这台浏览器里。宽度低于 1280px 时它会自动折叠成图标;低于 768px 时它整体消失,改为从顶栏打开的抽屉。页面顶部有给键盘用户的「跳到主内容」链接,左上角的标识是返回首页的链接。
导航的分组依据是「出事时你会去找什么」,而不是任何东西的开发顺序。
| 分组 | 页面 |
|---|---|
| 监控 | 总览(/) |
| 资源池 | 身份池(/identities)、代理(/proxies)、调度器(/scheduler) |
| 工具 | 调试台(/playground)、基础工具(/tools)、资料库(/library)、关注列表(/watchlist)、下载(/downloads)、接口文档(/docs)、MCP(/mcp-guide) |
| 访问控制 | API Key(/api-keys)、接口访问控制(/endpoint-access)、用户(/users) |
| 运维 | 日志(/logs)、系统信息(/system)、诊断(/diagnose)、备份(/backup)、通知(/notifications)、设置(/settings) |
有两样东西被固定在可滚动导航的下方,而不属于任何分组:
- 关于(
/about)——版本说明页:许可协议、版权、仓库与 issue 链接,以及捐赠地址。它本身就是控制台里的一个页面,所以看起来就像多一行导航。 - 赞助位 ——指向项目赞助商的、明确标注的外链,侧边栏折叠成图标时会隐藏。这里有两个刻意的选择:Logo 图片由你自己的实例提供,绝不从赞助商的主机拉取,因此打开控制台不会向第三方报告你的部署存在;并且它明写「赞助」二字,而不是伪装成某个功能。链接携带固定的推广参数,描述的是项目本身和展示位置,绝不涉及你、你的实例或你的访问者——每一份自部署副本发出的字符串都完全一样。
MCP 那一项指向 /mcp-guide 而不是 /mcp,因为 /mcp 属于挂在 API 上的 MCP 端点本身。端点自己的路径是带末尾斜杠的 /mcp/;/mcp 只会以 307 Temporary Redirect 跳到它,所以配置客户端时要带上这个斜杠——见MCP 与 AI 客户端。/parse 会重定向到 /downloads:解析工具已经变成下载页的一个模式,旧路径保留是因为它在 v5 的整个生命周期里都在导航中。
每个页面由哪篇文档负责
Section titled “每个页面由哪篇文档负责”侧边栏是控制台的地图,下面这张是从控制台回到文档的地图——每一行导航,以及讲它的那篇。
| 页面 | 路径 | 对应文档 |
|---|---|---|
| 总览 | / |
本篇,见下 |
| 身份池 | /identities |
身份与代理 |
| 代理 | /proxies |
身份与代理 |
| 调度器 | /scheduler |
身份与代理 |
| 调试台 | /playground |
调试台与工具 |
| 基础工具 | /tools |
调试台与工具 |
| 资料库 | /library |
下载、素材库与监控 |
| 关注列表 | /watchlist |
下载、素材库与监控 |
| 下载 | /downloads |
下载、素材库与监控 |
| 接口文档 | /docs |
调试台与工具 |
| MCP | /mcp-guide |
MCP 与 AI 客户端 |
| API Key | /api-keys |
用户与 API 密钥 |
| 接口访问控制 | /endpoint-access |
身份与代理 |
| 用户 | /users |
用户与 API 密钥 |
| 日志 | /logs |
本篇,见下 |
| 系统信息 | /system |
本篇,见下 |
| 诊断 | /diagnose |
本篇,见下 |
| 备份 | /backup |
运维 |
| 通知 | /notifications |
运维 |
| 设置 | /settings |
运维 |
| 关于 | /about |
本篇,见上 |
| 元素 | 是什么 |
|---|---|
| 菜单按钮 | 打开导航抽屉。仅在宽度低于 768px 时显示 |
| 面包屑 | 控制台 / <当前页面> |
| 主机标签 | 你实际连接的主机,取自 window.location.host。低于 768px 时隐藏 |
| 语言切换 | English / 中文 |
| 主题切换 | 暗色 / 亮色 / 跟随系统 |
| 账号菜单 | 显示已登录用户名,以及退出登录 |
语言。 切换立即生效、无需刷新,同时也会改变控制台发出的 Accept-Language 头,所以服务端渲染的文字——设置项说明、熔断原因、任务错误、OpenAPI 文档——会跟着一起换语言。判定顺序是:本次导航(或本标签页更早)的 ?lang= → 你显式保存的选择 → 服务端为这个文档协商出的语言 → navigator.language → 英文。?lang= 链接只在当前标签页内记住,绝不持久化:同事发来的链接说明的是这一次访问该用什么语言,而不是你从此以后的偏好。
主题。 是三档而不是两档:「跟随系统」跟随操作系统。选择保存在这台浏览器里。
语言、主题和侧边栏状态都是保存在本地的浏览器级偏好。服务端不存这些,清除站点数据即恢复默认。
每个页面共用的约定
Section titled “每个页面共用的约定”这些约定读一次,可以省下在后面四节里重复读四次。
- 表格可排序、可隐藏列、可切换密度。 每个数据表都有列菜单和密度菜单,两者的选择会按表分别记在这台浏览器里。有些列默认隐藏,下文按页面逐一列出。
- 手机上表格会变成卡片。 不适合窄屏的列会从卡片视图里丢掉,而不是硬挤进去。
- ID 点一下就能复制。 请求 ID、身份 ID、代理 ID 和提交哈希都用等宽字体完整显示并带复制入口——半个 UUID 毫无价值。
- 状态永远同时用颜色、图标和文字表达。 大家会把这些表格粘到聊天里(只有文字能活下来),也会截图进 issue(颜色可能偏移)。文字才是内容本体。
- 刷新时不做任何动画。 只有状态真的变化时那一行才会高亮,轮询本身不会——每五秒淡入一次的表格是没法读的。
- 时间按你的本地时区显示,服务端存的是 UTC。 涉及时间戳的表格会在筛选区下方注明这一点。
- 页面是轮询而不是长连接。 身份池状态以及出事时你会盯着的东西每 5 秒刷新,图表每 8 秒,变化慢的清单每 10 秒。
- 角色限制的是你能做什么,而不是你能看什么。
viewer可以读本文提到的每个页面;执行自检或修改设置需要operator或admin。见用户与 API 密钥。
/ ——「现在这套东西健康吗?它到底积累下了什么?」 这是落地页,也是适合常驻第二块屏幕的那一页。
页头显示运行中的版本;如果镜像构建时带了 DTK_COMMIT,还会显示可复制的构建提交号。旁边有两个选择器:
| 选择器 | 选项 |
|---|---|
| 接口 | 全部接口,或某一个具体接口。选项来自接口健康度看板 |
| 时间范围 | 最近 1 小时(60 秒桶)、最近 6 小时(300 秒)、最近 24 小时(300 秒)、最近 7 天(1800 秒) |
桶宽不是随手定的:24 小时按 5 分钟是 288 个点,画起来是瞬时的;一周按同样精度就不是了。
如果身份池计数为零并且所选时间范围内没有记录到任何流量,页面会整体换成「还没有请求」和一个跳转到身份池页面的按钮。只有两个条件同时成立才会触发,所以一个正常实例安静了一小时并不会看到它。
告警横幅显示在所有内容之上,而且只针对你必须处理的情况。什么都报的告警等于没人看的告警。
| 告警 | 色调 | 含义 | 该做什么 |
|---|---|---|---|
| 没有可用身份 | 危险 | 身份池里 active 身份为零。在恢复之前请求会以 IDENTITY_POOL_EXHAUSTED 被拒绝 |
去身份池页面铸造或导入——横幅上直接带按钮 |
| N 个身份处于降级状态 | 警示 | 这些身份仍会承接流量,但失败率高于其它身份 | 去身份池页面排查;长期降级通常意味着代理已死或 Cookie 过期 |
| 每个熔断接口一条横幅 | 危险 | 该接口已熔断。横幅会写明接口名、原因和距离恢复的时间 | 见下面的接口健康度表 |
身份池相关的告警在计数尚未加载完成或加载失败时会被抑制。没有这条规则,页面每次加载都会闪一次红色的「没有可用身份」,而且只要状态接口出错就会永久挂着一条。
指标卡片,第一行——请求跑得怎么样
Section titled “指标卡片,第一行——请求跑得怎么样”| 卡片 | 数据来源 | 配色规则 |
|---|---|---|
| 可用身份 | 各平台身份池计数之和 | 大于零为绿色,为零则红色 |
| 请求量 | 所选时间范围内的请求总数,带迷你折线 | — |
| 成功率 | 窗口内 ok ÷ 总数 |
低于 90% 为警示色,达到或超过为绿色 |
| 风控率 | risk_control ÷ 总数 |
只要大于零就是红色 |
| 平均耗时 | 按请求数加权的平均耗时 | — |
| 熔断接口 | 处于熔断状态的接口数量 | 大于零为红色。脚注给出已声明接口总数 |
90% 这个下限是卡片和逐接口表格共用的同一个常量,所以两者不可能对「多少算正常」产生分歧。写死成绿色会把 12% 的成功率画得和 99% 一样好看。
指标卡片,第二行——它留下了什么
Section titled “指标卡片,第二行——它留下了什么”上面每张卡片说的都是请求,没有一张回答这个实例到底积累了什么,而后者是另一个、也更常见的问题。
| 卡片 | 数据来源 | 配色规则 |
|---|---|---|
| 已归档作品 | 内容归档表的行数。脚注:涉及多少位不同作者 | — |
| 已下载媒体 | 已归档且媒体已保存的作品数。脚注:占已归档总数的多少 | — |
| 已占用磁盘 | 下载器有响应时取自媒体卷的实测值,否则取数据库里记录的已存媒体总量——是下载记录求和,不是数据库大小。脚注:来自 media.max_bytes 的上限 |
达到上限 75% 为警告色,90% 为危险色 |
| 正在下载 | 在途任务数。脚注:多少个失败或部分完成 | — |
| 关注中 | 关注列表条目数。脚注:多少个正在失败 | 有失败项时为警告色 |
磁盘这张卡片在快满之前一直安静,接近上限时才变吵,因为超过上限之后最旧的未置顶下载就会开始被清理。见下载、素材库与监控。
身份池状态分布
Section titled “身份池状态分布”一条按比例分段的横条加上每个状态的计数,跨平台统计:minting(铸造中)、active(可用)、cooling(冷却中)、degraded(降级)、retired(已退休)。cooling 不是问题——那是调度器有意让身份休息。绝大部分处于 degraded 或 retired 才是问题。状态机在核心概念里有说明。
三张,全部来自 request_log:
- 成功率与风控率 ——每个时间桶内的请求占比,纵轴固定为 0–100%,这样不同时间范围之间的形状可比。
- 请求量 ——每个时间桶的请求数。
- 各接口成功率 ——只有在没有选定单个接口、且有一个以上接口有流量时才显示。最多画该时间范围内请求量最高的六个接口,因为分类配色只有六个条目能在明暗两种主题下达到 3:1 对比度,而且折线图超过六条本来也就读不动了。
接口健康度表
Section titled “接口健康度表”平台适配器声明的每一个接口都会列出来,不管有没有流量。把没流量的也列出来是刻意的:一个没出现在看板上的接口,和一个从来没被调用过的接口一样看不见。
| 列 | 含义 |
|---|---|
| 熔断 | 正常或熔断中。默认排序把熔断中的排在最前 |
| 接口 | 逻辑接口名,例如 douyin.content_detail |
| 成功率 | 熔断器的 300 秒滚动窗口内的成功率。低于 90% 显示为警示色 |
| 风控率 | 同一窗口内的风控率。大于零显示为红色 |
| 样本数 | 该窗口内有多少个请求。3 个样本算出的比率几乎没有意义 |
| 命中身份数 | 遇到风控的不同身份数量。默认隐藏 |
| 恢复剩余 | 熔断的接口距离下次试探还有多久 |
这里的数字来自 Redis,也就是熔断器自己据以判断的那个滚动窗口,而不是上面来自请求日志的图表。它们回答的是不同的问题,因而不会永远一致:看板说的是「现在能不能用」,图表说的是「过去一天长什么样」。
如果这张表是空的,说明平台适配器根本没有报告任何接口。那是部署问题,不是数据为空。
看到这些之后该做什么
Section titled “看到这些之后该做什么”- 某一个接口成功率掉、风控率升 → 去日志,按该接口加
risk_control结果筛选,看牵涉到哪些身份。 - 所有接口成功率一起掉 → 通常是出口而不是平台的问题。跑一次诊断。
- 接口熔断 → 它会按计时自行重试。同一个接口反复熔断,通常意味着签名或接口定义已经漂移;诊断报告就是提 issue 时要附上的东西。
- 身份池空了或偏少 → 去身份池页面。
- 磁盘卡片进入警告 → 去下载页面,或在配置参考里调高
media.max_bytes。
/system ——「这里到底跑着什么,它能不能连上它需要的东西?」 这一页就是提 bug 时用来截图的那一页。
页头显示版本和提交号,还有一个「刷新」按钮,可以立刻重新读取而不用等轮询。
| 卡片 | 含义 |
|---|---|
| 版本 | 运行中的 dtk 版本。脚注是运行配置版本号,每次改设置都会递增 |
| 运行时长 | 自 api 进程启动起算,用的是单调时钟,因此系统时间被调整也不会跳变 |
| 可用身份 | 各平台可用身份总数 |
| 数据库大小 | 当前数据库的 pg_database_size |
postgres、redis 和 browser_rpc 的连通性与往返耗时,由服务端测得,而不是由你的浏览器测得。这个区别很重要:这里显示的慢是依赖慢,不是你笔记本慢。
| 状态 | 含义 |
|---|---|
| 健康 | 探测有响应。延迟即往返耗时 |
| 不可用 | 探测执行了但失败或超时。详情列显示的是 timeout 或异常的类型名,原文保留、不翻译;而 browser_rpc 不可达时这一列根本不显示任何详情。想看驱动自己的原话,请跑一次诊断并看第 1 步 |
| 未知 | 组件两者都没报告——实际情况就是没有配置 URL 的 browser_rpc。此时详情列显示「未配置」 |
browser_rpc 健康时还会在详情列里报告预热上下文数量。browser_rpc 不可用永远不构成把实例摘出流量的理由:铸造不在请求路径上,所以 /readyz 故意忽略它,只要求 Postgres 和 Redis。
Chromium 与 wreq 指纹
Section titled “Chromium 与 wreq 指纹”并排两个数字:browser_rpc 报告的 Chromium 主版本,以及传输层针对该浏览器实际会采用的 TLS 模拟档案主版本。这张卡片存在的理由是:两者不一致是控制台上别处都看不出来的失败模式——签名照样产出,只是不再符合平台的预期,而你要等几周后风控率上升才会发现。
| 状态 | 横幅 | 含义 |
|---|---|---|
| 两者已知且相同 | 成功 | 没有漂移 |
| 两者已知且不同 | 警示 | 版本漂移。签名仍能产出,但指纹已经和产出它的浏览器对不上。请固定浏览器镜像或更新指纹档案 |
| Chromium 未知 | 提示 | browser-rpc 未配置,或者还没有响应过健康检查 |
| wreq 指纹未知 | 提示 | 当前安装的 wreq 完全没有 Chrome 模拟档案,无从比对。签名仍然可用,但 TLS 指纹与产出它的浏览器对不上 |
两条「未知」提示是分开的,这是有原因的。以前只有一条统一措辞,结果在问题出在 wreq 这一侧时也去怪 browser-rpc,而它上面一行正显示着 browser-rpc 刚刚报上来的 Chromium 版本。
各表的估算行数,卡片描述里带数据库总大小。会报告的表是 request_log、identity_events、content_snapshots、tasks 和 identities。
「估算」两个字请按字面理解。对请求日志做 count(*) 是对全系统最大的表做一次全扫描,对一个会被轮询的状态接口来说太贵了,而「估算」背后其实是三个不同的来源:超表 request_log、identity_events、content_snapshots 来自 TimescaleDB 的分块估算,tasks 来自查询规划器的 reltuples,identities 则是精确的 count(*)——这张表小到跑得起。某张表的估算确实未知时——没人分析过的关系,或者没装 TimescaleDB 的服务器——那一行会被整行略去,而不是显示成空白格,所以「没有这一行」和「这一行是 0」不是一回事。这些数字用来给保留策略定容量是够的,别拿它做对账。
默认关闭,不开启就没有任何数据离开这台机器。 开关写的是运行配置项 system.check_updates,因此选择在重启后依然有效。viewer 不能改它。
开启后,「立即检查」会从你的浏览器向 api.github.com 发起一次请求——绝不会从服务端发起。结果会把最新发布标签与你运行的版本比对,其中 v5.0.0 和 5.0.0 视为同一个版本。没有外网访问的部署应当保持关闭;在一个运维控制台里悄悄向外报到,不是可以替使用者做的决定。
/logs ——「这一次具体的调用发生了什么?谁改了什么?」 两份日志,刻意分开,做成两个标签页。
页头有一个实时刷新开关,按计时刷新当前标签页(请求日志 5 秒,审计日志 10 秒)。仔细看某一行时请先关掉它,否则表格会在你眼皮底下移动。
请求日志标签页
Section titled “请求日志标签页”高频写入。每一次上游请求对应一条结构化记录。
筛选条件 ——所有条件都是可选的,留空表示不限:
| 条件 | 说明 |
|---|---|
| 请求 ID | UUID 精确匹配 |
| 接口 | 精确的逻辑接口名,例如 douyin.content_detail |
| 身份 ID | 某一个身份发起的全部请求 |
| 时间范围 | 15 分钟、1 小时(默认)、6 小时、24 小时、7 天、30 天 |
| 返回条数 | 100(默认)、200、500 |
| 结果 | 切换按钮,可同时选中多个。「全部」清空选择 |
这里有两条限制属于结构性设计而非界面装饰。时间窗口和条数上限都是必填的,而且都没有「全部」选项:无界地读 request_log 是这套 API 上唯一一个能把实例拖垮的查询。服务端把窗口封顶在 30 天,条数封顶在 500。值得知道的后果是:比你所选窗口更老的请求 ID 会查不到——这时应当扩大时间范围,而不是认定这条记录已经没了。
数据保留是另一条上限:retention.request_log_days 默认 14 天,所以查 30 天是允许的,只是能查到的更少。
结果词汇表是这一页上最有用的东西:
| 结果 | 颜色 | 含义 |
|---|---|---|
| 成功 | 绿色 | 平台给了响应,且响应解析成功 |
| 内容不存在 | 灰色(弱化) | 平台把话说清楚了:作品已删除、账号私密、地区限制。不是系统故障 |
| 风控命中 | 红色 | 平台拒绝解释——验证挑战、空响应体、直接拦截。这一类才是真正消耗身份的 |
| 网络错误 | 警示 | 请求根本没拿到可用的响应:DNS、TLS、代理、超时 |
「内容不存在」被刻意弱化。一条被删除的视频不是 bug,把它标红只会让人去找一个并不存在的问题。
列(默认隐藏:代理、拒绝原因、命中缓存、签名方式、平台):
| 列 | 含义 |
|---|---|
| 时间 | 本地时间 |
| 结果 | 上面那套徽标 |
| 接口 | 逻辑接口名 |
| 请求 ID | 可复制。提 issue 时引用的就是它 |
| HTTP 状态 | 平台返回的状态码(如果有) |
| 耗时 | 上游调用的实际耗时 |
| 身份 | 由哪个身份承接 |
| 代理 | 从哪个代理出去 |
| 错误码 | 稳定的机器码,永不翻译 |
| 拒绝原因 | 调度器为什么根本没发出去——见下 |
| 命中缓存 | 结果是否来自缓存 |
| 签名方式 | 由哪条签名路径产出的签名 |
| 平台 | douyin / tiktok |
有拒绝原因就意味着这个请求压根没出门,是调度器拒绝了它:
| 原因 | 含义 |
|---|---|
circuit_open |
该接口处于熔断中 |
no_identity |
该平台没有可用或降级的身份 |
no_token |
所有身份在令牌桶里的配额都用尽了 |
all_inflight |
所有身份都在处理请求 |
queue_full |
等待队列已满 |
wait_timeout |
等待身份超时 |
pinned_unavailable |
指定的那个身份无法处理该请求 |
如果当前版本没有某个原因码的译文,界面会原样显示它——没有翻译的原因码仍然是可以贴进 issue 的东西,而缺失翻译的占位符不是。
点击某一行会打开抽屉,展示完整记录,底部还有折叠起来的原始 JSON。记录里没有任何凭据:抓取层记录的是它调度时用的逻辑接口名,绝不是它构造出来的签名 URL,身份和代理也只以 ID 出现。
审计日志标签页
Section titled “审计日志标签页”低频写入,并且和请求日志分开存放,以免被日常流量淹没。它回答的是「谁改了什么」。
筛选条件只有操作(精确的操作名,例如 api_key.created 或 settings.updated)和返回条数。
| 列 | 含义 |
|---|---|
| 时间 | 本地时间 |
| 操作 | 点分格式的操作名 |
| 操作者 | 已知则显示用户名;否则用户 ID;否则执行操作的 API Key;再否则「系统」 |
| 对象 | 对象类型与 ID,例如 setting 加上配置项名 |
| 来源地址 | 客户端 IP。默认隐藏 |
抽屉里显示这条记录的详情负载。设置类变更在返回时会再次脱敏:设置变更会记录旧值和新值,而有些设置项存的是凭据。在源头脱敏机制存在之前写入的行还留在这张表里——没有任何东西会清理它——所以读取时会再脱敏一次。
/diagnose ——「我部署好了但拿不到数据。四个可能的地方里,到底是哪一个?」 原因通常在代理、Cookie、签名链路或网络这四处,而每猜一次都要付出一个来回。这一页把四处全都走一遍,然后交给你一整段文本。
执行它需要 operator 或 admin 角色。viewer 可以打开这个页面,但执行会被拒绝。
一次运行是怎么跑的
Section titled “一次运行是怎么跑的”点击开始自检会发出 POST /api/v1/admin/diagnose,它返回 202 和一个任务 ID,而不是同步把活干完——一次诊断要拨打代理并发起真实外部请求,这些都不该压在那个本应保持响应的容器的 HTTP 处理线程上。随后控制台每 5 秒轮询这个任务直到结束,每一步的结果到达时就标记出来。任务 ID 显示在页头,可复制。
只有一个选项:包含端到端冒烟测试,默认开启。关掉它会跳过第 6 步,让整次运行完全在本地进行——同时也意味着不消耗任何身份。
那 15 秒是发起外部请求的步骤上的单次网络请求超时,而不是某一步的整体期限:第 1 步的组件探测每个上限 3 秒,第 6 步的端到端抓取上限 25 秒。六个步骤是依次串行跑的,所以慢的那一步确实会拖住后面的——最该留意的是第 3 步:它最多拨打 20 个代理(按创建时间从旧到新),每个最长 15 秒。
报告在源头就已脱敏
Section titled “报告在源头就已脱敏”这份报告的全部意义就是被贴进公开 issue,所以掩码是在渲染器里做的,而不是交给粘贴的人去做。代理密码、Cookie、Authorization 与 X-API-Key 头、Cookie 与签名参数(sessionid、sid_guard、odin_tt、ttwid、msToken、a_bogus、X-Bogus、_signature、verifyFp 等等),以及形如 dtk_..._... 的 API Key 的密钥部分,全部替换为 [REDACTED]。代理的用户名会保留,以便这个代理仍然可辨识;密码绝不保留。API Key 的公开前缀会保留,以便报告仍能说清是哪把 Key 在起作用。
复制报告按钮复制的是服务端渲染出来的那段纯文本本身,而不是浏览器重新拼一遍的结果。
每一步报告的是一个稳定的代码,你读到的句子是按你的语言从这个代码渲染出来的。证据——驱动的报错、异常文本、每一步的 details——刻意保持英文,因为那才是维护者能搜索的内容。
| # | 步骤 | 实际做了什么 |
|---|---|---|
| 1 | components |
往返探测 Postgres、Redis 和 browser-rpc |
| 2 | egress |
不经代理直接访问 https://www.douyin.com/ 和 https://www.tiktok.com/ ——这是把「没网」和「代理坏了」区分开的办法 |
| 3 | proxies |
按创建时间从旧到新,最多拨通 20 个已配置的代理(MAX_PROXIES_PROBED),向回显服务查询出口地址,然后报告出口 IP、库里记录的国家,以及该行是否被标记为健康 |
| 4 | pool |
按状态统计身份数量,并报告最近一次成功请求是什么时候、最老的可用身份已经闲置多久 |
| 5 | signing |
每个平台各用纯算法签一个固定请求,并与 browser-rpc 比对——就是签名器注册表在生产中跑的那套影子比对 |
| 6 | smoke |
用一条固定的公开链接走完 解析 → 签名 → 抓取 → 分类 的全过程 |
注意第 6 步用的是服务端自带的链接,而不是你提供的——这一点和初始化向导第四步正好相反,后者会向你要一条。如果那条作品后来被删除或设为私密,这一步依然通过:平台把话说清楚了,而这一步问的就只有这个。
四种状态:通过、警告、失败、已跳过。整次运行的结论取所有步骤中最差的那个——PASS、WARN 或 FAIL。
警告不会让整次运行判失败。 警告的含义是:这一步跑完了、得出了结论,并且想让你知道某件事——身份池偏少、某个设置还停在开发默认值。把警告并进失败里,会让整份报告读起来是「结论 FAIL」,而一个实例明明在正常服务却被告知失败的运维,从此就不再看结论了。
已跳过也不是失败。 依赖不存在的步骤会报「未配置」,而不是一个你无从下手的红色失败。
第 1 步 —— components
Section titled “第 1 步 —— components”| 结果 | 状态 | 含义与处理 |
|---|---|---|
components_ok |
通过 | 三者都有响应 |
components_browser_rpc_down |
警告 | Postgres 与 Redis 正常,browser-rpc 不可用。身份铸造和签名回退都不可用。启动浏览器容器,或者手动导入 Cookie 并继续使用原生签名器 |
components_unreachable |
失败 | Postgres 和/或 Redis 不可达。确认这些容器在运行,并检查 DTK_DATABASE_URL、DTK_REDIS_URL 是否指向它们。这一项红着的时候,报告里其余部分都不可信 |
第 2 步 —— egress
Section titled “第 2 步 —— egress”| 结果 | 状态 | 含义与处理 |
|---|---|---|
egress_ok |
通过 | 两个平台域名都能直连 |
egress_partial |
警告 | 其中一个不可达。那个平台的请求将完全依赖可用的代理 |
egress_unreachable |
失败 | 两个都通不了。检查 DNS、主机防火墙,以及这台机器的出站流量是否必须走代理 |
第 3 步 —— proxies
Section titled “第 3 步 —— proxies”| 结果 | 状态 | 含义与处理 |
|---|---|---|
proxies_ok |
通过 | 被探测到的代理全部有响应。也就是最多 20 个、按创建时间从旧到新——池子更大时,剩下没被测到的那部分既没有通过,也没有被报告 |
proxies_none |
警告 | 没有配置任何代理。所有身份共用这台机器的出口 IP——初次试用没问题,身份池一忙就是关联风险 |
proxies_partial |
警告 | 一部分通、一部分不通。请停用或更换失败的那些,否则绑在上面的身份会一直失败 |
proxies_all_failed |
失败 | 一个都没响应。检查代理账号密码,以及服务商是否仍然放行这台机器的 IP。绑在失效代理上的身份无法自行恢复 |
proxies_no_session / proxies_unreadable |
已跳过 | 代理表读不出来——先看第 1 步 |
第 4 步 —— pool
Section titled “第 4 步 —— pool”| 结果 | 状态 | 含义与处理 |
|---|---|---|
pool_ok |
通过 | 达到或高于下限 |
pool_below_minimum |
警告 | 可用身份少于 pool.min_size(默认 3)。再铸造一些,或者如果这是有意为之就把该设置调低 |
pool_empty |
失败 | 一个可用身份都没有。在你铸造或导入之前,所有请求都会被拒绝或排队 |
pool_no_session / pool_unreadable |
已跳过 | 身份表读不出来——先看第 1 步 |
第 5 步 —— signing
Section titled “第 5 步 —— signing”| 结果 | 状态 | 含义与处理 |
|---|---|---|
signing_ok |
通过 | 两个平台上纯算法与浏览器签名一致 |
signing_not_comparable |
警告 | 浏览器参考实现的算法版本不同,因此结构化比对给不出任何结论。纯算路径不受影响,仍在正常服务。 这条读起来像故障,但它不是 |
signing_mismatch |
失败 | 纯算法已经和平台的实现产生偏差。这些平台目前改由 browser-rpc 签名;请附上这份报告提交 issue,以便更新算法 |
signing_no_browser_rpc |
已跳过 | 没有配置 browser-rpc,没有第二个签名器可以对照。配置 DTK_BROWSER_RPC_URL 即可启用影子比对,在风控率上升之前就发现失效的算法 |
signing_no_registry |
已跳过 | 本次运行没有拿到签名器注册表 |
只要有任何一个平台没能比对成功,这一步就报警告,而不是只在全部失败时才报。「纯算与浏览器签名一致」这句话,在一个平台比对成功、另一个没比对的情况下,会被读成关于两个平台的证据——而它没说的那个,恰恰是你需要被告知的那个。
第 6 步 —— smoke
Section titled “第 6 步 —— smoke”| 结果 | 状态 | 含义与处理 |
|---|---|---|
smoke_ok |
通过 | 一条真实链接完整跑通了整条链路 |
smoke_failed |
失败 | 先看上面失败的那一步。冒烟失败通常是代理、身份池或签名环节的连带结果,而不是它本身的问题 |
smoke_not_configured |
已跳过 | 你关掉了端到端冒烟测试 |
| 结果 | 状态 | 含义与处理 |
|---|---|---|
step_crashed |
失败 | 检查本身抛异常了。这是 dtk 的缺陷——请附上报告反馈给我们 |
在命令行里跑同一套检查
Section titled “在命令行里跑同一套检查”控制台和 CLI 跑的是同一份代码,所以即使坏掉的正是控制台,你也不会卡住:
docker compose -p dtk -f docker/compose.yml exec api dtk diagnosedocker compose -p dtk -f docker/compose.yml exec api dtk diagnose --skip-smokedocker compose -p dtk -f docker/compose.yml exec api dtk diagnose --jsonCLI 还额外支持 --platform、--smoke-url、--probe-url 和 -o/--output。见命令行参考。
哪个页面回答哪个问题
Section titled “哪个页面回答哪个问题”| 问题 | 页面 |
|---|---|
| 现在有没有着火? | 总览 |
| 哪个接口在失败,有多严重? | 总览 → 接口健康度表 |
请求 0c9f… 到底怎么了? |
日志 → 请求日志,按请求 ID 筛选 |
| 调度器为什么根本没发出去? | 日志 → 拒绝原因列 |
| 这个设置是谁在什么时候改的? | 日志 → 审计日志 |
| 我跑的是什么版本?它能连上 Postgres 吗? | 系统信息 |
| 浏览器和 TLS 指纹版本一致吗? | 系统信息 → Chromium 与 wreq 指纹 |
| 数据库长到多大了? | 系统信息 → 磁盘占用 |
| 部署完了,什么都不工作 | 诊断 |
| 提 bug 时该附上什么? | 诊断 → 复制报告 |
接下来读什么
Section titled “接下来读什么”- 配置参考 ——这些页面读取的每一个设置项,以及每一项的来源
- 核心概念 ——身份、调度器、熔断器,以及结果词汇表
- 身份与代理 ——总览页告警会把你送去的那些页面
- 调试台与工具 ——调试台、基础工具与接口文档这三个页面
- 用户与 API 密钥 ——角色,以及每种角色在控制台里能做什么
- 运维 ——设置、备份、通知这三个页面,数据保留,以及长期运行这套东西
- MCP 与 AI 客户端 ——MCP 页面,以及它所介绍的那个接入点
- 故障排查 ——从症状出发,适合你已经知道坏在哪的时候