Kibotos

日志

本页说明 ctrl、node、E2B 网关与 Exposure 网关怎样输出日志,怎样采集和查询,以及 guest 的控制台与 VMM 日志留在哪里。

概述

每个服务把日志写到 stderr,一行一条 JSON 记录。打包的 systemd 单元把 stderr 交给 journald,容器把它交给容器运行时。Kibotos 自己不采集、不导出日志:部署方在每台宿主上运行采集器,把记录送进自己的日志存储。

guest 内 Kibotos 代理的记录由 node 取回,写进 node 自己的日志。guest 的控制台与 VMM 日志不进入日志流,只保留在 node 宿主上,见控制台与 VMM 日志。

记录格式

每条记录都有下面四个字段:

字段取值
timeUTC 时间,毫秒精度,例如 2026-10-06T08:12:03.418Z
levelDEBUG、INFO、WARN、ERROR
msg事件名,例如 workspace command settled。事件名固定,可以直接用于查询与告警
componentctrl、node、guest、e2b、gw

其余字段随事件而定。一条 node 记录的例子:

{"time":"2026-10-06T08:12:03.418Z","level":"WARN","msg":"instance cleanup pending","component":"node","instance_id":"inst-06gfvmpnqsv7xcsfgz7ybx77pg","step":"volume_attachments","attempt":3,"error":"volume is still attached","suppressed":5,"failing_since":"2026-10-06T08:11:02.004Z","node_id":"node-a","incarnation":12}

级别的含义:

级别含义
ERROR不会自己恢复、需要人处理,例如命令的重试预算耗尽
WARN失败或降级,服务会重试或已经绕过
INFO状态变化与完成的操作
DEBUG排查细节,默认不输出

调用方自己的错误(参数非法、对象不存在)不记 WARN 或 ERROR。

关联字段

同一个对象在所有服务的记录里用同一个字段名,按这个字段查询就能把一次操作经过的服务串起来:

字段对象
workspace_idWorkspace;E2B 网关的 sandbox ID 也写在这里
instance_idWorkspace 的一次执行在 node 上的 Instance
node_id、incarnationnode 与它的本次运行。node 进程的每条记录都带这两个字段
data_plane_generationnode 数据面进程的一代。数据面进程的记录带它与 node_id,不带 incarnation:一代可以跨过 node 的多次运行
egress_generationnode 出口进程的一代。出口进程的记录带它与 node_id,不带 incarnation,与数据面进程相同
egress_idguest 连接经由转发的 Egress
command_idctrl 的命令。node 记录里是 ctrl 下发给 node 的命令 ID,例如 ctrl/workspace-create-fc0e90a06bf735372522aa4e/create,里面包含 ctrl 的命令 ID
control_session_idctrl 与 node 之间的一条控制连接
volume_id、transfer_id、exposure_id、template_id、storage_pool同名对象
principal、serial身份的 principal URI 与证书序列号
guest_boot_idguest 的一次启动
trace_id、span_id写下这条记录时所在的 trace 与 span,小写十六进制。哪些记录带它们见链路追踪的日志字段

时长字段以 _ms 结尾,单位是毫秒;error 是错误文本,code 是 RPC 错误码;状态、原因与阶段用小写,例如 running、unavailable。

从一个 Workspace 查到 guest 的步骤:

  1. 在 ctrl 的记录里按 workspace_id 找 workspace command settled,它带 instance_id、node_id 与 command_id。
  2. 在 node 的记录里按 instance_id 查这台 node 做了什么。按 ctrl 的命令 ID 做词组查询,会同时匹配 node 记录里派生出的命令 ID。
  3. 同一个 instance_id 下 component 为 guest 的记录来自 guest 内的代理。

重复失败

同一件事反复失败时,日志不会每次都写一行:

  • 第一次失败立即记录。
  • 之后同一对象的同一事件每分钟最多一条,带 suppressed(这期间省略的次数)与 failing_since(这一轮开始失败的时间)。
  • 会重试的操作恢复时记一条同名的 INFO 记录,带 recovered: true 与 failed_ms(持续失败了多久)。

所以「一分钟只有一条」不代表只失败了一次,看 suppressed。

级别设置

级别由环境变量设定,默认 info,取值为 debug、info、warn、error。取值非法时服务拒绝启动。

服务环境变量
ctrlKIBOTOS_CTRL_LOG_LEVEL
nodeKIBOTOS_NODE_LOG_LEVEL
E2B 网关KIBOTOS_E2B_LOG_LEVEL
Exposure 网关KIBOTOS_GW_LOG_LEVEL

ctrl 与 node 在服务单元里设置。下面的命令打开 node 的单元覆盖文件:

sudo systemctl edit kibotos-node.service

在打开的文件里写入下面两行,保存后重启 node:

[Service]
Environment=KIBOTOS_NODE_LOG_LEVEL=debug

两个网关写在各自的环境文件里,见 e2b.example.env 与 gw.example.env。

在宿主上查看

journald 保存着最近的日志,采集器不可用时也能直接在宿主上查。下面的命令显示 node 最近一小时的 WARN 与 ERROR:

journalctl -u kibotos-node --since -1h -o cat | jq -c 'select(.level == "WARN" or .level == "ERROR")'

下面的命令找出一个 Instance 在这台 node 上的全部记录,包括 guest 代理的:

