diff --git a/userspace/digwatch/digwatch.cpp b/userspace/digwatch/digwatch.cpp index ecfe810d..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; - - } } @@ -111,7 +116,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 +125,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 +152,6 @@ int digwatch_init(int argc, char **argv) { case 'h': usage(); - result = EXIT_SUCCESS; goto exit; case 'm': lua_main_filename = optarg; @@ -220,7 +224,8 @@ int digwatch_init(int argc, char **argv) do_inspect(inspector, rules, - formats); + formats, + ls); inspector->close(); } @@ -242,7 +247,10 @@ exit: delete inspector; } - lua_close(ls); + if(ls) + { + lua_close(ls); + } return result; } diff --git a/userspace/digwatch/formats.cpp b/userspace/digwatch/formats.cpp index 531c54e5..2c7d0f83 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,13 @@ 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 +39,25 @@ 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) +int digwatch_formats::format_event (lua_State *ls) { - return g_format_map[index]; + 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..0bda6965 100644 --- a/userspace/digwatch/lua/compiler.lua +++ b/userspace/digwatch/lua/compiler.lua @@ -167,13 +167,13 @@ 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, mname, fname, args) + return {type = "FunctionCall", mname = mname, fname = fname, arguments = args, source = str} end local function rule(filter, output) if not output then - output = outputformat("") + output = outputformat(nil) end return {type = "Rule", filter = filter, output = output} end @@ -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" * 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 a7963d9f..bd913280 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,10 +74,31 @@ 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 +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() @@ -90,8 +113,9 @@ 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 + + set_output(line_ast.output) -- Store the index of this formatter in each relational expression that -- this rule contains. @@ -100,8 +124,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 +136,15 @@ end function on_done() install_filter(state.filter_ast) end + +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 +