From f71de57a9097e50f5980bbdc8bfcb5f6361a1e7c Mon Sep 17 00:00:00 2001 From: Henri DF Date: Sun, 28 Feb 2016 20:26:42 -0800 Subject: [PATCH 1/5] fix unused vars warning in digwatch.cpp --- userspace/digwatch/digwatch.cpp | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/userspace/digwatch/digwatch.cpp b/userspace/digwatch/digwatch.cpp index ecfe810d..4e438cae 100644 --- a/userspace/digwatch/digwatch.cpp +++ b/userspace/digwatch/digwatch.cpp @@ -111,7 +111,7 @@ void do_inspect(sinsp* inspector, // int digwatch_init(int argc, char **argv) { - int result; + int result = EXIT_SUCCESS; sinsp* inspector = NULL; digwatch_rules* rules = NULL; digwatch_formats* formats = NULL; @@ -120,7 +120,7 @@ int digwatch_init(int argc, char **argv) int long_index = 0; string lua_main_filename; string lua_dir = DIGWATCH_INSTALLATION_DIR; - lua_State* ls; + lua_State* ls = NULL; static struct option long_options[] = { @@ -147,7 +147,6 @@ int digwatch_init(int argc, char **argv) { case 'h': usage(); - result = EXIT_SUCCESS; goto exit; case 'm': lua_main_filename = optarg; @@ -242,7 +241,10 @@ exit: delete inspector; } - lua_close(ls); + if(ls) + { + lua_close(ls); + } return result; } From 1c04ed7874beffb3cad8bcbffaf524a869053b0d Mon Sep 17 00:00:00 2001 From: Henri DF Date: Sun, 28 Feb 2016 21:06:29 -0800 Subject: [PATCH 2/5] rework digwatch event output handling the high-level change is that events matching a rule are now send into a lua "on_event" function for handling, rather than doing the handling down in c++. more specifics: before, the lua "load_rule" function registered formatters with associated IDs with the c++ side, which later used this state to reconcile events with formats and print output accordingly. now, no such state is kept on the c++ side. the lua "load_rule" function maintains the id->formatters map, and uses it to print outputs when it receives events. this change simplifies the existing flow and will also make the forthcoming implementation of function outputs far simpler than it would have been in the current setup. --- userspace/digwatch/digwatch.cpp | 34 ++++++++++++--------- userspace/digwatch/formats.cpp | 42 ++++++++++++++------------ userspace/digwatch/formats.h | 8 +++-- userspace/digwatch/lua/compiler.lua | 2 +- userspace/digwatch/lua/rule_loader.lua | 23 +++++++++++--- 5 files changed, 67 insertions(+), 42 deletions(-) diff --git a/userspace/digwatch/digwatch.cpp b/userspace/digwatch/digwatch.cpp index 4e438cae..fd0c47d9 100644 --- a/userspace/digwatch/digwatch.cpp +++ b/userspace/digwatch/digwatch.cpp @@ -45,18 +45,19 @@ static void usage() ); } +string lua_on_event = "on_event"; // // Event processing loop // void do_inspect(sinsp* inspector, digwatch_rules* rules, - digwatch_formats* formats) + digwatch_formats* formats, + lua_State* ls) { int32_t res; sinsp_evt* ev; string line; - sinsp_evt_formatter* formatter; // // Loop through the events @@ -89,20 +90,24 @@ void do_inspect(sinsp* inspector, continue; } - formatter = formats->lookup_formatter(ev->get_check_id()); - if(!formatter) + lua_getglobal(ls, lua_on_event.c_str()); + + if(lua_isfunction(ls, -1)) { - throw sinsp_exception("Error: No formatter for event with id %d " + to_string(ev->get_check_id())); + lua_pushlightuserdata(ls, ev); + lua_pushnumber(ls, ev->get_check_id()); + + if(lua_pcall(ls, 2, 0, 0) != 0) + { + const char* lerr = lua_tostring(ls, -1); + string err = "Error installing rules: " + string(lerr); + throw sinsp_exception(err); + } } - - bool has_all = formatter->tostring(ev, &line); - if(!has_all) { - cout << "(missing fields) "; + else + { + throw sinsp_exception("No function " + lua_on_event + " found in lua compiler module"); } - cout << line; - cout << endl; - - } } @@ -219,7 +224,8 @@ int digwatch_init(int argc, char **argv) do_inspect(inspector, rules, - formats); + formats, + ls); inspector->close(); } diff --git a/userspace/digwatch/formats.cpp b/userspace/digwatch/formats.cpp index 531c54e5..b7f2c9d8 100644 --- a/userspace/digwatch/formats.cpp +++ b/userspace/digwatch/formats.cpp @@ -6,12 +6,12 @@ extern "C" { #include "lauxlib.h" } -std::map g_format_map; sinsp* g_inspector; const static struct luaL_reg ll_digwatch [] = { - {"set_formatter", &digwatch_formats::set_formatter}, + {"formatter", &digwatch_formats::formatter}, + {"format_event", &digwatch_formats::format_event}, {NULL,NULL} }; @@ -24,20 +24,12 @@ digwatch_formats::digwatch_formats(sinsp* inspector, lua_State *ls) luaL_openlib(m_ls, "digwatch", ll_digwatch, 0); } -int digwatch_formats::set_formatter (lua_State *ls) { - uint32_t index = luaL_checkinteger(ls, 1); - string format = luaL_checkstring(ls, 2); - +int digwatch_formats::formatter(lua_State *ls) { + string format = luaL_checkstring(ls, 1); + sinsp_evt_formatter* formatter; try { - if(format == "" || format == "default") - { - g_format_map[index] = new sinsp_evt_formatter(g_inspector, DEFAULT_OUTPUT_STR); - } - else - { - g_format_map[index] = new sinsp_evt_formatter(g_inspector, format); - } + formatter = new sinsp_evt_formatter(g_inspector, format); } catch(sinsp_exception& e) { @@ -46,12 +38,24 @@ int digwatch_formats::set_formatter (lua_State *ls) { throw sinsp_exception("set_formatter error"); } - return 0; + lua_pushlightuserdata(ls, formatter); + + return 1; } -sinsp_evt_formatter* digwatch_formats::lookup_formatter(uint32_t index) -{ - return g_format_map[index]; +int digwatch_formats::format_event (lua_State *ls) { + string line; + + if (!lua_islightuserdata(ls, -1) || !lua_islightuserdata(ls, -2)) { + string err = "invalid arguments passed to format_event() "; + throw sinsp_exception("format_event error"); + } + sinsp_evt* evt = (sinsp_evt*)lua_topointer(ls, 1); + sinsp_evt_formatter* formatter = (sinsp_evt_formatter*)lua_topointer(ls, 2); + + formatter->tostring(evt, &line); + + lua_pushstring(ls, line.c_str()); + return 1; } - diff --git a/userspace/digwatch/formats.h b/userspace/digwatch/formats.h index 7cb84c61..913c461c 100644 --- a/userspace/digwatch/formats.h +++ b/userspace/digwatch/formats.h @@ -10,9 +10,11 @@ class digwatch_formats public: digwatch_formats(sinsp* inspector, lua_State *ls); - // set_formatter(index, format_string) - static int set_formatter(lua_State *ls); - sinsp_evt_formatter* lookup_formatter(uint32_t index); + // formatter = digwatch.formatter(format_string) + static int formatter(lua_State *ls); + + // formatted_string = digwatch.format_event(evt, formatter) + static int format_event(lua_State *ls); private: lua_State* m_ls; diff --git a/userspace/digwatch/lua/compiler.lua b/userspace/digwatch/lua/compiler.lua index aadd33bc..f9fa99b1 100644 --- a/userspace/digwatch/lua/compiler.lua +++ b/userspace/digwatch/lua/compiler.lua @@ -173,7 +173,7 @@ end local function rule(filter, output) if not output then - output = outputformat("") + output = outputformat(nil) end return {type = "Rule", filter = filter, output = output} end diff --git a/userspace/digwatch/lua/rule_loader.lua b/userspace/digwatch/lua/rule_loader.lua index a7963d9f..d0291133 100644 --- a/userspace/digwatch/lua/rule_loader.lua +++ b/userspace/digwatch/lua/rule_loader.lua @@ -5,6 +5,8 @@ --]] +local DEFAULT_OUTPUT_FORMAT = "%evt.num %evt.time %evt.cpu %proc.name (%thread.tid) %evt.dir %evt.type %evt.args" + local compiler = require "compiler" --[[ @@ -72,7 +74,7 @@ local state to the line-oriented compiler. --]] local function init() - return {macros={}, filter_ast=nil, n_rules=0} + return {macros={}, filter_ast=nil, n_rules=0, outputs={}} end @@ -90,8 +92,16 @@ function load_rule(r) error ("Unexpected type in load_rule: "..line_ast.type) end - -- Register a formatter with the output string from this rule - digwatch.set_formatter(state.n_rules, line_ast.output.value) + state.n_rules = state.n_rules + 1 + + local format + if line_ast.output.value==nil then + format = DEFAULT_OUTPUT_FORMAT + else + format = line_ast.output.value + end + + state.outputs[state.n_rules] = digwatch.formatter(format) -- Store the index of this formatter in each relational expression that -- this rule contains. @@ -100,8 +110,6 @@ function load_rule(r) -- event. mark_relational_nodes(line_ast.filter.value, state.n_rules) - state.n_rules = state.n_rules + 1 - -- Rule ASTs are merged together into one big AST, with "OR" between each -- rule. if (state.filter_ast == nil) then @@ -114,3 +122,8 @@ end function on_done() install_filter(state.filter_ast) end + +function on_event(evt, rule_id) + print(digwatch.format_event(evt, state.outputs[rule_id])) +end + From 55b2490314b4067e4c56f0f7e58fd9c42529413c Mon Sep 17 00:00:00 2001 From: Henri DF Date: Sun, 28 Feb 2016 21:14:46 -0800 Subject: [PATCH 3/5] coding convention --- userspace/digwatch/formats.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/userspace/digwatch/formats.cpp b/userspace/digwatch/formats.cpp index b7f2c9d8..2c7d0f83 100644 --- a/userspace/digwatch/formats.cpp +++ b/userspace/digwatch/formats.cpp @@ -24,7 +24,8 @@ digwatch_formats::digwatch_formats(sinsp* inspector, lua_State *ls) luaL_openlib(m_ls, "digwatch", ll_digwatch, 0); } -int digwatch_formats::formatter(lua_State *ls) { +int digwatch_formats::formatter(lua_State *ls) +{ string format = luaL_checkstring(ls, 1); sinsp_evt_formatter* formatter; try @@ -43,7 +44,8 @@ int digwatch_formats::formatter(lua_State *ls) { return 1; } -int digwatch_formats::format_event (lua_State *ls) { +int digwatch_formats::format_event (lua_State *ls) +{ string line; if (!lua_islightuserdata(ls, -1) || !lua_islightuserdata(ls, -2)) { From 1b7a5bd1190996edcc1ce2a6fba56478d3beeaac Mon Sep 17 00:00:00 2001 From: Henri DF Date: Mon, 29 Feb 2016 13:36:14 -0800 Subject: [PATCH 4/5] compiler: keep source in FunctionCall ASTs --- userspace/digwatch/lua/compiler.lua | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/userspace/digwatch/lua/compiler.lua b/userspace/digwatch/lua/compiler.lua index f9fa99b1..eed9b52d 100644 --- a/userspace/digwatch/lua/compiler.lua +++ b/userspace/digwatch/lua/compiler.lua @@ -167,8 +167,8 @@ local function outputformat (format) return {type = "OutputFormat", value = format} end -local function functioncall (name, args) - return {type = "FunctionCall", name = name, arguments = args} +local function functioncall (str, name, args) + return {type = "FunctionCall", name = name, arguments = args, source = str} end local function rule(filter, output) @@ -217,7 +217,7 @@ local G = { MacroDef = (C(V"Macro") * V"Skip" * V"Colon" * (V"Filter")); FuncArgs = symb("(") * list(V"Value", symb(",")) * symb(")"); - Output = ((V"Name" * V"FuncArgs") / functioncall) + P(1)^0 / outputformat; + Output = (C(V"Name" * V"FuncArgs") / functioncall) + P(1)^0 / outputformat; -- Terminals Value = terminal "Number" + terminal "String" + terminal "BareString"; From 6a99c1a9788c10ec78b8cc2e846d48124955967b Mon Sep 17 00:00:00 2001 From: Henri DF Date: Mon, 29 Feb 2016 20:15:50 -0800 Subject: [PATCH 5/5] Basic support for function calls in outputs --- userspace/digwatch/lua/compiler.lua | 8 ++--- userspace/digwatch/lua/rule_loader.lua | 41 +++++++++++++++++++------- 2 files changed, 35 insertions(+), 14 deletions(-) diff --git a/userspace/digwatch/lua/compiler.lua b/userspace/digwatch/lua/compiler.lua index eed9b52d..0bda6965 100644 --- a/userspace/digwatch/lua/compiler.lua +++ b/userspace/digwatch/lua/compiler.lua @@ -167,8 +167,8 @@ local function outputformat (format) return {type = "OutputFormat", value = format} end -local function functioncall (str, name, args) - return {type = "FunctionCall", name = name, arguments = args, source = str} +local function functioncall (str, mname, fname, args) + return {type = "FunctionCall", mname = mname, fname = fname, arguments = args, source = str} end local function rule(filter, output) @@ -217,7 +217,7 @@ local G = { MacroDef = (C(V"Macro") * V"Skip" * V"Colon" * (V"Filter")); FuncArgs = symb("(") * list(V"Value", symb(",")) * symb(")"); - Output = (C(V"Name" * V"FuncArgs") / functioncall) + P(1)^0 / outputformat; + Output = (C(V"Name" * P(".") * V"Name" * V"FuncArgs") / functioncall) + P(1)^0 / outputformat; -- Terminals Value = terminal "Number" + terminal "String" + terminal "BareString"; @@ -462,7 +462,7 @@ function print_ast(ast, level) print(ast.value) elseif t == "FunctionCall" then - print(ast.name .. "(" ) + print(ast.mname..ast.fname .. "(" ) print_ast(ast.arguments) print(")") diff --git a/userspace/digwatch/lua/rule_loader.lua b/userspace/digwatch/lua/rule_loader.lua index d0291133..bd913280 100644 --- a/userspace/digwatch/lua/rule_loader.lua +++ b/userspace/digwatch/lua/rule_loader.lua @@ -78,6 +78,27 @@ local function init() end +function set_output(output_ast) + + if(output_ast.type == "OutputFormat") then + + local format + if output_ast.value==nil then + format = DEFAULT_OUTPUT_FORMAT + else + format = output_ast.value + end + + state.outputs[state.n_rules] = {type="format", formatter=digwatch.formatter(format)} + + elseif (output_ast.type == "FunctionCall") then + require(output_ast.mname) + state.outputs[state.n_rules] = {type="function", mname = output_ast.mname, source=output_ast.source} + else + error ("Unexpected type in set_output: ".. output_ast.type) + end +end + function load_rule(r) if (state == nil) then state = init() @@ -94,14 +115,7 @@ function load_rule(r) state.n_rules = state.n_rules + 1 - local format - if line_ast.output.value==nil then - format = DEFAULT_OUTPUT_FORMAT - else - format = line_ast.output.value - end - - state.outputs[state.n_rules] = digwatch.formatter(format) + set_output(line_ast.output) -- Store the index of this formatter in each relational expression that -- this rule contains. @@ -123,7 +137,14 @@ function on_done() install_filter(state.filter_ast) end -function on_event(evt, rule_id) - print(digwatch.format_event(evt, state.outputs[rule_id])) +evt = nil +function on_event(evt_, rule_id) + if state.outputs[rule_id].type == "format" then + print(digwatch.format_event(evt, state.outputs[rule_id].formatter)) + elseif state.outputs[rule_id].type == "function" then + local reqmod = "local "..state.outputs[rule_id].mname.." = require('" ..state.outputs[rule_id].mname .. "')"; + evt = evt_ + assert(loadstring(reqmod .. "; print(type(evt));" ..state.outputs[rule_id].source))() + end end