Envoy Lua 过滤器通用日志 API:logTrace / logDebug / logInfo / logWarn / logErr / logCritical 源码级使用指南
2026/9/12 7:27:00 网站建设 项目流程

Envoy Lua 过滤器通用日志 API:logTrace / logDebug / logInfo / logWarn / logErr / logCritical 源码级使用指南

【免费下载链接】envoyCloud-native high-performance edge/middle/service proxy项目地址: https://gitcode.com/GitHub_Trending/en/envoy

本指南围绕 Envoy 仓库中定义的 lua_common.rst 文档展开,系统讲解 Envoy 向 Lua 脚本暴露的一组通用日志方法log*()。这组 API 是 Envoy Lua HTTP 过滤器(以及 Lua 集群选择器)中所有暴露给脚本的对象的公共能力,适用于请求处理、响应处理、头部/缓冲区/元数据处理等几乎所有脚本场景。读完本文,你将掌握六个日志方法的完整签名、日志级别与 Envoy 应用日志(spdlog /ENVOY_LOG)的对应关系、参数类型约束与常见错误,以及如何在实际过滤器脚本中用日志输出调试信息。

一、log*()是什么:一段被 16 处文档共同引用的公共定义

在 Envoy 的文档体系中,lua_common.rst 是一段短小而核心的公共内容块,它定义了六个日志方法,并被两处主文档大量复用:

  • HTTP Lua 过滤器文档:共 13 处include引用了该公共块,覆盖 Stream Handle API 的各方法小节(如trailers()route()stats())、Header object API、Buffer wrapper API、Metadata wrapper API、Stream info wrapper API、Connection wrapper API 等;
  • Lua 集群选择器文档:共 3 处引用,用于集群选择器脚本可用的对象。

原文的核心定义只有一句话:这组方法在 Envoy 暴露给 Lua 的所有对象上都可用(supported on all objects that Envoy exposes to Lua)。也就是说,无论你拿到的是请求句柄request_handle、响应句柄response_handle,还是headers()body()metadata()streamInfo()等返回的包装对象,都可以直接调用这六个日志方法,无需区分对象类型。

二、六个日志方法速查

handle:logTrace(message) handle:logDebug(message) handle:logInfo(message) handle:logWarn(message) handle:logErr(message) handle:logCritical(message)

每个方法都接受唯一的参数message(一个 Lua 字符串),并使用 Envoy 的应用日志系统(application logging)记录该消息。六个方法对应六个日志级别,从最细到最严重依次为:logTracelogDebuglogInfologWarnlogErrlogCritical

2.1 日志级别与 Envoy 日志系统的映射

从源码可以精确看到这六个方法最终落到了哪个日志通道。在 source/extensions/filters/common/lua/lua.h 的BaseLuaObject<T>::registerType()中,六个函数作为一个固定数组与类型自身的导出函数一起注册进该对象类型的 metatable:

constexpr std::array log_functions{ ExportedFunction{"logTrace", static_luaLogTrace}, ExportedFunction{"logDebug", static_luaLogDebug}, ExportedFunction{"logInfo", static_luaLogInfo}, ExportedFunction{"logWarn", static_luaLogWarn}, ExportedFunction{"logErr", static_luaLogErr}, ExportedFunction{"logCritical", static_luaLogCritical}, };

每个方法的 C++ 实现(见 lua.h)都遵循同一模式:从 Lua 栈取第二个参数(即message),再调用scriptLog()

template <class T> int BaseLuaObject<T>::luaLogTrace(lua_State* state) { absl::string_view message = Filters::Common::Lua::getStringViewFromLuaString(state, 2); scriptLog(spdlog::level::trace, message); return 0; }

scriptLog()在 source/extensions/filters/common/lua/lua.cc 中实现,将 spdlog 级别逐一映射为 Envoy 的ENVOY_LOG宏,并统一加上"script log: "前缀:

Lua 方法spdlog 级别ENVOY_LOG 输出用途
logTracetraceENVOY_LOG(trace, "script log: {}")极细粒度调试
logDebugdebugENVOY_LOG(debug, ...)调试信息
logInfoinfoENVOY_LOG(info, ...)常规信息
logWarnwarnENVOY_LOG(warn, ...)警告
logErrerrENVOY_LOG(error, ...)错误
logCriticalcriticalENVOY_LOG(critical, ...)严重错误

另外,LuaLoggable继承自Logger::Loggable<Logger::Id::lua>(见 lua.h),意味着这些日志归入 Envoy 日志体系中的lua日志类别(logger category)。因此,脚本日志的可见性受 Envoy 全局日志级别控制——例如以-l trace-l debug启动 Envoy 时,对应级别的脚本日志才会被输出;日志条目中会带有lua类别标识,方便在日志聚合时按类别过滤。

2.2 参数类型约束与常见报错

message必须是字符串。参数校验由 lua.h 中的getStringViewFromLuaString()完成,其底层使用luaL_checklstring

const char* input = luaL_checklstring(state, index, &input_size); return {input, input_size};

源码注释明确指出了两种边界行为:

  • 数字会被隐式转换:Lua 5.1 在运行时提供字符串与数字的自动转换,因此向logTrace(42)这类调用传入数字不会报错,而是被转换为字符串后记录;
  • 表(table)会直接报错:如果传入 table,例如logTrace({}),脚本会以如下错误终止:
[string "..."]:3: bad argument #1 to 'logTrace' (string expected, got table)

因此在写日志时,若数据来自headers():get()等可能返回nil的调用,注意用..拼接或先做空值判断,避免nil参与字符串拼接导致另一类运行时错误。

三、在请求 / 响应脚本中的实战用法

