尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

Folly 日志库日志级别(LogLevels)完全指南:从 FATAL 到 DBG9 的级别体系、数值模型与配置实践

Folly 日志库日志级别(LogLevels)完全指南:从 FATAL 到 DBG9 的级别体系、数值模型与配置实践 Folly 日志库日志级别LogLevels完全指南从 FATAL 到 DBG9 的级别体系、数值模型与配置实践【免费下载链接】follyAn open-source C library developed and used at Facebook.项目地址: https://gitcode.com/GitHub_Trending/fol/folly导读本文围绕 folly/logging/docs/LogLevels.md 展开系统讲解 FollyFacebook 开源的 C 基础库日志库中完整的日志级别体系FATAL、DFATAL、CRITICAL、ERR、WARN、INFO以及DBG0DBG9十个编号调试级别各自的分工与语义。通过阅读本文你将掌握日志级别背后的数值模型为何DBG0比DBG9更重要、DEBUG为何能一次打开所有调试级别、级别名称与配置字符串之间的解析规则以及如何在XLOG/FB_LOG宏和日志配置字符串中正确选用级别来精确控制程序的日志输出粒度。一、日志级别总体设计越重要数值越大Folly 日志库的全部日志级别定义在 folly/logging/LogLevel.h 中其核心是一个强类型枚举enum class LogLevel : uint32_t。设计原则非常清晰数值越大级别越重要越少出现。下面是该头文件中定义的关键级别及其实际数值级别数值uint32_t说明UNINITIALIZED0未初始化占位值NONE/MIN_LEVEL1不启用任何日志DBG即DEBUG1000最低最啰嗦的调试级别主要用于配置DBG0DBG91999 1990十个细分调试级别编号越小越重要INFO2000普通信息INFO0INFO92999 2990细分信息级别源码中同样存在WARNWARNING3000警告ERR4000错误CRITICAL5000严重错误DFATAL0x7ffffffe仅 debug 构建下终止程序FATAL/MAX_LEVEL0x7fffffff任何构建下都终止程序需要注意两处源码细节头文件注释明确指出DBG*和INFO*名称中的数字是反转的DBG0是最不啰嗦的调试级别DBG1更啰嗦一级以此类推DBG9最啰嗦。数值上则体现为DBG0 1999 DBG9 1990与数值越大越重要的总原则保持一致参见 LogLevel.h。FATAL就是MAX_LEVEL0x7fffffff因为LogCategory需要用最高位存储标志位所以最大值必须清除该位参见 LogLevel.h。此外头文件还提供了两个实用常量默认级别kDefaultLogLevel LogLevel::INFO以及最小致命级别kMinFatalLogLevel——在 debug 构建定义了folly::kIsDebug下为DFATAL否则为FATAL函数isLogLevelFatal()同样按构建模式判断一个级别是否致命参见 LogLevel.h。二、逐级解读从 FATAL 到 DEBUGFATAL必定终止程序使用FATAL级别记录的日志消息会直接中止abort你的程序并且无法被禁用。即使某个日志分类明确设置了自己的级别FATAL消息也永远会被处理。特别地如果程序在记录FATAL消息时还没有配置任何日志处理器handler该消息会被打印到 stderr确保程序不会静默退出。DFATAL仅 debug 构建下致命DFATAL与FATAL行为类似但只在 debug 构建下才终止程序——即构建时没有定义NDEBUG预处理器宏folly 中通过folly::kIsDebug判定。在 release 构建下DFATAL降级为一个普通的但级别很高的日志消息不会导致程序退出。这非常适合在开发阶段强制暴露不可达状态、在发布版本中又不至于因为一条日志直接崩溃的场景。CRITICAL介于ERR与FATAL之间的重要错误CRITICAL面向重要的错误消息其重要程度位于ERR和FATAL之间数值 5000。当一条错误足够严重、值得被高度关注但还不足以让程序中止时应当使用CRITICAL。ERR普通错误ERR面向一般错误消息。文档特别解释了命名原因这一类别叫做ERR而不是ERROR是因为 Windows 的公共头文件会把ERROR定义为预处理器宏直接用ERROR作为枚举名会与宏冲突这一点在 LogLevel.h 的注释中同样有说明。不过在配置字符串中ERROR仍被接受为ERR的别名见下文解析规则。WARN又名WARNING警告WARN面向警告消息且WARNING被接受为WARN的别名。在源码枚举中两者数值完全相同WARN 3000, WARNING 3000参见 LogLevel.h因此它们在一切场景下都等价。INFO信息INFO面向一般信息性消息同时它也是日志库的默认日志级别kDefaultLogLevel。这意味着如果某个分类没有显式配置级别默认只输出INFO及以上更重要的消息。DBG0DBG9十个细分调试级别日志库提供 10 个编号调试级别DBG0、DBG1、…、DBG9用于按啰嗦程度精细切分调试输出。DBG0比DBG9更重要——编号可以理解为该级别的 verbosity冗余度编号越大越啰嗦、越不重要。这一语义直接决定了设置级别的效果。文档给出的规则是把某个日志分类的级别设为DBG5会启用DBG0到DBG5的消息以及INFO及以上的更高级别而DBG6到DBG9的消息将被禁用。用数值模型可以精确验证设置有效级别为DBG51994后只有级别数值 ≥ 1994 的消息才会输出DBG01999DBG51994全部满足DBG61993DBG91990全部被过滤。DEBUG低于DBG9的总开关DEBUG类别位于DBG9之下数值上就是DBG 1000。把日志分类的级别设置为DEBUG会自动启用所有编号的DBG级别因为有效级别被压到 1000所有 ≥ 1000 的级别DBG0DBG9、INFO及以上都会被放行。因此DEBUG主要用于配置场景是打开全部调试输出的快捷开关。需要注意一个命名细节源码中该级别枚举名是DBG而不是DEBUG注释说明这是因为一些开源项目会把DEBUG定义为预处理器宏参见 LogLevel.h。DBG本身并不是设计用来在代码中直接使用的级别头文件建议在代码里使用更细粒度的DBGn而在分类配置里再用DBG或某个DBGn来控制开关。三、级别字符串的解析与格式化别名、编号与整数配置字符串、命令行参数以及logLevelToString()的输出都需要在级别名与枚举值之间转换这部分逻辑实现在 folly/logging/LogLevel.cpp 的stringToLogLevel()和logLevelToString()中。stringToLogLevel()的解析规则全部大小写不敏感包括标准名称UNINITIALIZED、NONE、DEBUG/DBG、INFO、WARN/WARNING、ERROR/ERR、CRITICAL、DFATAL、FATAL、MAX/MAX_LEVEL编号级别DBG0DBG9与INFO0INFO9超出范围的编号会抛出std::range_error如DBG10、INFO15LogLevel::foo与LogLevel(1234)包装形式函数会把LogLevel::WARN和LogLevel(1234)剥壳后继续解析保证logLevelToString()的输出可以被原样回读参见 LogLevel.cpp纯整数任意正整数会被直接转换为对应的LogLevel数值例如4000等价于ERR1994等价于DBG5。logLevelToString()则按相反方向输出标准级别输出标准名注意DBG输出为DEBUG编号级别输出DBG0DBG9、INFO0INFO9无法识别的数值输出为LogLevel(数值)形式参见 LogLevel.cpp。四、级别如何生效LogCategory、有效级别与继承日志级别本身不会单独起作用它必须挂在日志分类LogCategory上。每个分类维护一个LogLevel级别设置控制该分类以及子分类哪些消息被启用。核心实现在 folly/logging/LogCategory.hgetLevel()返回该分类自身配置的级别getEffectiveLevel()返回实际生效的级别原子加载memory_order_acquire它存储在effectiveLevel_这个std::atomicLogLevel成员中setLevel(LogLevel level, bool inherit true)用于修改级别与继承标志。继承规则是理解级别生效的关键分类的层级结构由名称中的.分隔符决定例如spacesim是spacesim.ships的父分类。当inherit为 true 时某个分类的有效级别是其自身级别与其父分类有效级别中更小更啰嗦的那个当inherit为 false 时有效级别就是它自身的级别完全不受父分类影响参见 LogCategory.h。因此向父分类乃至根分类下调级别会沿层级自动传播到所有子孙分类——这正是在配置里把spacesim.ships设为INFO就能一次打开该模块全部代码日志的底层原理。相关的分类层级与传播语义可进一步参考 folly/logging/docs/LogCategories.md。五、在配置字符串中使用日志级别日志库支持通过配置字符串控制级别这是日常调参最常用的方式完整语法见 folly/logging/docs/Config.md。基本格式是逗号分隔的分类级别列表单独的级别名则作用于根分类follyINFO,folly.io.asyncDBG2 WARN级别既可以用名称INFO、DBG2、WARN、ERROR等也可以用正整数指定。基于上文级别体系常见的配置示例及其含义配置字符串效果ERROR根分类级别设为ERRERROR是别名follyINFO,folly.ioDBG2folly分类为INFOfolly.io分类为DBG2follyDBG2,folly.io:INFOfolly.io用:禁用继承有效级别被钉死在INFO父分类的DBG2不会渗透进来folly:WARNfolly分类锁定为WARN屏蔽其噪音输出其余分类保持默认INFO其中:运算符正是对应上面setLevel(level, inheritfalse)的语义——禁用该分类的级别继承。如果你希望某个子模块的调试输出不随上级模块被放大或某组件太吵想单独按掉:是最直接的手段。六、在代码中使用日志级别日常写代码时级别作为宏的第一个参数出现相关用法详见 folly/logging/docs/Usage.md// 最常用自动按文件名选择分类 XLOG(INFO) hello world!; XLOG(ERR) something went wrong; XLOG(DBG1) detailed debug info; // 多参数自动拼接folly::tostring() XLOG(INFO, the number is , 2 2); // 输出 the number is 4 // 指定分类 folly::Logger eventLogger(eden.events); FB_LOG(eventLogger, WARN) something happened; // Python 风格格式化 XLOGF(DBG1, cannot engage {} thruster: {}, thruster.name(), err.what());XLOG系列宏定义在 folly/logging/xlog.hFB_LOG定义在 folly/logging/Logger.h。宏的关键优势在于惰性求值当消息被禁用时参数表达式根本不会被执行日志语句退化为一次条件判断因此可以在热点代码中放心保留大量DBG级别的语句可参考 folly/logging/docs/Overview.md 对非常廉价的调试日志目标的说明。七、实践建议综合文档与源码给出几条可落地的级别选用建议用编号调试级别做精细控制在代码中尽量使用DBG0DBG9而非笼统的DEBUG这样运维时可以通过分类配置精确选择啰嗦到什么程度——DBG0只给最关键的一层调试信息DBG9则近似全量追踪。用DEBUG即DBG做一键总开关排查问题时把分类级别设为DEBUG即可一次启用全部DBG0DBG9消息问题定位后再逐步收紧到某个具体的DBGn。区分ERR/CRITICAL/FATAL的严重度阶梯可恢复的错误用ERR需要立即人工关注但程序仍可继续的用CRITICAL不可恢复的状态用FATAL或 debug 阶段用DFATAL兜底。善用:切断继承对于依赖库或不关心的模块用folly:WARN之类的写法单独压音量避免被上层分类的 verbose 级别放大。级别数值可用于程序化判断由于所有级别都是可比较的uint32_t枚举且LogLevel支持与整数做/-运算见 LogLevel.h加法结果封顶于MAX_LEVEL你可以在代码里对级别做相对调整例如level 1表示稍重要一级。八、延伸阅读folly/logging/docs/Overview.md日志库整体设计目标廉价调试日志、层级分类、异步 I/O、格式化支持等folly/logging/docs/LogCategories.md分类层级、级别传播与消息传播folly/logging/docs/Config.md配置字符串完整语法与 JSON 配置格式folly/logging/docs/LogHandlers.md日志处理器与异步/同步写日志的取舍folly/logging/LogLevel.h 与 folly/logging/LogLevel.cpp级别的权威定义与解析实现【免费下载链接】follyAn open-source C library developed and used at Facebook.项目地址: https://gitcode.com/GitHub_Trending/fol/folly创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表