Skip to content

Commit

Permalink
Add option to display times in ISO 8601 UTC
Browse files Browse the repository at this point in the history
ISO 8601 time is useful when, say, running falco in a container, which
may have a different /etc/localtime than the host system.

A new config option time_format_iso_8601 controls whether log message
and event times are displayed in ISO 8601 in UTC or in local time. The
default is false (display times in local time).

This option is passed to logger init as well as outputs. For outputs it
eventually changes the time format field from %evt.time/%jevt.time to
%evt.time.iso8601/%jevt.time.iso8601.

Adding this field changes the falco engine version so increment it.

This depends on draios/sysdig#1317.
  • Loading branch information
mstemm committed Feb 13, 2019
1 parent 2af9a72 commit a198171
Show file tree
Hide file tree
Showing 12 changed files with 82 additions and 13 deletions.
5 changes: 5 additions & 0 deletions falco.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,11 @@ rules_file:
- /etc/falco/k8s_audit_rules.yaml
- /etc/falco/rules.d

# If true, the times displayed in log messages and output messages
# will be in ISO 8601. By default, times are displayed in the local
# time zone, as governed by /etc/localtime.
time_format_iso_8601: false

# Whether to output events in json or text
json_output: false

Expand Down
4 changes: 2 additions & 2 deletions userspace/engine/falco_engine_version.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,9 @@ limitations under the License.

// The version of rules/filter fields/etc supported by this falco
// engine.
#define FALCO_ENGINE_VERSION (2)
#define FALCO_ENGINE_VERSION (3)

// This is the result of running "falco --list -N | sha256sum" and
// represents the fields supported by this version of falco. It's used
// at build time to detect a changed set of fields.
#define FALCO_FIELDS_CHECKSUM "32a91c003ab34f198dcb4c3100fbfb22bf402ad36549f193afa43d73f1f2eba3"
#define FALCO_FIELDS_CHECKSUM "b1bf297373fd08c91ffc978dbff5b349ec9338e25b54f70f23e40a609d47924b"
14 changes: 14 additions & 0 deletions userspace/engine/json_evt.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -278,6 +278,7 @@ std::string json_event_filter_check::extract(json_event *evt)
}

