Add more useful json output.

Instead of using sysdig's json output, which only contains the fields
from the format string without any formatting text, use the string
output to build a json object containing the format string, rule name,
severity, and the event time (converted to a json-friendly ISO8601).

This fixes https://github.com/draios/falco/issues/82.
This commit is contained in:
Mark Stemm 2016-06-06 16:52:40 -07:00
parent 9ab7f52fb0
commit 52a7c77596
5 changed files with 56 additions and 25 deletions

View File

@ -242,7 +242,6 @@ int falco_init(int argc, char **argv)
sinsp* inspector = NULL; sinsp* inspector = NULL;
falco_rules* rules = NULL; falco_rules* rules = NULL;
int op; int op;
sinsp_evt::param_fmt event_buffer_format;
int long_index = 0; int long_index = 0;
string lua_main_filename; string lua_main_filename;
string scap_filename; string scap_filename;
@ -391,7 +390,7 @@ int falco_init(int argc, char **argv)
rules = new falco_rules(inspector, ls, lua_main_filename); rules = new falco_rules(inspector, ls, lua_main_filename);
falco_formats::init(inspector, ls); falco_formats::init(inspector, ls, config.m_json_output);
falco_fields::init(inspector, ls); falco_fields::init(inspector, ls);
falco_logger::init(ls); falco_logger::init(ls);
@ -416,16 +415,6 @@ int falco_init(int argc, char **argv)
inspector->set_hostname_and_port_resolution_mode(false); inspector->set_hostname_and_port_resolution_mode(false);
if (config.m_json_output)
{
event_buffer_format = sinsp_evt::PF_JSON;
}
else
{
event_buffer_format = sinsp_evt::PF_NORMAL;
}
inspector->set_buffer_format(event_buffer_format);
for(std::vector<output_config>::iterator it = config.m_outputs.begin(); it != config.m_outputs.end(); ++it) for(std::vector<output_config>::iterator it = config.m_outputs.begin(); it != config.m_outputs.end(); ++it)
{ {
add_output(ls, *it); add_output(ls, *it);

View File

@ -1,8 +1,11 @@
#include <json/json.h>
#include "formats.h" #include "formats.h"
#include "logger.h" #include "logger.h"
sinsp* falco_formats::s_inspector = NULL; sinsp* falco_formats::s_inspector = NULL;
bool s_json_output = false;
const static struct luaL_reg ll_falco [] = const static struct luaL_reg ll_falco [] =
{ {
@ -11,9 +14,10 @@ const static struct luaL_reg ll_falco [] =
{NULL,NULL} {NULL,NULL}
}; };
void falco_formats::init(sinsp* inspector, lua_State *ls) void falco_formats::init(sinsp* inspector, lua_State *ls, bool json_output)
{ {
s_inspector = inspector; s_inspector = inspector;
s_json_output = json_output;
luaL_openlib(ls, "falco", ll_falco, 0); luaL_openlib(ls, "falco", ll_falco, 0);
} }
@ -42,15 +46,53 @@ int falco_formats::format_event (lua_State *ls)
{ {
string line; string line;
if (!lua_islightuserdata(ls, -1) || !lua_islightuserdata(ls, -2)) { if (!lua_islightuserdata(ls, -1) ||
!lua_isstring(ls, -2) ||
!lua_isstring(ls, -3) ||
!lua_islightuserdata(ls, -4)) {
falco_logger::log(LOG_ERR, "Invalid arguments passed to format_event()\n"); falco_logger::log(LOG_ERR, "Invalid arguments passed to format_event()\n");
throw sinsp_exception("format_event error"); throw sinsp_exception("format_event error");
} }
sinsp_evt* evt = (sinsp_evt*)lua_topointer(ls, 1); sinsp_evt* evt = (sinsp_evt*)lua_topointer(ls, 1);
sinsp_evt_formatter* formatter = (sinsp_evt_formatter*)lua_topointer(ls, 2); const char *rule = (char *) lua_tostring(ls, 2);
const char *level = (char *) lua_tostring(ls, 3);
sinsp_evt_formatter* formatter = (sinsp_evt_formatter*)lua_topointer(ls, 4);
formatter->tostring(evt, &line); formatter->tostring(evt, &line);
// For JSON output, the formatter returned just the output
// string containing the format text and values. Use this to
// build a more detailed object containing the event time,
// rule, severity, full output, and fields.
if (s_json_output) {
Json::Value event;
Json::FastWriter writer;
// Convert the time-as-nanoseconds to a more json-friendly ISO8601.
time_t evttime = evt->get_ts()/1000000000;
char time_sec[20]; // sizeof "YYYY-MM-DDTHH:MM:SS"
char time_ns[12]; // sizeof ".sssssssssZ"
string iso8601evttime;
strftime(time_sec, sizeof(time_sec), "%FT%T", gmtime(&evttime));
snprintf(time_ns, sizeof(time_ns), ".%09luZ", evt->get_ts() % 1000000000);
iso8601evttime = time_sec;
iso8601evttime += time_ns;
event["time"] = iso8601evttime;
event["rule"] = rule;
event["priority"] = level;
event["output"] = line;
line = writer.write(event);
// Json::FastWriter may add a trailing newline. If it
// does, remove it.
if (line[line.length()-1] == '\n')
{
line.resize(line.length()-1);
}
}
lua_pushstring(ls, line.c_str()); lua_pushstring(ls, line.c_str());
return 1; return 1;
} }

View File

@ -13,7 +13,7 @@ class sinsp_evt_formatter;
class falco_formats class falco_formats
{ {
public: public:
static void init(sinsp* inspector, lua_State *ls); static void init(sinsp* inspector, lua_State *ls, bool json_output);
// formatter = falco.formatter(format_string) // formatter = falco.formatter(format_string)
static int formatter(lua_State *ls); static int formatter(lua_State *ls);

View File

@ -6,10 +6,10 @@ mod.levels = levels
local outputs = {} local outputs = {}
function mod.stdout(evt, level, format) function mod.stdout(evt, rule, level, format)
format = "*%evt.time: "..levels[level+1].." "..format format = "*%evt.time: "..levels[level+1].." "..format
formatter = falco.formatter(format) formatter = falco.formatter(format)
msg = falco.format_event(evt, formatter) msg = falco.format_event(evt, rule, levels[level+1], formatter)
print (msg) print (msg)
end end
@ -26,26 +26,26 @@ function mod.file_validate(options)
end end
function mod.file(evt, level, format, options) function mod.file(evt, rule, level, format, options)
format = "%evt.time: "..levels[level+1].." "..format format = "%evt.time: "..levels[level+1].." "..format
formatter = falco.formatter(format) formatter = falco.formatter(format)
msg = falco.format_event(evt, formatter) msg = falco.format_event(evt, rule, levels[level+1], formatter)
file = io.open(options.filename, "a+") file = io.open(options.filename, "a+")
file:write(msg, "\n") file:write(msg, "\n")
file:close() file:close()
end end
function mod.syslog(evt, level, format) function mod.syslog(evt, rule, level, format)
formatter = falco.formatter(format) formatter = falco.formatter(format)
msg = falco.format_event(evt, formatter) msg = falco.format_event(evt, rule, levels[level+1], formatter)
falco.syslog(level, msg) falco.syslog(level, msg)
end end
function mod.event(event, level, format) function mod.event(event, rule, level, format)
for index,o in ipairs(outputs) do for index,o in ipairs(outputs) do
o.output(event, level, format, o.config) o.output(event, rule, level, format, o.config)
end end
end end

View File

@ -256,7 +256,7 @@ function on_event(evt_, rule_id)
rule_output_counts.by_name[rule.rule] = rule_output_counts.by_name[rule.rule] + 1 rule_output_counts.by_name[rule.rule] = rule_output_counts.by_name[rule.rule] + 1
end end
output.event(evt_, rule.level, rule.output) output.event(evt_, rule.rule, rule.level, rule.output)
end end
function print_stats() function print_stats()