From a0a2a35ed30938f99715cced352a3fd6f89d82dd Mon Sep 17 00:00:00 2001 From: Donatas Abraitis Date: Wed, 28 Aug 2024 17:08:45 +0300 Subject: [PATCH] lib: Add a helper function to dump Lua stack Very handy for debugging. In Lua script just use "log.trace(table)": ``` function on_rib_process_dplane_results(ctx) log.trace(ctx.rinfo.zd_ng) end ``` You will get something like: ``` Aug 28 17:04:36 donatas-laptop zebra[3782199]: [GCZ7N-MM9D9] { 1: { type: 2 weight: 1 flags: 5 backup_idx: 0 vrf_id: 0 nh_encap_type: 0 gate: { value: 5.87967e+08 string: "192.168.11.35" } nh_label_type: 0 srte_color: 0 ifindex: 0 backup_num: 0 } 2: { type: 3 weight: 1 flags: 3 backup_idx: 0 vrf_id: 0 nh_encap_type: 0 nh_label_type: 0 srte_color: 0 ifindex: 4 backup_num: 0 } } ``` Signed-off-by: Donatas Abraitis --- doc/developer/scripting.rst | 5 ++- lib/frrlua.c | 83 ++++++++++++++++++++++++++++++++++--- lib/frrlua.h | 3 ++ 3 files changed, 84 insertions(+), 7 deletions(-) diff --git a/doc/developer/scripting.rst b/doc/developer/scripting.rst index 7a43314490..f51130b1e3 100644 --- a/doc/developer/scripting.rst +++ b/doc/developer/scripting.rst @@ -523,6 +523,7 @@ object which contains methods corresponding to each of the ``zlog`` levels: log.error("error") log.notice("notice") log.debug("debug") + log.trace("trace") The log messages will show up in the daemon's log output. @@ -579,14 +580,14 @@ accomplished with scripting. RM_FAILURE, RM_NOMATCH, RM_MATCH, RM_MATCH_AND_CHANGE) log.info("Evaluating route " .. prefix.network .. " from peer " .. peer.remote_id.string) - + function on_match (prefix, attributes) log.info("Match") return { attributes = RM_MATCH } end - + function on_nomatch (prefix, attributes) log.info("No match") return { diff --git a/lib/frrlua.c b/lib/frrlua.c index 6ad0b5796a..ef081e4bd0 100644 --- a/lib/frrlua.c +++ b/lib/frrlua.c @@ -382,6 +382,12 @@ static const char *frrlua_log_thunk(lua_State *L) return lua_tostring(L, 1); } +static int frrlua_log_trace(lua_State *L) +{ + zlog_debug("%s", frrlua_stackdump(L)); + return 0; +} + static int frrlua_log_debug(lua_State *L) { zlog_debug("%s", frrlua_log_thunk(L)); @@ -413,11 +419,12 @@ static int frrlua_log_error(lua_State *L) } static const luaL_Reg log_funcs[] = { - {"debug", frrlua_log_debug}, - {"info", frrlua_log_info}, - {"notice", frrlua_log_notice}, - {"warn", frrlua_log_warn}, - {"error", frrlua_log_error}, + { "trace", frrlua_log_trace }, + { "debug", frrlua_log_debug }, + { "info", frrlua_log_info }, + { "notice", frrlua_log_notice }, + { "warn", frrlua_log_warn }, + { "error", frrlua_log_error }, {}, }; @@ -432,6 +439,67 @@ void frrlua_export_logging(lua_State *L) * Debugging. */ +void lua_table_dump(lua_State *L, int index, struct buffer *buf, int level) +{ + char tmpbuf[64] = {}; + + lua_pushnil(L); + + while (lua_next(L, index) != 0) { + int key_type; + int value_type; + + for (int i = 0; i < level; i++) + buffer_putstr(buf, " "); + + key_type = lua_type(L, -2); + if (key_type == LUA_TSTRING) { + const char *key = lua_tostring(L, -2); + + buffer_putstr(buf, key); + buffer_putstr(buf, ": "); + } else if (key_type == LUA_TNUMBER) { + snprintf(tmpbuf, sizeof(tmpbuf), "%g", + lua_tonumber(L, -2)); + buffer_putstr(buf, tmpbuf); + buffer_putstr(buf, ": "); + } + + value_type = lua_type(L, -1); + switch (value_type) { + case LUA_TSTRING: + snprintf(tmpbuf, sizeof(tmpbuf), "\"%s\"\n", + lua_tostring(L, -1)); + buffer_putstr(buf, tmpbuf); + break; + case LUA_TBOOLEAN: + snprintf(tmpbuf, sizeof(tmpbuf), "%s\n", + lua_toboolean(L, -1) ? "true" : "false"); + buffer_putstr(buf, tmpbuf); + break; + case LUA_TNUMBER: + snprintf(tmpbuf, sizeof(tmpbuf), "%g\n", + lua_tonumber(L, -1)); + buffer_putstr(buf, tmpbuf); + break; + case LUA_TTABLE: + buffer_putstr(buf, "{\n"); + lua_table_dump(L, lua_gettop(L), buf, level + 1); + for (int i = 0; i < level; i++) + buffer_putstr(buf, " "); + buffer_putstr(buf, "}\n"); + break; + default: + snprintf(tmpbuf, sizeof(tmpbuf), "%s\n", + lua_typename(L, value_type)); + buffer_putstr(buf, tmpbuf); + break; + } + + lua_pop(L, 1); + } +} + char *frrlua_stackdump(lua_State *L) { int top = lua_gettop(L); @@ -458,6 +526,11 @@ char *frrlua_stackdump(lua_State *L) lua_tonumber(L, i)); buffer_putstr(buf, tmpbuf); break; + case LUA_TTABLE: /* tables */ + buffer_putstr(buf, "{\n"); + lua_table_dump(L, i, buf, 1); + buffer_putstr(buf, "}\n"); + break; default: /* other values */ snprintf(tmpbuf, sizeof(tmpbuf), "%s\n", lua_typename(L, t)); diff --git a/lib/frrlua.h b/lib/frrlua.h index dc0f4d9986..e407a4492f 100644 --- a/lib/frrlua.h +++ b/lib/frrlua.h @@ -181,6 +181,9 @@ int frrlua_table_get_integer(lua_State *L, const char *key); */ void frrlua_export_logging(lua_State *L); +/* A helper fuction that dumps the Lua stack */ +void lua_table_dump(lua_State *L, int index, struct buffer *buf, int level); + /* * Dump Lua stack to a string. * -- 2.39.5