journalctl -u kibotos-node -o cat | jq -c 'select(.instance_id == "inst-06gfvmpnqsv7xcsfgz7ybx77pg")'

容器部署用 kubectl logs 或 docker logs 读同样的记录。

控制台与 VMM 日志

guest 的控制台与 VMM 自己的日志不进日志流。Instance 结束时,node 先把它们保留下来,再清理 Instance 的运行时目录:

  • 位置:<storage.root>/machine-logs/<instance_id>/,例如 /var/lib/kibotos/node/machine-logs/inst-06gfvmpnqsv7xcsfgz7ybx77pg/。
  • 所有结束方式都保留:按请求停止、强制停止、VM 自行退出、VMM 启动失败。同一个 Instance 再次结束时覆盖上一次的文件。
  • 每个文件只保留末尾 1 MiB。保留区总量超过 1 GiB 或超过 1000 个 Instance 时,删掉最旧的 Instance 目录。
  • node 日志里只有一条 instance machine exited,带退出码或信号、是否被 OOM 杀掉、运行时长,以及 retained(保留目录的路径)。按请求停止后 systemd 已经回收了单元、查不到退出状态时,用 exit_status: unobserved 代替退出码。guest 自己复位后 node 重启 VMM,成功时再写一条 instance machine restarted after guest reset,带 restart_count 与新的 guest_boot_id。

注意:

  • 控制台里可能有 Workspace 内程序写出的内容。保留区只有 root 能读,不要把它交给日志采集器。
  • 这些文件只能在宿主上读取,ctrl 与网关没有读取它们的接口。

不会出现在日志里的内容

下面这些内容不会写进任何级别的日志:

  • 进程的参数、环境变量与输入输出,文件内容,用户给出的路径与文件名,剪贴板与屏幕内容。
  • token、私钥、口令、注册密钥、API key 与会话凭证。需要区分时只记 key ID、证书序列号或摘要的前 8 个十六进制字符。
  • Exposure 主机名里随机的那部分。它就是访问 Exposure 的凭证;日志里记 exposure_id,解析出 Exposure 之前记 zone 与标签摘要的前缀。
  • 带查询串的完整 URL。网关记录路由模式,例如 GET /sandboxes/{id}。

参考部署:Vector、VictoriaLogs 与 Grafana

参考部署用 Vector 在每台宿主上采集,写入 VictoriaLogs 单节点版,用 Grafana 查询。能读 journald 或容器输出、并按 JSON 解析的采集器与存储都可以替换它们。

VictoriaLogs

VictoriaLogs 的启动参数:

参数示例说明
-storageDataPath/var/lib/victoria-logs数据目录,放在本地磁盘
-retentionPeriod30d保留期
-httpListenAddr10.0.0.6:9428只监听采集器与 Grafana 能访问的内网地址
-httpAuth.username、-httpAuth.passwordkibotos、口令写入与查询的认证。需要分开写入与查询的权限时,在前面放 vmauth

Vector

每台宿主运行一个 Vector,读 Kibotos 服务的 journald 记录并解析成字段。参考配置是 deploy/logging/vector.toml,改 endpoints 后即可使用。

  • Vector 0.58 起默认不展开配置里的环境变量。口令放在只给 Vector 读取的文件里,用 Vector 的 secret 文件后端引用,参考配置就是这样写的。
  • node 的数据面进程每一代是一个以代号命名的单元,都在 kibotos-dataplane.slice 里。参考配置按 slice 选中它们,unit 统一记为 kibotos-dataplane,代号在记录的 data_plane_generation 字段里。
  • 出口进程同样一代一个单元,都在 kibotos-egress.slice 里,unit 统一记为 kibotos-egress,代号在 egress_generation 字段里。
  • stream 字段是 host、component 与 unit。instance_id、command_id 这类字段数量很多,作为普通字段写入,VictoriaLogs 照样能按它们查询。
  • 容器部署把 journald source 换成 Vector 的 kubernetes_logs 或 docker_logs source,解析部分不变。

Grafana

Grafana 装 VictoriaLogs 数据源插件 victoriametrics-logs-datasource,添加数据源时填 VictoriaLogs 的地址与口令。deploy/logging/grafana-dashboard.json 是一个按组件与级别统计记录数、列出最常见的 WARN 与 ERROR 的看板,可以直接导入。

看板的变量 filter 填一个 LogsQL 过滤条件,作用于每个面板,默认 *。链路追踪看板的链接按 uid kibotos-logs 打开这个看板,并把 filter 设为 trace_id: 加 Trace ID,所以导入时保留这个 uid。

常用查询(LogsQL):

想找查询
一个 Workspace 的全部记录workspace_id:"ws-06gcx267w1zffcb3w06zhv5z9c"
一台 node 上一个 Instance 的记录,包括 guest 代理instance_id:"inst-06gfvmpnqsv7xcsfgz7ybx77pg"
失败结算的命令msg:"workspace command settled" level:WARN
最近一小时最多的 WARN 与 ERROR_time:1h level:in(WARN,ERROR) | stats by (component, msg) count() n | sort by (n desc)

注意

  • 采集器与存储要能从 Kibotos 宿主访问,租户不能访问:日志里有对象 ID 与错误信息。
  • 日志量随 Workspace 操作次数增长。先在一台 node 上观察一天的写入量,再按保留期估算磁盘。

本页内容