- 区块链
【免费下载链接】eos
An open source smart contract platform
本指南以 EOSIO 仓库中 Deep-mind Logger 集成文档 为核心,系统讲解如何在nodeos上启用 Deep-mind logger、识别以DMLOG为前缀的结构化日志行,并深入nodeos、chain_plugin与chain库源码,说明这些日志事件从何处产生、如何输出,帮助你为区块链数据索引、审计与分析类系统(如 dfuse 平台)提供完整的链上数据源。
Overview:Deep-mind Logger 是什么
Deep-mind logger是 dfuse 平台(一个高可扩展、高性能的开源区块链数据搜索与处理平台)的核心组件之一。它通过与 EOSIO 的nodeos核心服务守护进程深度集成,将节点在出块、验证、资源限制、授权、数据库读写等链上操作过程中的内部细节,以结构化、可机器解析的日志行完整输出出来。
与面向人眼排障的普通nodeos日志不同,Deep-mind 日志的目标读者是外部数据索引与处理程序:下游系统(例如 dfuse 的索引器)可以消费这些日志,重建出完整的链状态变化历史(谁创建了表、哪一行数据被插入/更新/删除、每笔交易的完整 trace、协议特性何时激活等),而无需解析区块二进制或依赖节点内存状态。
在 EOSIO 中,Deep-mind 日志功能由chain_plugin提供(--deep-mind命令行开关),其日志输出经由fc日志框架的专用dmlogappender 完成。
与 Zipkin tracer 的关系
在 第三方日志与追踪集成总览 中,EOSIO 官方将 Deep-mind logger 与 Zipkin tracer 并列为两种官方支持的遥测集成方式:
| 遥测工具 | 关注点 | 输出形式 |
|---|---|---|
| Deep-mind logger | 链上操作细节(区块、交易、资源、DB 变更、协议特性) | 文本日志行(DMLOG前缀) |
| Zipkin tracer | 节点内部请求/处理的分布式追踪时序 | Zipkin span(HTTP 上报) |
二者用途互补:Deep-mind 回答"链上发生了什么",Zipkin 回答"节点内部处理耗时如何"。
如何启用 Deep-mind Logger
要获得完整的 Deep-mind 日志功能,只需在启动nodeos实例时追加--deep-mind标志:
nodeos --deep-mind该标志在源码中定义于 chain_plugin.cpp:
("contracts-console", bpo::bool_switch()->default_value(false), "print contract's output to console") ("deep-mind", bpo::bool_switch()->default_value(false), "print deeper information about chain operations")- 类型为布尔开关,默认关闭(
false); - 开启后,
nodeos会输出"关于链操作的更深层信息"(print deeper information about chain operations)。
启动后即可在nodeos控制台输出中观察到 Deep-mind logger 生成的详细信息。这些日志行与默认nodeos输出行的区别在于:它们以DMLOG关键字开头。此外,chain_plugin还会同时输出一条独立的启动日志行(以dm-log相关文本标识),便于确认 Deep-mind 已激活。
启用时的底层处理
--deep-mind开启后,chain_plugin.cpp 会执行两件关键操作:
// initialize deep mind logging if ( options.at( "deep-mind" ).as<bool>() ) { // ...(注释说明见下) setbuf(stdout, NULL); // 1. 将 stdout 切换为无缓冲 I/O my->chain->enable_deep_mind( &_deep_mind_log ); // 2. 在 controller 上启用 Deep-mind 并挂接日志器 }setbuf(stdout, NULL):将标准输出从行缓冲切换为无缓冲模式。源码注释(chain_plugin.cpp)解释了原因:Deep-mind 会向进程外输出海量数据,在高压力下fwrite等系统调用可能在中途失败;如果使用 libc 持有的缓冲,恢复与重试几乎不可能正确完成。改为无缓冲后,fc::dmlog_appender可以在写入失败时自行重试,从而获得更健壮的输出。注释同时提到未来版本计划改用 FIFO 文件方式输出,以彻底摆脱对stdout的依赖。enable_deep_mind(&_deep_mind_log):将 Deep-mind 日志器注入链控制器(controller),此后区块、交易、数据库、资源等环节都会向该日志器发送结构化事件。
日志器与 appender 的注册
nodeos在 main.cpp 中通过add_deep_mind_logger将deep-mind日志器注册进fc日志框架:
fc::logging_config& add_deep_mind_logger(fc::logging_config& config) { config.appenders.push_back( fc::appender_config( "deep-mind", "dmlog" ) ); fc::logger_config dmlc; dmlc.name = "deep-mind"; dmlc.level = fc::log_level::debug; dmlc.enabled = true; dmlc.appenders.push_back("deep-mind"); config.loggers.push_back( dmlc ); return config; }要点:
- appender 类型为
dmlog(Deep-mind 专用输出器),日志器名为deep-mind; - 日志级别固定为
debug,enabled = true; - 当用户没有提供
logging.json时(main.cpp),initialize_logging会使用默认配置并注入该 Deep-mind 日志器;若提供了logging.json,Deep-mind 的日志配置则交由配置文件中对应的 logger/appender 控制(日志配置热重载由logging_conf_handler支持,见 main.cpp)。
DMLOG 日志行详解:你在控制台会看到什么
下面是启用--deep-mind后,在nodeos输出控制台中实际可见的DMLOG日志行示例(来自 Deep-mind Logger 集成文档):
DMLOG START_BLOCK 30515 DMLOG TRX_OP CREATE onblock 308f77bf49ab4ddde74d37c7310c0742e253319d9da57ebe51eb7b35f1ffe174 {"expiration":"2020-11-12T10:13:06","ref_block_num":30514,...} DMLOG CREATION_OP ROOT 0 DMLOG RLIMIT_OP ACCOUNT_USAGE UPD {"owner":"eosio","net_usage":{"last_ordinal":1316982371,"value_ex":0,"consumed":0},"cpu_usage":{"last_ordinal":1316982371,"value_ex":24855,"consumed":101},"ram_usage":27083} DMLOG APPLIED_TRANSACTION 30515 {"id":"308f77bf49ab4ddde74d37c7310c0742e253319d9da57ebe51eb7b35f1ffe174","block_num":30515,"block_time":"2020-11-12T10:13:05.500",...} DMLOG RLIMIT_OP STATE UPD {"average_block_net_usage":{"last_ordinal":30514,"value_ex":0,"consumed":0},"average_block_cpu_usage":{"last_ordinal":30514,...} DMLOG ACCEPTED_BLOCK 30516 {"block_num":30516,"dpos_proposed_irreversible_blocknum":30516,"dpos_irreversible_blocknum":30515,... ... DMLOG FEATURE_OP ACTIVATE 0ec7e080177b2c02b278d5088611686b49d739925a92d9bfcacd7fc6b74053bd {"feature_digest":"0ec7e080177b2c02b278d5088611686b49d739925a92d9bfcacd7fc6b74053bd","subjective_restrictions":{"enabled":true,"preactivation_required":false,"earliest_allowed_activation_time":"1970-01-01T00:00:00.000"},"description_digest":"64fe7df32e9b86be2b296b3f81dfd527f84e82b98e363bc97e40bc7a83733310","dependencies":[],"protocol_feature_type":"builtin","specification": [{"name":"builtin_feature_codename","value":"PREACTIVATE_FEATURE"}]} ... DMLOG FEATURE_OP ACTIVATE 825ee6288fb1373eab1b5187ec2f04f6eacb39cb3a97f356a07c91622dd61d16 {"feature_digest":"825ee6288fb1373eab1b5187ec2f04f6eacb39cb3a97f356a07c91622dd61d16","subjective_restrictions":{"enabled":true,"preactivation_required":true,"earliest_allowed_activation_time":"1970-01-01T00:00:00.000"},"description_digest":"14cfb3252a5fa3ae4c764929e0bbc467528990c9cc46aefcc7f16367f28b6278","dependencies":[],"protocol_feature_type":"builtin","specification": [{"name":"builtin_feature_codename","value":"KV_DATABASE"}]} ... DMLOG FEATURE_OP ACTIVATE c3a6138c5061cf291310887c0b5c71fcaffeab90d5deb50d3b9e687cead45071 {"feature_digest":"c3a6138c5061cf291310887c0b5c71fcaffeab90d5deb50d3b9e687cead45071","subjective_restrictions":{"enabled":true,"preactivation_required":true,"earliest_allowed_activation_time":"1970-01-01T00:00:00.000"},"description_digest":"69b064c5178e2738e144ed6caa9349a3995370d78db29e494b3126ebd9111966","dependencies":[],"protocol_feature_type":"builtin","specification": [{"name":"builtin_feature_codename","value":"ACTION_RETURN_VALUE"}]}各事件类型语义
结合文档示例与仓库源码,可以归纳出以下核心事件类型(DMLOG后第一个字段为事件类型):
| 事件类型 | 语义 | 示例/来源 |
|---|---|---|
START_BLOCK | 开始处理/生产一个区块(后跟区块号,如30515) | 出块循环入口 |
TRX_OP | 交易生命周期操作(如CREATE onblock,后跟交易 id 与交易 JSON) | 交易创建/恢复阶段 |
CREATION_OP | 作用域/对象创建操作(如ROOT 0,标识根对象及其 id) | 数据库会话初始化 |
RLIMIT_OP | 资源限制状态变化:ACCOUNT_USAGE UPD(账户资源用量更新,含 net/cpu 用量 ordinal、value_ex、consumed与ram_usage字节数)、STATE UPD(全局资源状态更新,如平均区块 net/cpu 用量) | 见下文源码位置 |
APPLIED_TRANSACTION | 一笔交易已被完整执行应用(后跟区块号与交易 trace JSON,含id、block_num、block_time等) | chain_plugin.cpp |
ACCEPTED_BLOCK | 一个区块被接受(后跟区块号与区块状态 JSON,含dpos_proposed_irreversible_blocknum、dpos_irreversible_blocknum等) | chain_plugin.cpp |
FEATURE_OP | 协议特性(protocol feature)操作,如ACTIVATE(激活,后跟特性摘要feature_digest、主观限制subjective_restrictions、依赖dependencies、特性类型protocol_feature_type与规格说明) | protocol_feature_manager相关 |
值得注意的细节:
FEATURE_OP ACTIVATE是理解协议演进的入口。示例中三条ACTIVATE分别对应PREACTIVATE_FEATURE(preactivation_required: false)、KV_DATABASE(preactivation_required: true)与ACTION_RETURN_VALUE(preactivation_required: true)三个内建协议特性,完整记录了每个特性激活时的摘要与约束条件。这为外部系统还原"网络在何时启用了哪些协议特性"提供了精确依据。RLIMIT_OP是资源计量审计的数据源。ACCOUNT_USAGE UPD给出了eosio账户在某个时间点的net_usage(last_ordinal、value_ex、consumed)、cpu_usage与ram_usage(字节数),下游可据此重建资源使用历史。- 事件主体部分是 JSON 对象(可能跨行输出),其后紧跟的十六进制字符串(如交易 id)或 JSON 字段可作为关联键。
源码视角:DMLOG 事件从哪些环节产生
Deep-mind 日志并非由单一模块集中生成,而是分散在链执行管线的多个关键节点。除上面已展示的 chain_plugin.cpp(ACCEPTED_BLOCK、APPLIED_TRANSACTION,分别挂在accepted_block与applied_transaction信号上,将整个区块/交易 trace 序列化并输出)之外,链库内部同样大量埋点:
数据库操作事件(
TBL_OP/DB_OP):在 db_context.cpp 中,表创建/删除输出TBL_OP INS/REM,行记录插入/更新/删除输出DB_OP INS/UPD/REM,字段依次为动作 id(action_id)、付费账户(payer)、表所属合约(code)、作用域(scope)、表名、主键(primkey)以及以十六进制表示的记录数据(ndata/odata)。例如插入一行:DMLOG DB_OP INS ${action_id} ${payer} ${table_code} ${scope} ${table_name} ${primkey} ${ndata}授权操作事件(
AUTH_OP):authorization_manager.cpp 在授权检查与权限更新路径上(如check_authorization、update_permission等)会写入 Deep-mind 日志,记录权限变更与授权判定细节。资源限制事件(
RLIMIT_OP):libraries/chain/resource_limits.cpp是文档示例中RLIMIT_OP ACCOUNT_USAGE/STATE UPD的实现载体,负责在资源账户用量与全局资源状态更新时输出对应 JSON。合约调用上下文:apply_context.cpp 内含大量
if (auto dm_logger = control.get_deep_mind_logger())守卫式埋点(如动作执行、inline action、上下文变更等环节),仅在 Deep-mind 启用时才会进入日志分支,从而在默认情况下保持零开销。KV 数据库(rocksdb)路径:
libraries/chain/backing_store/kv_context.cpp、db_context_rocksdb.cpp与db_key_value_any_lookup.cpp等文件同样包含 Deep-mind 埋点,覆盖 KV 表操作事件(KV_OP类),配合KV_DATABASE协议特性使用。
这种"守卫式埋点 + 集中式 appender"的设计带来两个工程优势:
- 默认零成本:
get_deep_mind_logger()未启用时返回空指针,日志分支被短路,不影响正常节点性能; - 输出可审计:所有 Deep-mind 事件最终统一经
deep-mindlogger(dmlogappender)输出,格式一致、可被下游工具流式消费。
性能考虑与使用建议
第三方日志与追踪集成总览 明确提示:一切皆有代价。遥测工具一旦激活,必然会对nodeos性能造成一定影响,影响程度取决于多种因素(区块吞吐、交易密度、数据库变更量、输出落盘/管道消费速度等),但无论何种情况性能都会被拖累。
因此官方建议:
- 按需开启:仅在你确实需要 Deep-mind 提供的额外详细信息(例如搭建区块链数据索引服务、调试协议特性激活、进行链状态审计)时启用
--deep-mind; - 用后即关:完成数据采集后立刻移除该标志并重启
nodeos,让节点回归无埋点的正常运行模式; - 配套治理输出:由于 Deep-mind 输出量巨大,建议将
nodeos的 stdout 重定向到专门的文件或管道供下游消费,避免与控制台人工排障日志混流。
总结
Deep-mind logger 为 EOSIO 链数据生态提供了一个"链上操作全记录"的标准输出通道:一个--deep-mind标志即可让nodeos输出覆盖区块生产(START_BLOCK)、交易生命周期(TRX_OP、APPLIED_TRANSACTION)、资源计量(RLIMIT_OP)、区块接受(ACCEPTED_BLOCK)、协议特性激活(FEATURE_OP)以及表/行级数据库变更(TBL_OP、DB_OP)等全链路事件。理解其事件格式与源码埋点位置,是构建基于 EOSIO 的区块链索引、分析与审计系统的第一步。
进一步阅读
- Deep-mind Logger 官方集成文档(本指南的原始出处)
- 第三方日志与追踪集成总览
- Zipkin tracer 集成
- chain_plugin 插件文档
- nodeos 原生日志配置
- 区块链
【免费下载链接】eos
An open source smart contract platform
相关推荐
EOSIO nodeos 原生日志配置完全指南:logging.json、Appender 与 Logger 机制深度解析
EOSIO nodeos 原生日志配置完全指南:logging.json、Appender 与 Logger 机制深度解析 nodeos 的原生日志体系由 lo
区块链EOSIO nodeos 区块日志重放(Replay)实战指南——从 blocks.log 重建链状态
EOSIO nodeos 区块日志重放(Replay)实战指南——从 blocks.log 重建链状态 导读 本文聚焦 EOSIO(eos)核心节点程序 nod
区块链Deep Image Prior训练日志分析:TensorBoard集成方法
Deep Image Prior训练日志分析:TensorBoard集成方法 在深度学习项目中,训练过程的可视化与监控对模型调优至关重要。本文将详细介绍如何为D
深度学习计算机视觉图像处理
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考