
使用 Rust 与 WASI 模式扩展 Fluent Bitwasi_serde_json 示例深度解析【免费下载链接】fluent-bitFast and Lightweight Logs, Metrics and Traces processor for Linux, BSD, OSX and Windows项目地址: https://gitcode.com/GitHub_Trending/fl/fluent-bit导读examples/wasi_serde_json/是 Fluent Bit 官方提供的 WASIWebAssembly System Interface模式示例演示了如何用 Rust 编写一个 WASM 程序被 Fluent Bit 的exec_wasi输入插件周期性调用将其 stdout 输出解析为结构化日志事件。读完本文你将掌握 WASI 程序的 Rust 构建全流程rustup目标添加、cargo build交叉编译、exec_wasi插件的完整配置方法WASI_Path、Parser、accessible_paths、oneshot等参数以及 Fluent Bit 底层如何基于 wasm-micro-runtimeWAMR实例化并执行 WASM 模块、把输出转换为 MessagePack 日志记录的完整数据通路。示例定位Fluent Bit 的 WASI 模式是什么Fluent Bit 允许用户通过 WASM 扩展数据采集能力。在exec_wasi输入插件出现之前exec插件只能周期执行本地命令行程序而exec_wasi则把执行对象替换为符合 WASI 规范的.wasm二进制模块其入口main()在 Fluent Bit 内嵌的 wasm-micro-runtime见仓库 lib/wasm-micro-runtime-WAMR-2.4.1/中被调用stdout输出被捕获并交给配置的 Parser 解析为结构化记录。这种方式兼具“跨平台可移植”与“沙箱隔离”的特点同一份.wasm文件可以在 Linux、BSD、macOS、Windows 上以一致行为运行。本示例仓库位于 examples/wasi_serde_json/包含三个核心文件文件作用examples/wasi_serde_json/README.md构建与集成验证步骤本文的主体脉络examples/wasi_serde_json/src/main.rsRust WASI 程序源码输出 JSON 并测试文件系统 APIexamples/wasi_serde_json/Cargo.toml依赖声明serde_json与chrono程序源码解读main.rs 在做什么src/main.rs 是一个极简但完整的 WASI 应用它演示了两种能力1. 生成并输出结构化 JSON 到 stdoutuse std::io::prelude::*; use std::fs; use serde_json::json; use chrono::Utc; fn main() { // Note that fractional second must be handled by .%9f not %L like as fluent-bit. let time Utc::now().format(%Y-%m-%dT%H:%M:%S.%9f %z).to_string(); let john json!({ name: John Doe, age: 43, phones: [ 44 1234567, 44 2345678 ], time: format!({}, time), }); println!({}, john.to_string()); ... }注意源码第 11 行的注释时间格式的纳秒部分必须使用%9f而不是 Fluent Bit 解析器中的%L。这直接关系到与 Parser 时间字段的匹配是初学者最容易踩的坑——WASI 侧的 Rustchrono与 Fluent Bit 侧的strptime格式串并不完全等价。2. 验证 WASI 文件系统 API 暴露// Create a file (Testing for exposed wasi API) let mut file fs::File::create(helloworld.txt).expect(Unable to create file); write!(file, Hello world!\n).unwrap();这段代码尝试在当前工作目录创建helloworld.txt。WASI 默认不允许模块随意访问宿主机文件系统必须通过accessible_paths配置显式授权可访问目录详见下文参数表这正是 WASI 沙箱安全模型的体现。serde_json负责 JSON 序列化chrono负责时间格式化两者的版本声明见 Cargo.toml[dependencies] serde_json 1.0 chrono 0.4构建 WASI 模块从 Rust 到 .wasm示例 README 给出的构建流程分三步前提是本机已安装 Rust 工具链README 编写时使用的 rustc 版本为 1.61.0实际构建以你当前工具链为准未安装时可先用rustup准备编译器与工具链。第一步为 Rust 工具链添加 WASI 目标$ rustup target add wasm32-wasip1wasm32-wasip1即 WASI Preview 1 对应的 Rust 编译目标它将标准库中的文件、时间等系统调用重定向到 WASI 的fd_write、path_open等 API这与 main.rs 注释中“This will handle writing to stdout for us using the WASI APIs (e.g fd_write)”相互印证。第二步交叉编译 Release 版本$ cargo build --target wasm32-wasip1 --release第三步确认产物$ ls target/wasm32-wasip1/release/*.wasm target/wasm32-wasip1/release/wasi_serde_json.wasm构建出的wasi_serde_json.wasm就是后续WASI_Path需要指向的文件。需要说明的是示例 README 中rustup的官网地址属于外部站点此处不展开若你的环境通过发行版包管理器安装 Rust也可用rustup target add统一管理交叉编译目标。集成验证parsers.conf 与 fluent-bit.confWASI 集成验证需要两个配置文件README 均给出了完整示例。第一步定义 JSON Parserparsers.conf[PARSER] Name wasi Format json Time_Key time Time_Format %Y-%m-%dT%H:%M:%S.%L %zTime_Key time指示插件从 JSON 记录的time字段提取时间戳Time_Format与 main.rs 中chrono输出的%Y-%m-%dT%H:%M:%S.%9f %z格式对应Fluent Bit 侧用%L表示毫秒/微秒小数部分Rust 侧用%9f表示纳秒两者解析结果一致。Parser 的完整配置项可参考仓库根目录的 conf/parsers.conf 中其他[PARSER]段落。第二步编写 exec_wasi 输入配置fluent-bit.conf[SERVICE] Flush 1 Daemon Off Parsers_File parsers.conf Log_Level info HTTP_Server Off HTTP_Listen 0.0.0.0 HTTP_Port 2020 [INPUT] Name exec_wasi Tag exec.wasi.local WASI_Path /path/to/wasi_ser_json.wasm Parser wasi [OUTPUT] Name stdout Match *注意原文档中WASI_Path写的是wasi_serde_json.wasm的完整路径此处按原意指向构建产物。关键配置语义[SERVICE]中的Parsers_File parsers.conf把第一步定义的 Parser 加载进来HTTP_Server Off关闭监控接口若开启则监听HTTP_Listen/HTTP_Port指定的 0.0.0.0:2020[INPUT]的Name exec_wasi启用 WASI 输入插件WASI_Path指向.wasm文件Parser wasi指定用哪个 Parser 解析 WASM 的 stdout 输出[OUTPUT]使用stdout输出插件把解析后的记录打印到终端Match *匹配所有标签这里对应exec.wasi.local。启动 Fluent Bit 后WASI 程序会按interval_sec默认 1 秒周期执行终端应持续打印包含name、age、phones、time字段的 JSON 日志。exec_wasi 插件参数全解结合源码README 只使用了WASI_Path与Parser两个参数但插件的完整配置面远不止于此。从 plugins/in_exec_wasi/in_exec_wasi.c 的config_map定义可以看到全部可配置项及其默认值参数类型默认值说明WASI_Pathstring无必填要执行的 WASM 程序路径缺失时插件报错no input command was givenaccessible_paths逗号分隔列表.当前工作目录允许 WASM 程序访问的路径列表对应 main.rs 中创建helloworld.txt所需授权Parserstring无用于解析 WASM stdout 输出的 Parser 名称未配置时按原始文本以wasi_stdout为键记录interval_secint1采集周期秒见头文件DEFAULT_INTERVAL_SECinterval_nsecint0采集周期纳秒补充见头文件DEFAULT_INTERVAL_NSECbuf_sizesize4096读取 stdout 的缓冲区大小见头文件DEFAULT_BUF_SIZEoneshotboolfalse只执行一次置位后强制interval_sec -1改为事件驱动wasm_heap_sizesize8192WASM 运行时堆大小KB见头文件DEFAULT_WASM_HEAP_SIZEwasm_stack_sizesize8192WASM 运行时栈大小KB见头文件DEFAULT_WASM_STACK_SIZE默认值常量集中在 plugins/in_exec_wasi/in_exec_wasi.h。参数之间的联动逻辑值得注意见 in_exec_wasi.c当interval_sec与interval_nsec都 ≤ 0 时插件会用默认值覆盖当oneshot为真时两个 interval 被强制设为 -1插件改用事件收集器pipe 触发执行一次cb_prerun中向管理管道写入哑元值 0xc003 以“踢”起执行见 in_exec_wasi.c只有用户显式设置的wasm_heap_size/wasm_stack_size大于运行时默认值时才会生效见 in_exec_wasi.c。插件通过FLB_PLUGIN(in_exec_wasi ...)注册并链接flb-wasm-static与vmlib-static即 WAMR 虚拟机详见 plugins/in_exec_wasi/CMakeLists.txt在 plugins/CMakeLists.txt 中以REGISTER_IN_PLUGIN(in_exec_wasi)纳入 Fluent Bit 输入插件体系。底层数据通路从 WASI stdout 到日志事件理解示例“能跑起来”的背后是 in_exec_wasi.c 中in_exec_wasi_collect回调完成的一连串动作创建临时文件接管 stdoutFILE *stdoutp tmpfile()创建一个匿名临时文件把其文件描述符写入 WASM 配置的stdoutfd第 54、82 行WASI 模块中println!的输出即被重定向到这里实例化并调用 WASI mainflb_wasm_instantiate()基于wasi_path与accessible_dir_list加载模块随后flb_wasm_call_wasi_main()执行入口函数第 84-97 行若找不到 main 则报错WASI main function is not found逐行解析 stdoutrewind(stdoutp)后按行fgets读取第 100-102 行去掉行尾换行符若配置了 Parser则调用flb_parser_do()把每行文本解析为 msgpack 数据第 109 行解析失败时打印parser returned an error并跳过编码为日志事件并分发使用flb_log_event_encoder把解析结果或未配置 Parser 时的原始文本键名为wasi_stdout与时间戳编码为 Fluent Bit 标准日志事件通过flb_input_log_append()交给路由与输出第 116-153 行销毁实例执行结束后flb_wasm_destroy()释放模块关闭临时文件第 202-206 行。未配置Parser时的行为同样值得注意第 156-200 行每行输出会以固定键名wasi_stdout附带原始文本直接入库此时所有字段都是非结构化的。这正是示例中特意定义 JSON Parser 的原因——只有结构化的 JSON 输出才能被stdout插件以key: value形式完整呈现。延伸其他语言的 WASI 构建与更多参考WASI 并不局限于 Rust。仓库测试目录 tests/runtime/wasm/go/ 中的 Makefile 展示了用 TinyGo 以-targetwasi构建 WASI 模块的方式tinygo build -wasm-abigeneric -targetwasi -o $.wasm $.go这说明只要目标平台是 WASI Preview 1无论 Rust 还是 Go 生成的.wasm都可以被exec_wasi插件加载执行。如果你想在自己的项目里复刻本示例直接复用 examples/wasi_serde_json/ 的Cargo.toml与main.rs按上文三步构建再把fluent-bit.conf中的WASI_Path换成你的产物路径即可。若需要对 WASI 程序暴露宿主机目录务必配置accessible_paths否则文件系统类 API 调用会因权限不足而失败。小结本文以 examples/wasi_serde_json/README.md 为骨架完整还原了从 Rust 源码、wasm32-wasip1交叉编译、.wasm产物到exec_wasi插件集成验证的全过程并结合 plugins/in_exec_wasi/ 源码剖析了插件全部配置参数与 stdout→Parser→日志事件的三段式数据通路。掌握这套流程后你便可以用任意支持 WASI 的语言为 Fluent Bit 编写可移植、可沙箱化运行的自定义数据采集逻辑。【免费下载链接】fluent-bitFast and Lightweight Logs, Metrics and Traces processor for Linux, BSD, OSX and Windows项目地址: https://gitcode.com/GitHub_Trending/fl/fluent-bit创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考