HTTP Lua 过滤器文档 的“脚本示例”一节给出了一组直接可用的日志用法:在请求阶段记录权威头、方法、路径,在响应阶段记录状态码:

function envoy_on_request(request_handle) -- Log information about the request request_handle:logInfo("Authority: "..request_handle:headers():get(":authority")) request_handle:logInfo("Method: "..request_handle:headers():get(":method")) request_handle:logInfo("Path: "..request_handle:headers():get(":path")) end function envoy_on_response(response_handle) -- Log response status code response_handle:logInfo("Status: "..response_handle:headers():get(":status")) end

值得强调的是,envoy_on_requestenvoy_on_response是 Envoy 加载脚本时查找的两个全局函数,分别以协程方式在请求路径和响应路径运行,并通过参数传入对应的 stream handle(详见 lua_filter.rst)。由于log*()是"所有对象通用"的公共方法,上述request_handle/response_handle以及它们返回的 header 对象都支持全部六个级别,开发者可以在关键路径上灵活选择级别输出:

function envoy_on_request(request_handle) local headers = request_handle:headers() headers:logDebug("request headers captured") -- 头部对象同样支持日志 request_handle:logWarn("slow request detected") end

3.1 与bodyChunks()等流式场景的配合

在流式读取请求体时,文档示例展示了另一种基于级别数字的旧式调用request_handle:log(0, chunk:length())(见 lua_filter.rst):

for chunk in request_handle:bodyChunks() do request_handle:log(0, chunk:length()) end

在需要逐块观察数据到达情况时,优先推荐使用语义更清晰的logTrace/logDebug配合块长度与内容前缀输出,例如:

for chunk in request_handle:bodyChunks() do request_handle:logTrace("body chunk received, length="..chunk:length()) end

注意bodyChunks()迭代期间 Envoy 会挂起脚本、逐个投递块且不会缓冲,日志调用本身是同步的,不会破坏这一流式语义。

四、为什么“所有对象”都有日志方法:源码级解释

要理解"所有对象通用"这一承诺,需要回到 C++ 侧的类设计。Envoy 暴露给 Lua 的所有对象都派生自模板基类BaseLuaObject<T>(见 lua.h),其registerType()在注册每个类型时:

  1. 将上表六个日志函数与类型自身的exportedFunctions()合并;
  2. 通过luaL_newmetatable创建该类型对应的 metatable,并把合并后的函数表注册进去;
  3. 同时注册__gc元方法,保证 Lua GC 时正确析构 C++ 对象。

此外,每个方法经由DECLARE_LUA_FUNCTION(Class, Name)宏生成静态 thunk(lua.h),thunk 内部先做 userdata 类型校验,再调用object->checkDead(state)检查对象是否已失效(例如句柄被错误地存为全局变量并在协程外使用),最后才进入真正的实现。这意味着:即使对象处于"失效"状态,调用日志方法也会先触发object used outside of proper scope错误,从而尽早暴露脚本中的句柄滥用问题。

从这一设计可以推断:只要一个对象是BaseLuaObject的子类,它在 Lua 侧就自动具备这六个日志方法,这正好印证了 lua_common.rst 中"支持 Envoy 暴露给 Lua 的所有对象"的表述——包括 stream handle、header 对象、buffer 对象、metadata 对象、stream info 对象、connection 对象、route 对象等,无需逐一单独实现。

五、日志 API 之外:脚本可观测性的完整拼图

log*()是脚本侧主动观测的主要手段,而 Envoy 还在过滤器侧提供了被动观测能力,二者配合可构成完整的可观测性闭环:

  • 脚本错误也会走同一日志通道:从 lua_filter.cc 可以看到,脚本执行出错时,过滤器会把错误状态信息以err级别通过scriptLog()输出,同样带"script log: "前缀,便于在日志中统一检索脚本相关输出;
  • 统计指标:Lua 过滤器默认在.lua.命名空间输出统计,其中errors(脚本执行错误总数)与executionsenvoy_on_request/envoy_on_response执行总次数)两个计数器可直接反映脚本健康度;多过滤器实例可通过stat_prefix区分(详见 lua_filter.rst)。

实际排查脚本问题时,推荐的顺序是:先通过.lua.errors计数器确认是否存在脚本错误 → 用logDebug/logTrace级别的脚本日志定位具体分支 → 结合errors计数器的跳变时间点反查对应请求。由于脚本日志归入lua类别,还可以在日志处理管线中单独路由或告警,避免与其他类别日志混在一起。

六、小结

log*()六个方法是 Envoy Lua 脚本体系中最基础也最通用的可观测性 API:它定义简洁(单一字符串参数)、覆盖面广(所有暴露给 Lua 的对象)、实现透明(直接映射到 Envoy 的lua日志类别与 spdlog 级别)。无论是快速调试头部/体处理逻辑,还是为生产环境埋点观测,都可以在这六个级别中选出合适的粒度。

想进一步深入,可继续阅读:

  • 公共定义原文:docs/root/_include/lua_common.rst
  • HTTP Lua 过滤器完整文档(含 Stream Handle API 与各包装对象 API):docs/root/configuration/http/http_filters/lua_filter.rst
  • Lua 集群选择器文档:docs/root/configuration/http/cluster_specifier/lua.rst
  • 日志方法的 C++ 实现(注册与级别映射):source/extensions/filters/common/lua/lua.h、source/extensions/filters/common/lua/lua.cc
  • 过滤器实现(错误日志与统计):source/extensions/filters/http/lua/lua_filter.cc

【免费下载链接】envoyCloud-native high-performance edge/middle/service proxy项目地址: https://gitcode.com/GitHub_Trending/en/envoy

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询