在 C 程序中嵌入 Fluent Bit:out_lib 库模式示例深度解析
在 C 程序中嵌入 Fluent Bitout_lib 库模式示例深度解析【免费下载链接】fluent-bitFast and Lightweight Logs, Metrics and Traces processor for Linux, BSD, OSX and Windows项目地址: https://gitcode.com/GitHub_Trending/fl/fluent-bitFluent Bit 既可以作为独立的守护进程运行也可以作为库被嵌入到宿主应用中。本篇文章以仓库中的 out_lib 示例 为骨架完整讲解 Library Mode库模式的用法如何在 C 程序中创建 Fluent Bit 上下文、注册lib输入与lib输出、通过回调函数在进程内部直接接收日志数据并借助 out_lib 输出插件 的源码理解数据在内部是以何种格式、何种方式交还给你。读完本文你将掌握一套应用内嵌 Fluent Bit、调用方即输入的完整可运行方案。库模式的核心思想调用方即输入out_lib 示例的 README 用两句话点明了库模式的设计本质该工具使用 Fluent Bit 的**库版本library version**将数据刷新flush到已注册的输出当把 Fluent Bit 作为库使用时调用者caller本身就成为输入input。这与常规的独立进程模式截然不同独立运行时日志来源是tail、forward、syslog等输入插件而库模式下数据由你宿主程序主动通过 API 注入Fluent Bit 内部的引擎、路由、过滤、缓冲与输出机制仍然完整工作但输入侧由你的代码驱动。示例程序将这种程序内嵌数据管道的能力浓缩在了一个约 90 行的 C 文件中。示例的整体工作流从 out_lib.c 的main()可以看出一次完整的库模式调用遵循以下生命周期flb_create()创建并初始化 Fluent Bit 库上下文flb_ctx_tflb_input(ctx, lib, NULL)注册lib输入插件获得输入实例 IDin_ffd并用flb_input_set设置 tagflb_output(ctx, lib, callback)注册lib输出插件并把用户自定义回调函数通过struct flb_lib_out_cb传给它再用flb_output_set设置match与formatflb_start(ctx)启动后台引擎workerflb_lib_push(ctx, in_ffd, data, len)以 msgpack 数组形式循环推送数据flb_stop(ctx)停止引擎、flb_destroy(ctx)释放全部资源。这里值得注意示例同时注册了lib输入和lib输出二者都叫 lib但职责完全不同——输入侧lib负责接收flb_lib_push注入的数据输出侧lib即 out_lib 插件负责把数据回调给宿主程序。整个数据闭环都发生在进程内部没有网络、没有磁盘文件。回调函数数据如何交还给宿主程序示例中定义了两个回调对应两种数据格式int my_stdout_json(void *record, size_t size, void *data) { printf([%s], __FUNCTION__); printf(%s, (char *) record); printf(\n); flb_lib_free(record); return 0; } int my_stdout_msgpack(void *data, size_t size) { printf([%s], __FUNCTION__); msgpack_object_print(stdout, *(msgpack_object *) data); printf(\n); flb_lib_free(data); return 0; }回调签名void *record、size_t size、void *data与 include/fluent-bit/flb_lib.h 中struct flb_lib_out_cb的声明一一对应struct flb_lib_out_cb { int (*cb) (void *record, size_t size, void *data); void *data; };其中第三个参数data是注册时传入的任意不透明数据示例中为NULL可用于向回调传递宿主上下文。两个关键细节必须调用flb_lib_free()释放内存record缓冲区由 out_lib 插件分配宿主代码消费完后必须通过库提供的flb_lib_freeflb_lib.h 中导出的FLB_EXPORT int flb_lib_free(void *data)归还否则会造成泄漏返回值约定返回0表示成功负值表示失败该值由插件层感知并决定 flush 结果。在main()中回调通过struct flb_lib_out_cb注册callback.cb my_stdout_json; callback.data NULL; out_ffd flb_output(ctx, lib, callback); flb_output_set(ctx, out_ffd, match, test, format, json, NULL);format设为json时回调收到的是 JSON 字符串若注释掉这行默认 msgpack回调收到的是原始 msgpack 对象——这正是代码中预留的my_stdout_msgpack分支的用途。out_lib 输出插件的内部实现plugins/out_lib/out_lib.c 是回调机制的底层实现从源码可以确认以下事实插件名注册为libstruct flb_output_plugin out_lib_plugin中的.name lib这就是示例中flb_output(ctx, lib, ...)能命中的原因out_lib_init把flb_output传入的struct flb_lib_out_cb *拆解为cb_func与cb_data存进配置上下文若未提供回调插件会直接报错 Callback is not set 并返回失败out_lib_flush是核心分发逻辑源码中明确了两种data_modechunk模式把整个 event chunkevent_chunk-data与event_chunk-size原样传给回调一次single_record模式默认用msgpack_unpack_next逐条解析 chunk 中的每一条记录逐条回调。在single_record模式下format参数决定回调收到的内容对应 out_lib.h 中的枚举FLB_OUT_LIB_FMT_MSGPACK/FLB_OUT_LIB_FMT_JSONformatmsgpack直接拷贝该条记录的原始字节alloc_size off - last_off交给回调formatjson调用flb_msgpack_to_json_str将记录转成 JSON 字符串并重组为[timestamp,json]数组形式输出见snprintf(out_buf, out_size, [%f,%s], ...)一段。json_escape_unicode的取值来自引擎配置控制非 ASCII 字符是否转义。插件还通过配置映射config_map暴露了三个可调参数在库模式编程中同样可用参数类型默认值说明formatstringmsgpack回调接收的数据格式msgpack或jsonconfig_map 描述中还提及 json_lines / json_stream但configure()中实际分支为 msgpack/json 两种max_recordsint无不限每个 chunk 最多回调的日志记录条数0或未设置表示不限制data_modestringsingle_recordsingle_record逐条回调chunk整块回调另外插件的event_type同时声明了FLB_OUTPUT_LOGS | FLB_OUTPUT_METRICS意味着它也能承接指标类事件当formatjson且事件类型为 metrics 时源码走的是FLB_HAVE_METRICS分支直接对整个 msgpack 对象转 JSON而非拼装[timestamp,json]。数据注入flb_lib_push 的用法示例在启动引擎后循环 100 次构造标准 msgpack 数组格式的日志并注入for (i 0; i 100; i) { n snprintf(tmp, sizeof(tmp) - 1, [%f, {\key\: \val %i\}], flb_time_now(), i); flb_lib_push(ctx, in_ffd, tmp, n); }注意数据格式[timestamp, map]这是 Fluent Bit 记录record的标准 msgpack 数组结构第一个元素是时间戳第二个元素是日志内容 map。flb_time_now()flb_lib.h 导出的FLB_EXPORT double flb_time_now()返回当前时间的 double 表示作为记录时间戳。flb_lib_push在 src/flb_lib.c 中的实现细节印证了生命周期要求如果上下文状态为FLB_LIB_NONE或FLB_LIB_ERROR会直接报错 cannot push data, engine is not running 并返回 -1——必须先flb_start再推送数据它通过in_instance_get(ctx, ffd)依据in_ffd找到输入实例再沿内部通道把数据送入引擎走完路由、过滤、输出全流程。构建与运行示例examples/CMakeLists.txt 显示out_lib示例仅在FLB_OUT_LIB打开时才参与构建add_subdirectory(hello_world) if(FLB_OUT_LIB) add_subdirectory(out_lib) endif()out_lib/CMakeLists.txt 则展示了它的链接方式find_package (Threads) add_executable(out_lib ${src}) target_link_libraries(out_lib fluent-bit-shared) target_link_libraries(out_lib ${CMAKE_THREAD_LIBS_INIT})它链接的是fluent-bit-shared共享库版本这正对应以库形式嵌入的主题你的程序只需 includefluent-bit.h示例源码第 20 行的#include fluent-bit.h并链接共享库即可获得flb_create、flb_input、flb_output、flb_lib_push、flb_start、flb_stop、flb_destroy等全部库模式 API。运行编译出的out_lib可执行程序后stdout 上会打印 100 行形如[my_stdout_json][1660000000.000000,{key:val 0}]的输出——每一行都是一条被 Fluent Bit 内部管道完整处理后回调给你的日志记录。生命周期与资源管理要点从示例代码和库实现中可以提炼出库模式编程的几条铁律顺序不可颠倒flb_create→ 注册输入/输出 →flb_start→flb_lib_push→flb_stop→flb_destroy。在引擎启动前推送数据会被拒绝见flb_lib_push的状态检查回调必须消费并释放数据record由插件flb_malloc分配宿主回调内必须调用flb_lib_free(record)归还示例的两个回调函数都严格遵守了这一约定match 决定路由示例中flb_input_set(ctx, in_ffd, tag, test, NULL)给输入打上test标签flb_output_set(ctx, out_ffd, match, test, ...)让输出只接收该标签的数据二者必须配对数据才能流转资源对称释放flb_stop停止后台 workerflb_destroy释放整个上下文flb_lib.h 导出的flb_start/flb_stop/flb_loop/flb_destroy避免在宿主程序长期运行中出现句柄与内存泄漏。这套模式特别适合需要在进程内完成日志采集、解析、过滤再转交业务代码的场景例如 SDK 式日志库、嵌入式中间件或需要精确控制日志管道的应用——out_lib示例就是最精简、可照抄的起点。【免费下载链接】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),仅供参考