状态与日志
状态目录在哪
当前 Linux 用户的 ~/.bm2。HOME 不可用时回退到 /tmp/bm2-<uid>。每个用户一个守护进程,管理全部已注册项目。
这个路径是固定的,配置无法改变它:bm2 按 Linux 用户划分管理范围,而一个可以被指到别处的守护进程,会心安理得地把同一批应用管上两遍。
目录布局
daemon.endpoint # 控制通道端点:本机端口 + 共享令牌(目录权限 0700)
bm2d.lock # 同一时刻只有一个守护进程;持有者退出即释放,SIGKILL 也不例外
bm2d.pid # 守护进程 PID
bm2.events.jsonl # CLI 连接与重试事件
bm2d.log # 守护进程 stderr 与运行时诊断
bm2d.events.jsonl # 守护进程与监督事件
<name>/project.json # 一个项目的登记信息
<name>/<name>-<id>.json # 持久化的实例状态
<name>/logs/<name>-<id>.out.log # 应用 stdout
<name>/logs/<name>-<id>.error.log # 应用 stderr
<name>/logs/<name>-<id>.crash.log # 异常退出诊断目录以 0700 创建,因为里面放着授权控制守护进程的令牌。
两类日志,严格分开
<name>/logs/ 下的三份日志属于应用,由应用自己写入。顶层的三份属于 bm2,记录管理侧做了什么。分开的好处很直接:对应用日志 tail -f 读到的全是应用输出,而管理侧的历史小到可以长期保留。
出问题时这个划分尤其重要:应用崩了,它写自己的 .error.log 与 .crash.log;而「要不要重启、为什么」记在 bm2d.events.jsonl 里。
轮转
单个文件超过 [logs] max_size_mb 即轮转一次,[logs] keep 决定保留几代归档。默认的 keep = 0 保留所有代数,所以磁盘占用的唯一上界就是你设的那个。
守护进程自身的日志不属于任何项目,因此不受任何项目的 [logs] 支配,统一用内置策略。
两种轮转方式都用上了,用哪一种取决于文件被谁握着。应用的 stdout 与 stderr 由应用自己持有 fd,所以先把内容拷出来再原地截断——改名会让应用继续往旧 inode 写,而新文件永远是空的。bm2 自己写的日志走改名,更省也更不丢东西。
实例状态文件的用途
<name>/<name>-<id>.json 记录守护进程把一个实例重新接上所需的东西:pid、启动时间、重启次数、最后一次退出的原因。
它的用途只有一个——守护进程重启之后,新守护进程收养仍在运行的实例,而不是把它们再启动一份。它不记录日志、不记录环境变量值、不记录配置内容。
事件日志
两个 *.events.jsonl 每行一个 JSON 对象。它们只记录管理元数据:时间戳、事件名、适用时的应用/实例/PID,以及运维原因。
它们不包含环境变量值、协议载荷、应用输出,也不包含通知凭据。
tail -f ~/.bm2/bm2d.events.jsonl # 盯着守护进程
jq -c . ~/.bm2/bm2d.events.jsonl # 按字段过滤