diff --git a/userspace/libsinsp/eventformatter.cpp b/userspace/libsinsp/eventformatter.cpp index ded0071d9d..c52456298b 100644 --- a/userspace/libsinsp/eventformatter.cpp +++ b/userspace/libsinsp/eventformatter.cpp @@ -27,10 +27,27 @@ limitations under the License. #ifdef HAS_FILTERING extern sinsp_filter_check_list g_filterlist; +sinsp_evt_formatter::sinsp_evt_formatter(sinsp* inspector) + : m_inspector(inspector) +{ +} + sinsp_evt_formatter::sinsp_evt_formatter(sinsp* inspector, const string& fmt) { m_inspector = inspector; - set_format(fmt); + + gen_event_formatter::output_format of = gen_event_formatter::OF_NORMAL; + + if(m_inspector->get_buffer_format() == sinsp_evt::PF_JSON + || m_inspector->get_buffer_format() == sinsp_evt::PF_JSONEOLS + || m_inspector->get_buffer_format() == sinsp_evt::PF_JSONHEX + || m_inspector->get_buffer_format() == sinsp_evt::PF_JSONHEXASCII + || m_inspector->get_buffer_format() == sinsp_evt::PF_JSONBASE64) + { + of = gen_event_formatter::OF_JSON; + } + + set_format(of, fmt); } sinsp_evt_formatter::~sinsp_evt_formatter() @@ -43,12 +60,14 @@ sinsp_evt_formatter::~sinsp_evt_formatter() } } -void sinsp_evt_formatter::set_format(const string& fmt) +void sinsp_evt_formatter::set_format(gen_event_formatter::output_format of, const string& fmt) { uint32_t j; uint32_t last_nontoken_str_start = 0; string lfmt(fmt); + m_output_format = of; + if(lfmt == "") { throw sinsp_exception("empty formatting token"); @@ -200,25 +219,34 @@ bool sinsp_evt_formatter::resolve_tokens(sinsp_evt *evt, map& val return retval; } +bool sinsp_evt_formatter::get_field_values(gen_event *gevt, std::map &fields) +{ + sinsp_evt *evt = static_cast(gevt); -bool sinsp_evt_formatter::tostring(sinsp_evt* evt, OUT string* res) + return resolve_tokens(evt, fields); +} + +gen_event_formatter::output_format sinsp_evt_formatter::get_output_format() +{ + return m_output_format; +} + +bool sinsp_evt_formatter::tostring_withformat(gen_event* gevt, std::string &output, gen_event_formatter::output_format of) { bool retval = true; const filtercheck_field_info* fi; + sinsp_evt *evt = static_cast(gevt); + uint32_t j = 0; vector::iterator it; - res->clear(); + output.clear(); ASSERT(m_tokenlens.size() == m_tokens.size()); for(j = 0; j < m_tokens.size(); j++) { - if(m_inspector->get_buffer_format() == sinsp_evt::PF_JSON - || m_inspector->get_buffer_format() == sinsp_evt::PF_JSONEOLS - || m_inspector->get_buffer_format() == sinsp_evt::PF_JSONHEX - || m_inspector->get_buffer_format() == sinsp_evt::PF_JSONHEXASCII - || m_inspector->get_buffer_format() == sinsp_evt::PF_JSONBASE64) + if(of == OF_JSON) { Json::Value json_value = m_tokens[j].second->tojson(evt); @@ -268,35 +296,41 @@ bool sinsp_evt_formatter::tostring(sinsp_evt* evt, OUT string* res) { string sstr(str); sstr.resize(tks, ' '); - (*res) += sstr; + output += sstr; } else { - (*res) += str; + output += str; } } } - if(m_inspector->get_buffer_format() == sinsp_evt::PF_JSON - || m_inspector->get_buffer_format() == sinsp_evt::PF_JSONEOLS - || m_inspector->get_buffer_format() == sinsp_evt::PF_JSONHEX - || m_inspector->get_buffer_format() == sinsp_evt::PF_JSONHEXASCII - || m_inspector->get_buffer_format() == sinsp_evt::PF_JSONBASE64) + if(of == OF_JSON) { - (*res) = m_writer.write(m_root); - (*res) = res->substr(0, res->size() - 1); + output = m_writer.write(m_root); + output = output.substr(0, output.size() - 1); } return retval; } +bool sinsp_evt_formatter::tostring(gen_event* gevt, std::string &output) +{ + return tostring_withformat(gevt, output, m_output_format); +} + +bool sinsp_evt_formatter::tostring(sinsp_evt* evt, OUT string* res) +{ + return tostring_withformat(evt, *res, m_output_format); +} + #else // HAS_FILTERING -sinsp_evt_formatter::sinsp_evt_formatter(sinsp* inspector, const string& fmt) +sinsp_evt_formatter::sinsp_evt_formatter(sinsp* inspector) { } -void sinsp_evt_formatter::set_format(const string& fmt) +void sinsp_evt_formatter::set_format(gen_event_formatter::output_format of, const std::string &format) = 0; { throw sinsp_exception("sinsp_evt_formatter unavailable because it was not compiled in the library"); } @@ -306,7 +340,12 @@ bool sinsp_evt_formatter::resolve_tokens(sinsp_evt *evt, map& val throw sinsp_exception("sinsp_evt_formatter unavailable because it was not compiled in the library"); } -bool sinsp_evt_formatter::tostring(sinsp_evt* evt, OUT string* res) +bool sinsp_evt_formatter::tostring(gen_event* gevt, std::string &output) +{ + throw sinsp_exception("sinsp_evt_formatter unavailable because it was not compiled in the library"); +} + +bool sinsp_evt_formatter::tostring_withformat(gen_event* gevt, std::string &output, gen_event_formatter::output_format of) { throw sinsp_exception("sinsp_evt_formatter unavailable because it was not compiled in the library"); } @@ -342,5 +381,40 @@ bool sinsp_evt_formatter_cache::resolve_tokens(sinsp_evt *evt, string &format, m bool sinsp_evt_formatter_cache::tostring(sinsp_evt *evt, string &format, OUT string *res) { - return get_cached_formatter(format)->tostring(evt, res); + return get_cached_formatter(format)->tostring(evt, *res); +} + +sinsp_evt_formatter_factory::sinsp_evt_formatter_factory(sinsp *inspector) + : m_inspector(inspector), m_output_format(gen_event_formatter::OF_NORMAL) +{ +} + +sinsp_evt_formatter_factory::~sinsp_evt_formatter_factory() +{ +} + +void sinsp_evt_formatter_factory::set_output_format(gen_event_formatter::output_format of) +{ + m_formatters.clear(); + + m_output_format = of; +} + +std::shared_ptr sinsp_evt_formatter_factory::create_formatter(const std::string &format) +{ + auto it = m_formatters.find(format); + + if (it != m_formatters.end()) + { + return it->second; + } + + std::shared_ptr ret; + + ret.reset(new sinsp_evt_formatter(m_inspector)); + + ret->set_format(m_output_format, format); + m_formatters[format] = ret; + + return ret; } diff --git a/userspace/libsinsp/eventformatter.h b/userspace/libsinsp/eventformatter.h index 0aa227673c..3294bf3702 100644 --- a/userspace/libsinsp/eventformatter.h +++ b/userspace/libsinsp/eventformatter.h @@ -16,6 +16,9 @@ limitations under the License. */ #pragma once +#include +#include +#include #include class sinsp_filter_check; @@ -29,7 +32,7 @@ class sinsp_filter_check; This class can be used to format an event into a string, based on an arbitrary format. */ -class SINSP_PUBLIC sinsp_evt_formatter +class SINSP_PUBLIC sinsp_evt_formatter : public gen_event_formatter { public: /*! @@ -41,8 +44,12 @@ class SINSP_PUBLIC sinsp_evt_formatter as the one of the sysdig '-p' command line flag, so refer to the sysdig manual for details. */ + sinsp_evt_formatter(sinsp* inspector); + sinsp_evt_formatter(sinsp* inspector, const string& fmt); + void set_format(gen_event_formatter::output_format of, const string& fmt) override; + ~sinsp_evt_formatter(); /*! @@ -57,6 +64,12 @@ class SINSP_PUBLIC sinsp_evt_formatter */ bool resolve_tokens(sinsp_evt *evt, map& values); + // For compatibility with gen_event_filter_factory + // interface. It just calls resolve_tokens(). + bool get_field_values(gen_event *evt, std::map &fields) override; + + gen_event_formatter::output_format get_output_format() override; + /*! \brief Fills res with the string rendering of the event. @@ -68,6 +81,11 @@ class SINSP_PUBLIC sinsp_evt_formatter */ bool tostring(sinsp_evt* evt, OUT string* res); + // For compatibility with gen_event_formatter + bool tostring(gen_event* evt, std::string &output) override; + + bool tostring_withformat(gen_event* evt, std::string &output, gen_event_formatter::output_format of) override; + /*! \brief Fills res with end of capture string rendering of the event. \param res Pointer to the string that will be filled with the result. @@ -78,7 +96,7 @@ class SINSP_PUBLIC sinsp_evt_formatter bool on_capture_end(OUT string* res); private: - void set_format(const string& fmt); + gen_event_formatter::output_format m_output_format; // vector of (full string of the token, filtercheck) pairs // e.g. ("proc.aname[2], ptr to sinsp_filter_check_thread) @@ -123,3 +141,22 @@ class SINSP_PUBLIC sinsp_evt_formatter_cache sinsp *m_inspector; }; /*@}*/ + +class sinsp_evt_formatter_factory : public gen_event_formatter_factory +{ +public: + sinsp_evt_formatter_factory(sinsp *inspector); + virtual ~sinsp_evt_formatter_factory(); + + void set_output_format(gen_event_formatter::output_format of) override; + + std::shared_ptr create_formatter(const std::string &format) override; + +protected: + + // Maps from output string to formatter + std::map> m_formatters; + + sinsp *m_inspector; + gen_event_formatter::output_format m_output_format; +}; diff --git a/userspace/libsinsp/gen_filter.cpp b/userspace/libsinsp/gen_filter.cpp index b2a13acdb7..73029e796e 100644 --- a/userspace/libsinsp/gen_filter.cpp +++ b/userspace/libsinsp/gen_filter.cpp @@ -248,3 +248,18 @@ void gen_event_filter::add_check(gen_event_filter_check* chk) { m_curexpr->add_check((gen_event_filter_check *) chk); } +gen_event_formatter::gen_event_formatter() +{ +} + +gen_event_formatter::~gen_event_formatter() +{ +} + +gen_event_formatter_factory::gen_event_formatter_factory() +{ +} + +gen_event_formatter_factory::~gen_event_formatter_factory() +{ +} diff --git a/userspace/libsinsp/gen_filter.h b/userspace/libsinsp/gen_filter.h index a9ee2a7a63..068015f539 100644 --- a/userspace/libsinsp/gen_filter.h +++ b/userspace/libsinsp/gen_filter.h @@ -16,6 +16,9 @@ along with Falco. If not, see . #pragma once +#include +#include +#include #include /* @@ -155,7 +158,7 @@ class gen_event_filter_expression : public gen_event_filter_check // // An expression is consistent if all its checks are of the same type (or/and). // - // This method returns the expression operator (BO_AND/BO_OR/BO_NONE) if the + // This method returns the expression operator (BO_AND/BO_OR/BO_NONE) if the // expression is consistent. It returns -1 if the expression is not consistent. // int32_t get_expr_boolop(); @@ -206,3 +209,45 @@ class gen_event_filter_factory // Create a new filtercheck virtual gen_event_filter_check *new_filtercheck(const char *fldname) = 0; }; + +class gen_event_formatter +{ +public: + enum output_format { + OF_NORMAL = 0, + OF_JSON = 1 + }; + + gen_event_formatter(); + virtual ~gen_event_formatter(); + + virtual void set_format(output_format of, const std::string &format) = 0; + + // Format the output string with the configured format + virtual bool tostring(gen_event *evt, std::string &output) = 0; + + // In some cases, it may be useful to format an output string + // with a custom format. + virtual bool tostring_withformat(gen_event *evt, std::string &output, output_format of) = 0; + + // The map should map from field name, without the '%' + // (e.g. "proc.name"), to field value (e.g. "nginx") + virtual bool get_field_values(gen_event *evt, std::map &fields) = 0; + + virtual output_format get_output_format() = 0; +}; + + +class gen_event_formatter_factory +{ +public: + gen_event_formatter_factory(); + virtual ~gen_event_formatter_factory(); + + // This should be called before any calls to + // create_formatter(), and changes the output format of new + // formatters. + virtual void set_output_format(gen_event_formatter::output_format of) = 0; + + virtual std::shared_ptr create_formatter(const std::string &format) = 0; +};