std::string jevt_filter_check::s_jevt_time_field = "jevt.time";
std::string jevt_filter_check::s_jevt_time_iso_8601_field = "jevt.time.iso8601";
std::string jevt_filter_check::s_jevt_rawtime_field = "jevt.rawtime";
std::string jevt_filter_check::s_jevt_value_field = "jevt.value";
std::string jevt_filter_check::s_jevt_obj_field = "jevt.obj";
Expand All @@ -288,6 +289,7 @@ jevt_filter_check::jevt_filter_check()
"generic ways to access json events",
{
{s_jevt_time_field, "json event timestamp as a string that includes the nanosecond part"},
{s_jevt_time_iso_8601_field, "json event timestamp in ISO 8601 format, including nanoseconds and time zone offset (in UTC)"},
{s_jevt_rawtime_field, "absolute event timestamp, i.e. nanoseconds from epoch."},
{s_jevt_value_field, "General way to access single property from json object. The syntax is [<json pointer expression>]. The property is returned as a string"},
{s_jevt_obj_field, "The entire json object, stringified"}
Expand All @@ -307,6 +309,12 @@ int32_t jevt_filter_check::parse_field_name(const char *str, bool alloc_state, b
return s_jevt_time_field.size();
}

if(strncmp(s_jevt_time_iso_8601_field.c_str(), str, s_jevt_time_iso_8601_field.size()) == 0)
{
m_field = s_jevt_time_iso_8601_field;
return s_jevt_time_iso_8601_field.size();
}

if(strncmp(s_jevt_rawtime_field.c_str(), str, s_jevt_rawtime_field.size()) == 0)
{
m_field = s_jevt_rawtime_field;
Expand Down Expand Up @@ -361,6 +369,12 @@ uint8_t* jevt_filter_check::extract(gen_event *evt, uint32_t* len, bool sanitize
*len = m_tstr.size();
return (uint8_t *) m_tstr.c_str();
}
else if(m_field == s_jevt_time_iso_8601_field)
{
sinsp_utils::ts_to_iso_8601(evt->get_ts(), &m_tstr);
*len = m_tstr.size();
return (uint8_t *) m_tstr.c_str();
}
else if(m_field == s_jevt_obj_field)
{
json_event *jevt = (json_event *) evt;
Expand Down
1 change: 1 addition & 0 deletions userspace/engine/json_evt.h
Original file line number Diff line number Diff line change
Expand Up @@ -200,6 +200,7 @@ class jevt_filter_check : public json_event_filter_check
private:

static std::string s_jevt_time_field;
static std::string s_jevt_time_iso_8601_field;
static std::string s_jevt_rawtime_field;
static std::string s_jevt_obj_field;
static std::string s_jevt_value_field;
Expand Down
2 changes: 2 additions & 0 deletions userspace/falco/configuration.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ using namespace std;

falco_configuration::falco_configuration()
: m_buffered_outputs(false),
m_time_format_iso_8601(false),
m_webserver_enabled(false),
m_webserver_listen_port(8765),
m_webserver_k8s_audit_endpoint("/k8s_audit"),
Expand Down Expand Up @@ -157,6 +158,7 @@ void falco_configuration::init(string conf_filename, list<string> &cmdline_optio
m_min_priority = (falco_common::priority_type) (it - falco_common::priority_names.begin());

m_buffered_outputs = m_config->get_scalar<bool>("buffered_outputs", false);
m_time_format_iso_8601 = m_config->get_scalar<bool>("time_format_iso_8601", false);

falco_logger::log_stderr = m_config->get_scalar<bool>("log_stderr", false);
falco_logger::log_syslog = m_config->get_scalar<bool>("log_syslog", true);
Expand Down
1 change: 1 addition & 0 deletions userspace/falco/configuration.h
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,7 @@ class falco_configuration
falco_common::priority_type m_min_priority;

bool m_buffered_outputs;
bool m_time_format_iso_8601;

bool m_webserver_enabled;
uint32_t m_webserver_listen_port;
Expand Down
6 changes: 5 additions & 1 deletion userspace/falco/falco.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -666,12 +666,15 @@ int falco_init(int argc, char **argv)
if (conf_filename.size())
{
config.init(conf_filename, cmdline_options);
falco_logger::set_time_format_iso_8601(config.m_time_format_iso_8601);

// log after config init because config determines where logs go
falco_logger::log(LOG_INFO, "Falco initialized with configuration file " + conf_filename + "\n");
}
else
{
config.init(cmdline_options);
falco_logger::set_time_format_iso_8601(config.m_time_format_iso_8601);
falco_logger::log(LOG_INFO, "Falco initialized. No configuration file found, proceeding with defaults\n");
}

Expand Down Expand Up @@ -741,7 +744,8 @@ int falco_init(int argc, char **argv)
outputs->init(config.m_json_output,
config.m_json_include_output_property,
config.m_notifications_rate, config.m_notifications_max_burst,
config.m_buffered_outputs);
config.m_buffered_outputs,
config.m_time_format_iso_8601);

if(!all_events)
{
Expand Down
10 changes: 7 additions & 3 deletions userspace/falco/falco_outputs.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,8 @@ using namespace std;
falco_outputs::falco_outputs(falco_engine *engine)
: m_falco_engine(engine),
m_initialized(false),
m_buffered(true)
m_buffered(true),
m_time_format_iso_8601(false)
{

}
Expand Down Expand Up @@ -63,7 +64,8 @@ falco_outputs::~falco_outputs()

void falco_outputs::init(bool json_output,
bool json_include_output_property,
uint32_t rate, uint32_t max_burst, bool buffered)
uint32_t rate, uint32_t max_burst, bool buffered,
bool time_format_iso_8601)
{
// The engine must have been given an inspector by now.
if(! m_inspector)
Expand All @@ -83,13 +85,14 @@ void falco_outputs::init(bool json_output,
m_notifications_tb.init(rate, max_burst);

m_buffered = buffered;
m_time_format_iso_8601 = time_format_iso_8601;

m_initialized = true;
}

void falco_outputs::add_output(output_config oc)
{
uint8_t nargs = 2;
uint8_t nargs = 3;
lua_getglobal(m_ls, m_lua_add_output.c_str());

if(!lua_isfunction(m_ls, -1))
Expand All @@ -98,6 +101,7 @@ void falco_outputs::add_output(output_config oc)
}
lua_pushstring(m_ls, oc.name.c_str());
lua_pushnumber(m_ls, (m_buffered ? 1 : 0));
lua_pushnumber(m_ls, (m_time_format_iso_8601 ? 1 : 0));

// If we have options, build up a lua table containing them
if (oc.options.size())
Expand Down
4 changes: 3 additions & 1 deletion userspace/falco/falco_outputs.h
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,8 @@ class falco_outputs : public falco_common

void init(bool json_output,
bool json_include_output_property,
uint32_t rate, uint32_t max_burst, bool buffered);
uint32_t rate, uint32_t max_burst, bool buffered,
bool time_format_iso_8601);

void add_output(output_config oc);

Expand All @@ -72,6 +73,7 @@ class falco_outputs : public falco_common
token_bucket m_notifications_tb;

bool m_buffered;
bool m_time_format_iso_8601;

std::string m_lua_add_output = "add_output";
std::string m_lua_output_event = "output_event";
Expand Down
22 changes: 19 additions & 3 deletions userspace/falco/logger.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -30,12 +30,18 @@ const static struct luaL_reg ll_falco [] =
};

int falco_logger::level = LOG_INFO;
bool falco_logger::time_format_iso_8601 = false;

void falco_logger::init(lua_State *ls)
{
luaL_openlib(ls, "falco", ll_falco, 0);
}

void falco_logger::set_time_format_iso_8601(bool val)
{
falco_logger::time_format_iso_8601 = val;
}

void falco_logger::set_level(string &level)
{
if(level == "emergency")
Expand Down Expand Up @@ -105,10 +111,20 @@ void falco_logger::log(int priority, const string msg) {
}

if (falco_logger::log_stderr) {

std::time_t result = std::time(nullptr);
char buf[sizeof "YYYY-MM-DDTHH:MM:SS-0000"];
strftime(buf, sizeof(buf), "%FT%T%z", std::localtime(&result));
fprintf(stderr, "%s: %s", buf, msg.c_str());
if(falco_logger::time_format_iso_8601)
{
char buf[sizeof "YYYY-MM-DDTHH:MM:SS-0000"];
strftime(buf, sizeof(buf), "%FT%T%z", std::gmtime(&result));
fprintf(stderr, "%s: %s", buf, msg.c_str());
}
else
{
string tstr = std::asctime(std::localtime(&result));
tstr = tstr.substr(0, 24);// remove trailling newline
fprintf(stderr, "%s: %s", tstr.c_str(), msg.c_str());
}
}
}

Expand Down
3 changes: 3 additions & 0 deletions userspace/falco/logger.h
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,8 @@ class falco_logger
public:
static void init(lua_State *ls);

static void set_time_format_iso_8601(bool val);

// Will throw exception if level is unknown.
static void set_level(string &level);

Expand All @@ -44,4 +46,5 @@ class falco_logger
static int level;
static bool log_stderr;
static bool log_syslog;
static bool time_format_iso_8601;
};
23 changes: 20 additions & 3 deletions userspace/falco/lua/output.lua
Original file line number Diff line number Diff line change
Expand Up @@ -149,10 +149,26 @@ function output_event(event, rule, source, priority, priority_num, format)
format = format:sub(2)
end

-- time_format_iso_8601 will be the same for all output channels
time_format_iso_8601 = 0

for index,o in ipairs(outputs) do
time_format_iso_8601 = o.options.time_format_iso_8601
break
end

if source == "syscall" then
format = "*%evt.time: "..priority.." "..format
if time_format_iso_8601 == 1 then
format = "*%evt.time.iso8601: "..priority.." "..format
else
format = "*%evt.time: "..priority.." "..format
end
else
format = "*%jevt.time: "..priority.." "..format
if time_format_iso_8601 == 1 then
format = "*%jevt.time: "..priority.." "..format
else
format = "*%jevt.time.iso8601: "..priority.." "..format
end
end

msg = formats.format_event(event, rule, source, priority, format)
Expand All @@ -175,7 +191,7 @@ function output_reopen()
end
end

function add_output(output_name, buffered, options)
function add_output(output_name, buffered, time_format_iso_8601, options)
if not (type(mod[output_name]) == 'function') then
error("rule_loader.add_output(): invalid output_name: "..output_name)
end
Expand All @@ -191,6 +207,7 @@ function add_output(output_name, buffered, options)
end

options.buffered = buffered
options.time_format_iso_8601 = time_format_iso_8601

table.insert(outputs, {output = mod[output_name],
cleanup = mod[output_name.."_cleanup"],
Expand Down

0 comments on commit a198171

Please sign in to comment.