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

资讯详情

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

Vector Lua Transform 完全指南:使用 Lua 5.4 编程式处理日志与指标事件

Vector Lua Transform 完全指南:使用 Lua 5.4 编程式处理日志与指标事件 Vector Lua Transform 完全指南使用 Lua 5.4 编程式处理日志与指标事件【免费下载链接】vectorA high-performance observability data pipeline.项目地址: https://gitcode.com/GitHub_Trending/vect/vector本指南以 Vector 官方的luatransform 组件文档为核心系统讲解如何用嵌入式 Lua 5.4 引擎对日志log与指标metric事件进行编程式处理。你将掌握version、hooks、source、search_dirs、timers、metric_tag_values全部配置项的含义与用法理解 Vector 数据模型到 Lua 数据类型的映射规则并通过 6 个官方示例和源码级原理剖析获得可直接投入生产管道pipeline的完整实战能力。Lua Transform 是什么luatransform 是 Vector 内置的一个通用数据处理组件它内嵌一个完整的 Lua 5.4 运行时允许你直接用 Lua 脚本改写流过管道的每一个事件。与专注于声明式转换的remaptransform 相比luatransform 提供的是近乎无限自由度的编程能力凡是remap表达式语言覆盖不到的边角场景复杂字符串解析、外部 Lua 库调用、周期性聚合、按需构造新事件等都可以用 Lua 脚本来实现。根据官方组件元数据website/cue/reference/components/transforms/lua.cue开发状态stable稳定输出方式stream流式逐事件处理是否有状态true脚本中可以持有跨事件的全局状态配合定时器可实现聚合统计。在输入输出类型上luatransform 同时接受日志与全部类型的指标counter、distribution、gauge、histogram、set、summary但不支持 trace 事件源码 lib/vector-core/src/event/lua/event.rs 中会明确报错Trace are not supported。官方性能警告优先使用 remap官方文档在support.warnings中给出了明确的性能指引luatransform 比remaptransform 慢约 60%只要情况允许强烈建议优先使用remap。luatransform 仅用于remap无法覆盖的边界场景不应作为默认首选。若remap无法满足你的用例请提交 issue 反馈。因此在架构选型时请遵循先remap后lua的原则能用 VRLVector Remap Language表达的逻辑尽量用remap组件完成只有确实需要通用编程能力时才引入lua。快速上手最小可运行配置luatransform 采用版本化配置version字段当前推荐使用 API 版本2。最小配置只需提供一个process钩子。以下配置为每个事件添加一个processed_by字段并输出transforms: my_lua_transform: type: lua inputs: - my_source version: 2 hooks: process: | function (event, emit) event.log.processed_by lua emit(event) end要点version: 2是必填项官方通过generate_config生成的默认骨架即为version: 2加空的hooks.process见 src/transforms/lua/mod.rshooks.process是必填钩子接收(event, emit)两个参数event是待处理事件emit是用于向外输出事件的回调函数事件被修改后必须调用emit(event)否则该事件会被丢弃。配置参数完整参考luatransform 的全部配置项定义在 website/cue/reference/components/transforms/generated/lua.cue 与 Rust 结构体 src/transforms/lua/v2/mod.rs 中汇总如下参数类型必填默认值说明versionstring1/2是无Transform API 版本。1已弃用且将在未来版本移除应使用2hooks.processstringLua 源码或函数名是无每个事件进入时调用的钩子签名function (event, emit)hooks.initstringLua 源码或函数名否无首个事件到来时、process之前调用一次签名function (emit)hooks.shutdownstringLua 源码或函数名否无transform 停止时调用一次签名function (emit)sourcestringLua 源码否无初始化脚本可 import 外部依赖、定义钩子函数等search_dirsarraystring否[]require加载 Lua 模块时的搜索目录未设置时使用配置文件所在目录timersarrayobject否[]周期性执行的定时器列表每个包含interval_seconds与handlermetric_tag_valuesstringsingle/full否single指标标签值在 Lua 中的暴露形式versionAPI 版本选择version字段保证了向后兼容性。两个版本的行为差异明显版本 1已弃用只支持日志事件配置项仅source与search_dirs整个脚本直接作为每个事件的处理器执行见 src/transforms/lua/v1/mod.rs。构建时会打印弃用警告DEPRECATED The lua transform API version 1 is deprecated. Please convert your script to version 2.版本 2推荐支持日志与指标引入hooks生命周期机制与timers定时器配置使用#[serde(deny_unknown_fields)]严格校验见 src/transforms/lua/v2/mod.rs。hooks生命周期钩子hooks是 v2 的核心机制包含三个可选/必填的钩子hooks.process必填对每个进入的事件调用。它既可以写内联 Lua 闭包也可以写source中定义的函数名。无论是闭包还是函数签名都是function (event, emit)——event为正在处理的事件emit为事件输出回调。官方默认示例function (event, emit) event.log.field value -- 设置字段值 event.log.another_field nil -- 删除字段 event.log.first, event.log.second nil, event.log.first -- 重命名字段 -- 非常重要发射处理后的事件。 emit(event) endhooks.init可选在首个事件到来时、process之前调用一次签名function (emit)。可用于初始化全局状态如计数器、连接池、加载配置等。测试用例lua_runs_init_hooksrc/transforms/lua/v2/mod.rs验证了init钩子可以通过emit在管道启动阶段就构造并输出新事件。hooks.shutdown可选transform 停止时调用一次签名function (emit)。常用于冲刷残留状态——例如把尚未上报的计数最终输出为指标事件。source初始化脚本source用于注入一段启动代码典型用途是定义被hooks引用的具名函数通过require加载外部 Lua 模块。官方示例给出了两种典型写法-- 写法一定义钩子与定时器所需的全部函数 function init() count 0 end function process() count count 1 end function timer_handler(emit) emit(make_counter(counter)) counter 0 end function shutdown(emit) emit(make_counter(counter)) end function make_counter(value) return metric { name event_counter, kind incremental, timestamp os.date(!*t), counter { value value } } end-- 写法二从外部文件加载含钩子与定时器定义的模块 require(custom_module)需要说明的是source并非必填——如果所有钩子都以内联方式写在hooks中就不需要source见 website/cue/reference/components/transforms/generated/lua.cue 的说明。search_dirs模块搜索目录search_dirs指定require加载 Lua 模块时的绝对路径搜索列表。如果未设置则默认使用配置文件所在的目录。这一默认行为由源码default_config_paths()实现它读取全局的CONFIG_PATHS对文件型配置取其所在目录、对目录型配置直接使用该目录见 src/transforms/lua/v2/mod.rs。构建时每个目录会被格式化为{dir}/?.lua追加到 Lua 的package.path中并保留原有路径见 src/transforms/lua/v2/mod.rs。示例search_dirs: - /etc/vector/lua随后即可在脚本中require(custom_module)。测试用例lua_load_filesrc/transforms/lua/v2/mod.rs演示了从search_dirs指定目录加载script2.lua模块并调用其导出函数的完整链路。timers定时器timers允许配置一个或多个周期性任务每个定时器包含两个必填字段字段类型必填说明interval_secondsuint是执行间隔秒文档示例值为2handlerstring是定时器触发时调用的函数名或内联闭包签名function (emit)timers: - interval_seconds: 5 handler: timer_handler定时器在源码中通过RuntimeTransform::timer_handler驱动每个定时器持有一个唯一的数值 IDhandler 以RegistryKey形式注册在 Lua 虚拟机中见 src/transforms/lua/v2/mod.rs。定时器 handler 可以借助emit周期性输出新事件——这是实现每 N 秒上报一次聚合指标的官方推荐路径。metric_tag_values指标标签的暴露形式Vector 的指标标签可能对应多个值多值标签或空值。该配置控制 Lua 脚本中event.metric.tags的形态single默认标签值以单个字符串暴露与旧版本行为一致。多值标签只显示最后一个赋值空值被忽略full所有标签以字符串或 null 组成的数组形式暴露可完整看到每一个值。源码中该配置映射为MetricTagMode::Single / Full两种模式见 src/transforms/lua/v2/mod.rs并在事件转换为 Lua 值时生效见 lib/vector-core/src/event/lua/metric.rs。注意metric_tag_values取值非法如auto会在配置解析阶段直接被拒绝对应测试rejects_auto_metric_tag_valuessrc/transforms/lua/mod.rs。事件数据模型事件在 Lua 中长什么样官方文档明确process钩子的第一个参数event在 Lua 中表现为一个table其结构与 Vector 的数据模型完全一致。以 lib/vector-core/src/event/lua/event.rs 的实现为准日志事件事件表顶层含log键其值为日志字段表指标事件事件表顶层含metric键其值为指标表包含name、namespace、timestamp、interval_ms、tags、kind以及按类型区分的counter/gauge/set/distribution/aggregated_histogram/aggregated_summary/sketch等子表trace 事件不支持转换时报错。Vector 类型与 Lua 类型映射表官方文档给出了完整的类型映射关系这是编写脚本时必须遵守的契约Vector 类型Lua 类型说明Stringstring—Integerinteger—Floatnumber—Booleanboolean—TimestamptableLua 没有专用时间戳类型按os.date/os.time的约定用表表示Null空字符串Lua 中把字段设为nil表示删除#长度运算符对含 null 的序列行为不符合预期因此 Null 编码为空字符串Maptable—Arraysequence序列是表的特例索引从 1 开始Lua 惯例时间戳的特殊约定时间戳在 Lua 中是一个包含以下字段的表{ year, month, day, hour, min, sec, nanosec, yday, wday, isdst }从 Lua 回传 Vector 时yday、wday、isdst三个字段可以省略相比标准os.time表示Vector 额外支持通过nanosec字段表达亚秒精度。源码 lib/vector-core/src/event/lua/util.rs 验证了这一约定timestamp_to_table会把DateTimeUtc完整写出全部 9 个字段反向的table_to_timestamp读取year/month/day/hour/min/sec并以nanosec缺省为 0补齐纳秒。Null 值的编码细节映射表中Null → 空字符串是一条容易踩坑的规则在 Lua 中向表的字段写入nil意味着删除该字段同时#运算符无法正确处理含空值的序列。因此 Vector 用空字符串表示语义上的 Null 值避免与 Lua 的nil删除语义冲突。测试lua_non_coercible_valuesrc/transforms/lua/v2/mod.rs验证了向字段写入nil后该字段确实被删除。官方实战示例全解析组件文档共提供了 6 个官方示例覆盖日志与指标事件最常见的操作模式。以下逐一给出完整配置、输入输出与要点分析。示例 1添加、重命名、删除日志字段version: 2 hooks: process: | function (event, emit) -- 添加根级字段 event.log.field new value -- 添加嵌套字段 event.log.nested {} event.log.nested.field nested value -- 重命名字段 event.log.renamed_field event.log.field_to_rename event.log.field_to_rename nil -- 删除字段 event.log.field_to_remove nil emit(event) end输入事件field_to_rename: old value field_to_remove: remove me输出事件field: new value nested: field: nested value renamed_field: old value要点字段的增删改通过简单的表赋值/置nil完成event.log直接对应日志的顶层字段空间重命名的惯用法是新字段 旧字段旧字段 nil。对应的单元测试有lua_add_field、lua_read_field、lua_remove_fieldsrc/transforms/lua/v2/mod.rs。示例 2添加、重命名、删除指标标签version: 2 hooks: process: | function (event, emit) -- 添加标签 event.metric.tags.tag new value -- 重命名标签 event.metric.tags.renamed_tag event.log.tag_to_rename event.metric.tags.tag_to_rename nil -- 删除标签 event.metric.tags.tag_to_remove nil emit(event) end输入指标一个logins增量计数器kind: incremental name: logins counter: value: 2.0 tags: tag_to_rename: old value tag_to_remove: remove me输出指标kind: incremental name: logins counter: value: 2.0 tags: tag: new value renamed_tag: old value要点指标事件通过event.metric访问kind字段取incremental或absolute指标值位于按类型命名的子表如counter.value中。多值标签的读写形态由metric_tag_values控制见上文。示例 3完全丢弃一个事件version: 2 hooks: process: | function (event, emit) -- 不调用 emit 函数即可彻底丢弃事件 end输入任何事件输出为空null。要点不调用emit(event)即丢弃事件这是实现过滤语义的最直接方式。测试lua_drop_eventsrc/transforms/lua/v2/mod.rs专门验证了输出流为空的行为。示例 4遍历日志字段version: 2 hooks: process: | function (event, emit) -- 删除所有值为 - 的字段 for f, v in pairs(event) do if v - then event[f] nil end end emit(event) end输入value_to_remove: - value_to_keep: keep输出value_to_keep: keep要点日志事件表可直接用pairs()遍历逐字段过滤清洗。测试lua_pairssrc/transforms/lua/v2/mod.rs展示了for k,v in pairs(event.log)的完整遍历改写模式。示例 5解析时间戳source 具名函数version: 2 hooks: process: process source: | timestamp_pattern (%d%d%d%d)-- (%d%d):(%d%d):(%d%d).?(%d*) function parse_timestamp(str) local year, month, day, hour, min, sec, millis string.match(str, timestamp_pattern) local ms 0 if millis and millis ~ then ms tonumber(millis) end return { year tonumber(year), month tonumber(month), day tonumber(day), hour tonumber(hour), min tonumber(min), sec tonumber(sec), nanosec ms * 1000000 } end function process(event, emit) event.log.timestamp parse_timestamp(event.log.timestamp_string) emit(event) end输入timestamp_string: 2020-04-07 06:26:02.643输出timestamp_string: 2020-04-07 06:26:02.643 timestamp: 2020-04-07 06:26:02.643要点这是hooks.process引用source中具名函数的标准用法。parse_timestamp返回的表严格遵循上文的时间戳约定含nanosec字段Vector 会将其正确转换为内部时间戳类型。示例 6统计日志数量init timers shutdown 组合这是最能体现 v2 生命周期机制的示例用全局计数统计处理过的日志数每 5 秒把累计数作为指标事件输出一次并在关闭时冲刷剩余计数。version: 2 hooks: init: init process: process shutdown: shutdown timers: - interval_seconds: 5 handler: timer_handler source: | function init() count 0 end function process() count count 1 end function timer_handler(emit) emit(make_counter(count)) count 0 end function shutdown(emit) emit(make_counter(count)) end function make_counter(value) return metric { name event_counter, kind incremental, timestamp os.date(!*t), counter { value value } } end输入任意日志事件示例输入为{}。输出名为event_counter、kindincremental的计数指标示例输出counter.value为1.0。要点init在首个事件前初始化全局变量countprocess每处理一个事件即自增计数且不需要调用emit该钩子只做计数不转发原始日志timer_handler每 5 秒构造一个event_counter增量计数指标并通过emit输出随后清零shutdown在停止时把剩余计数最后一次冲刷出去保证数据不丢失make_counter展示了在 Lua 中从零构造指标事件的完整写法name、kind、timestamp、counter.value均为必填语义字段timestamp使用os.date(!*t)生成符合约定的时间戳表。源码实现原理深入 Lua 运行时嵌入式 Lua 5.4 引擎与安全标准库transform 通过mluacrate 创建 Lua 5.4 虚拟机并以StdLib::ALL_SAFE加载安全标准库集合不包含调试库等潜在危险模块以支持加载 C 模块见 src/transforms/lua/v2/mod.rs。所有钩子init/process/shutdown与定时器 handler 都会被编译为mlua::Function并注册为RegistryKey保证在整个生命周期内可被反复调用src/transforms/lua/v2/mod.rs。自动垃圾回收GC控制Lua 的垃圾回收在高事件速率下可能不会自动及时触发导致类似内存泄漏的 RAM 增长模式。为此源码实现了每 16 次调用强制 GC 一次的机制GC_INTERVAL: usize 16见 src/transforms/lua/v2/mod.rs。该间隔大于 1是因为 GC 本身开销较大不宜在每次处理后执行。每次 GC 都会通过内部事件LuaGcTriggered上报当前used_memorysrc/internal_events/lua.rs。事件的双向转换Vector → Lua日志事件经 lib/vector-core/src/event/lua/log.rs 转换为字段表指标事件经 lib/vector-core/src/event/lua/metric.rs 转换为包含name、namespace、timestamp、interval_ms、tags、kind及类型子表的结构化表Lua → Vector事件表必须且只能包含顶层log或metric键之一否则报Event should contain either log or metric key at the top level转换错误lib/vector-core/src/event/lua/event.rs。由于 Lua 脚本可任意改写事件Vector 无法静态推导输出 schema——源码中outputs()会重置输出类型定义Definition::default_for_namespace即下游组件不再假定任何字段结构src/transforms/lua/v2/mod.rs。错误处理与可观测性运行时错误通过内部事件体系上报主要包含三类src/internal_events/lua.rsLuaScriptError脚本运行时报错如error(this is an error)对应component_errors_total计数与ComponentEventsDropped事件错误码如syntax_error、runtime_error、callback_error等LuaBuildError配置/源码构建期错误错误码细分到invalid_hook_init、invalid_hook_process、invalid_timer_handler、runtime_error_gc等 13 种LuaGcTriggered将 GC 触发时的used_memory写入 gauge 指标lua_memory_used_bytes。因此你可以在internal_metrics源中订阅lua_memory_used_bytes指标组件遥测定义见 website/cue/reference/components/transforms/lua.cue监控 Lua 运行时内存水位。学习资源建议官方文档专门为 Lua 新手预留了指引编写有实质业务逻辑的 transform 需要具备 Lua 基础。由于 Lua 本身简单易学阅读官方书籍《Programming in Lua》的前几章或查阅 Lua 参考手册即可满足绝大多数场景。官方文档原文website/cue/reference/components/transforms/lua.cue亦明确指出在动手编写复杂脚本前先掌握 Lua 的表table、函数、pairs/ipairs迭代与string库等核心概念。最佳实践小结优先remap约 60% 的性能差距意味着能不用 Lua 就不用仅当remap无法表达时才选用lua始终使用version: 2v1 已弃用并将被移除且不支持指标事件与钩子/定时器机制利用source组织代码把可复用的具名函数、外部require模块放入sourcehooks中只写函数名引用便于阅读与复用严格遵守类型映射时间戳用含nanosec的约定表、Null 用空字符串、数组索引从 1 开始不要遗漏emit需要向下游传递事件时务必调用emit(event)emit可多次调用以实现事件复制测试lua_duplicate_event验证了单事件双发射的合法性见 src/transforms/lua/v2/mod.rs用定时器做周期性聚合全局状态 timersshutdown冲刷是统计类 transform 的标准实现模式关注lua_memory_used_bytes通过 internal_metrics 观测 Lua 内存配合内置的自动 GC 机制保障长期运行的稳定性。【免费下载链接】vectorA high-performance observability data pipeline.项目地址: https://gitcode.com/GitHub_Trending/vect/vector创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表