DEBUG.WIKI
野草云;香港 200Mbps 峰值;不限月流量 · BGP VPS;查看套餐 →
雨云;给项目一台云服务器
晚安云;香港 CN2 ¥15/月

tracing-appender 初始化文件失败就 panic,改用可返回错误的 Builder

tracing-appender 0.2.5 的 RollingFileAppender::new 和滚动便捷函数会在文件初始化失败时 panic。需要由应用决定退出或降级时,使用 Builder::build 接收 InitError,而不是继续调用 expect。

程序刚配置文件日志就退出,错误包含:

initializing rolling file appender failed

如果使用 RollingFileAppender::new,或 tracing_appender::rolling::never、daily 等便捷入口,要检查日志文件初始化是否失败。这些入口在正式 tracing-appender 0.2.5 中会对初始化结果调用 expect;目录不可写、文件无法打开等 I/O 错误,因而会变成 panic。

移动端尤其要留意应用当前是否有权访问目标位置。例如设备锁定期间的文件保护条件可能与正常前台运行不同。不能因为平时能打开该文件,就把启动时的失败当成没有可能发生的情况。

用 build 把决定权交回应用

0.2.5 已有返回 Result 的 Builder,无需等待便捷构造函数改变签名:

use std::path::Path;
use tracing_appender::rolling::{InitError, RollingFileAppender, Rotation};

fn open_log(directory: &Path) -> Result<RollingFileAppender, InitError> {
    RollingFileAppender::builder()
        .rotation(Rotation::NEVER)
        .filename_prefix("app.log")
        .build(directory)
}

这是面向 tracing-appender 0.2.5 的函数;该正式包声明的最低 Rust 版本为 1.63。directory 应由应用按平台规则提供,函数在调用时才尝试初始化文件。例子保留不轮转的行为;原来按天或按小时轮转的项目应保留对应 Rotation,而不是为处理错误顺手取消轮转。

build 返回的 InitError 包含初始化上下文与底层 I/O 错误。调用方可以把它沿启动结果向上传递,让外层决定如何展示失败;如果最后又写成 .expect(...) 或 .unwrap(),仍然选择了 panic,并没有获得可恢复的启动流程。

失败后是否继续,由日志要求决定

日志属于必须落盘的审计记录时,文件初始化失败应让相关启动或操作明确失败,不要静默切到别处后仍报告成功。日志只是辅助诊断时,可以按应用已有策略转向 stderr 或其他可用输出,并清楚记录文件日志未启用。

此时不能再依赖尚未完成安装的文件 subscriber 来报告初始化失败。若应用已有初始化前的错误输出入口,应继续使用它;也不要为每次重试重复安装全局 subscriber。

检查实际解析后的目录、父目录与文件权限,区分“不存在”“不可创建”“已有路径是目录”等情况。涉及平台文件保护时,应使用平台允许的位置或生命周期时机,不通过扩大全部目录权限或关闭文件保护来掩盖问题。输入的目录与文件名也应来自可信配置,而不是直接拼入外部请求内容。

build 成功只覆盖初始化阶段

这个改动不会保证后续磁盘写入永远成功。磁盘空间不足、文件轮转失败,以及异步写入队列的问题仍需各自监控。若后续套用 tracing_appender::non_blocking,还要按原来约定保留 WorkerGuard 的存活期;不要把初始化错误处理与退出时刷新混成同一问题。

复查时分别覆盖正常可写目录与受控的初始化失败条件。失败分支应走应用选定的退出或降级流程,不能再从便捷构造函数的 expect 触发 panic;正常分支仍要确认文件名、轮转策略和最终关闭后的内容符合原配置。无需删除已有日志来制造失败。