diff --git a/digwatch.yaml b/digwatch.yaml index 0c452e78..9d5c98f5 100644 --- a/digwatch.yaml +++ b/digwatch.yaml @@ -5,12 +5,12 @@ rules_file: /etc/digwatch.conf priority_level: warning syslog_output: - enabled: true + enabled: false file_output: enabled: true - filename: "bla.bla" + filename: ./events.txt stdout_output: - enabled: false + enabled: true diff --git a/userspace/digwatch/digwatch.cpp b/userspace/digwatch/digwatch.cpp index 43de8178..0a963106 100644 --- a/userspace/digwatch/digwatch.cpp +++ b/userspace/digwatch/digwatch.cpp @@ -54,13 +54,13 @@ static void usage() } string lua_on_event = "on_event"; +string lua_add_output = "add_output"; // // Event processing loop // void do_inspect(sinsp* inspector, digwatch_rules* rules, - string output_name, lua_State* ls) { int32_t res; @@ -110,9 +110,8 @@ void do_inspect(sinsp* inspector, { lua_pushlightuserdata(ls, ev); lua_pushnumber(ls, ev->get_check_id()); - lua_pushstring(ls, output_name.c_str()); - if(lua_pcall(ls, 3, 0, 0) != 0) + if(lua_pcall(ls, 2, 0, 0) != 0) { const char* lerr = lua_tostring(ls, -1); string err = "Error invoking function output: " + string(lerr); @@ -157,6 +156,38 @@ void add_lua_path(lua_State *ls, string path) lua_pop(ls, 1); } +void add_output(lua_State *ls, output_config oc) +{ + + uint8_t nargs = 1; + lua_getglobal(ls, lua_add_output.c_str()); + + if(!lua_isfunction(ls, -1)) + { + throw sinsp_exception("No function " + lua_add_output + " found. "); + } + lua_pushstring(ls, oc.name.c_str()); + + // If we have options, build up a lua table containing them + if (oc.options.size()) + { + nargs = 2; + lua_createtable(ls, 0, oc.options.size()); + + for (auto it = oc.options.cbegin(); it != oc.options.cend(); ++it) + { + lua_pushstring(ls, (*it).second.c_str()); + lua_setfield(ls, -2, (*it).first.c_str()); + } + } + + if(lua_pcall(ls, nargs, 0, 0) != 0) + { + const char* lerr = lua_tostring(ls, -1); + throw sinsp_exception(string(lerr)); + } + +} // @@ -345,6 +376,11 @@ int digwatch_init(int argc, char **argv) inspector->set_hostname_and_port_resolution_mode(false); + for(std::vector::iterator it = config.m_outputs.begin(); it != config.m_outputs.end(); ++it) + { + add_output(ls, *it); + } + if (infile.size()) { inspector->open(infile); @@ -366,7 +402,6 @@ int digwatch_init(int argc, char **argv) } do_inspect(inspector, rules, - output_name, ls); inspector->close(); diff --git a/userspace/digwatch/lua/output.lua b/userspace/digwatch/lua/output.lua index a15d89c2..5863b297 100644 --- a/userspace/digwatch/lua/output.lua +++ b/userspace/digwatch/lua/output.lua @@ -9,6 +9,29 @@ function mod.stdout(evt, level, format) print (msg) end +function mod.file_validate(options) + if (not type(options.filename) == 'string') then + error("File output needs to be configured with a valid filename") + end + + file, err = io.open(options.filename, "a+") + if file == nil then + error("Error with file output: "..err) + end + file:close() + +end + +function mod.file(evt, level, format, options) + format = "%evt.time: "..levels[level+1].." "..format + formatter = digwatch.formatter(format) + msg = digwatch.format_event(evt, formatter) + + file = io.open(options.filename, "a+") + file:write(msg, "\n") + file:close() +end + function mod.syslog(evt, level, format) formatter = digwatch.formatter(format) diff --git a/userspace/digwatch/lua/rule_loader.lua b/userspace/digwatch/lua/rule_loader.lua index 773328e2..b39069c5 100644 --- a/userspace/digwatch/lua/rule_loader.lua +++ b/userspace/digwatch/lua/rule_loader.lua @@ -159,17 +159,33 @@ function on_done() io.flush() end -local outputs = require('output') +local output_functions = require('output') -function on_event(evt_, rule_id, output_name) - if not (type(outputs[output_name]) == 'function') then - error("rule_loader.on_event(): invalid output_name: ", output_name) +outputs = {} + +function add_output(output_name, config) + if not (type(output_functions[output_name]) == 'function') then + error("rule_loader.add_output(): invalid output_name: "..output_name) end + -- outputs can optionally define a validation function so that we don't + -- find out at runtime (when an event finally matches a rule!) that the config is invalid + if (type(output_functions[output_name.."_validate"]) == 'function') then + output_functions[output_name.."_validate"](config) + end + + table.insert(outputs, {output = output_functions[output_name], config=config}) +end + +function on_event(evt_, rule_id) + if state.outputs[rule_id] == nil then error ("rule_loader.on_event(): event with invalid rule_id: ", rule_id) end - outputs[output_name](evt_, state.outputs[rule_id].level, state.outputs[rule_id].format) + for index,o in ipairs(outputs) do + o.output(evt_, state.outputs[rule_id].level, state.outputs[rule_id].format, o.config) + end + end