diff --git a/userspace/falco/app/actions/create_signal_handlers.cpp b/userspace/falco/app/actions/create_signal_handlers.cpp index 7cc10d53..fd59d848 100644 --- a/userspace/falco/app/actions/create_signal_handlers.cpp +++ b/userspace/falco/app/actions/create_signal_handlers.cpp @@ -131,9 +131,9 @@ falco::app::run_result falco::app::actions::create_signal_handlers(falco::app::s { std::string rule = "Falco internal: hot restart failure"; std::string msg = rule + ": " + err; - std::map o = {}; + auto fields = nlohmann::json::object(); auto now = std::chrono::duration_cast(std::chrono::system_clock::now().time_since_epoch()).count(); - s.outputs->handle_msg(now, falco_common::PRIORITY_CRITICAL, msg, rule, o); + s.outputs->handle_msg(now, falco_common::PRIORITY_CRITICAL, msg, rule, fields); } return success; diff --git a/userspace/falco/app/actions/process_events.cpp b/userspace/falco/app/actions/process_events.cpp index 0e91346d..07537901 100644 --- a/userspace/falco/app/actions/process_events.cpp +++ b/userspace/falco/app/actions/process_events.cpp @@ -228,11 +228,10 @@ static falco::app::run_result do_inspect( { sinsp_utils::ts_to_string(duration_start, &last_event_time_str, false, true); } - std::map o = { - {"last_event_time", last_event_time_str}, - }; + nlohmann::json fields; + fields["last_event_time"] = last_event_time_str; auto now = std::chrono::duration_cast(std::chrono::system_clock::now().time_since_epoch()).count(); - s.outputs->handle_msg(now, falco_common::PRIORITY_DEBUG, msg, rule, o); + s.outputs->handle_msg(now, falco_common::PRIORITY_DEBUG, msg, rule, fields); // Reset the timeouts counter, Falco alerted timeouts_since_last_success_or_msg = 0; } diff --git a/userspace/falco/event_drops.cpp b/userspace/falco/event_drops.cpp index fc052476..fef71f01 100644 --- a/userspace/falco/event_drops.cpp +++ b/userspace/falco/event_drops.cpp @@ -156,7 +156,7 @@ bool syscall_evt_drop_mgr::perform_actions(uint64_t now, scap_stats &delta, bool case syscall_evt_drop_action::ALERT: { - std::map output_fields; + nlohmann::json output_fields; output_fields["n_evts"] = std::to_string(delta.n_evts); /* Total number of kernel side events actively traced (not including events discarded due to simple consumer mode in eBPF case). */ output_fields["n_drops"] = std::to_string(delta.n_drops); /* Number of all kernel side event drops out of n_evts. */ output_fields["n_drops_buffer_total"] = std::to_string(delta.n_drops_buffer); /* Total number of kernel side drops due to full buffer, includes all categories below, likely higher than sum of syscall categories. */ diff --git a/userspace/falco/falco_outputs.cpp b/userspace/falco/falco_outputs.cpp index 5f39d6a3..a862a707 100644 --- a/userspace/falco/falco_outputs.cpp +++ b/userspace/falco/falco_outputs.cpp @@ -161,8 +161,13 @@ void falco_outputs::handle_msg(uint64_t ts, falco_common::priority_type priority, std::string &msg, std::string &rule, - std::map &output_fields) + nlohmann::json &output_fields) { + if (!output_fields.is_object()) + { + throw falco_exception("falco_outputs: output fields must be key-value maps"); + } + falco_outputs::ctrl_msg cmsg = {}; cmsg.ts = ts; cmsg.priority = priority; @@ -202,7 +207,7 @@ void falco_outputs::handle_msg(uint64_t ts, sinsp_utils::ts_to_string(ts, ×tr, false, true); cmsg.msg = timestr + ": " + falco_common::format_priority(priority) + " " + msg + " ("; - for(auto &pair : output_fields) + for(auto &pair : output_fields.items()) { if(first) { @@ -212,7 +217,11 @@ void falco_outputs::handle_msg(uint64_t ts, { cmsg.msg += " "; } - cmsg.msg += pair.first + "=" + pair.second; + if (!pair.value().is_primitive()) + { + throw falco_exception("falco_outputs: output fields must be key-value maps"); + } + cmsg.msg += pair.key() + "=" + pair.value().dump(); } cmsg.msg += ")"; } diff --git a/userspace/falco/falco_outputs.h b/userspace/falco/falco_outputs.h index beedc60f..c51726f9 100644 --- a/userspace/falco/falco_outputs.h +++ b/userspace/falco/falco_outputs.h @@ -66,7 +66,7 @@ public: falco_common::priority_type priority, std::string &msg, std::string &rule, - std::map &output_fields); + nlohmann::json &output_fields); /*! \brief Sends a cleanup message to all outputs. diff --git a/userspace/falco/outputs.h b/userspace/falco/outputs.h index 0b562f7c..1155c8b1 100644 --- a/userspace/falco/outputs.h +++ b/userspace/falco/outputs.h @@ -21,6 +21,7 @@ limitations under the License. #include "falco_common.h" #include "gen_filter.h" +#include namespace falco { @@ -49,7 +50,7 @@ struct message std::string msg; std::string rule; std::string source; - std::map fields; + nlohmann::json fields; std::set tags; }; diff --git a/userspace/falco/outputs_grpc.cpp b/userspace/falco/outputs_grpc.cpp index 548aefb8..49e52090 100644 --- a/userspace/falco/outputs_grpc.cpp +++ b/userspace/falco/outputs_grpc.cpp @@ -79,9 +79,13 @@ void falco::outputs::output_grpc::output(const message *msg) // output fields auto &fields = *grpc_res.mutable_output_fields(); - for(const auto &kv : msg->fields) + for(const auto &kv : msg->fields.items()) { - fields[kv.first] = kv.second; + if (!kv.value().is_primitive()) + { + throw falco_exception("output_grpc: output fields must be key-value maps"); + } + fields[kv.key()] = kv.value().dump(); } // hostname diff --git a/userspace/falco/stats_writer.cpp b/userspace/falco/stats_writer.cpp index a423cfa3..49c31e66 100644 --- a/userspace/falco/stats_writer.cpp +++ b/userspace/falco/stats_writer.cpp @@ -162,8 +162,7 @@ void stats_writer::worker() noexcept { std::string rule = "Falco internal: metrics snapshot"; std::string msg = "Falco metrics snapshot"; - std::map fields = {m.output_fields.begin(), m.output_fields.end()}; - m_outputs->handle_msg(m.ts, falco_common::PRIORITY_INFORMATIONAL, msg, rule, fields); + m_outputs->handle_msg(m.ts, falco_common::PRIORITY_INFORMATIONAL, msg, rule, m.output_fields); } if (use_file) @@ -188,7 +187,7 @@ stats_writer::collector::collector(const std::shared_ptr& writer) } void stats_writer::collector::get_metrics_output_fields_wrapper( - std::unordered_map& output_fields, + nlohmann::json& output_fields, const std::shared_ptr& inspector, uint64_t now, const std::string& src, uint64_t num_evts, double stats_snapshot_time_delta_sec) { @@ -199,14 +198,14 @@ void stats_writer::collector::get_metrics_output_fields_wrapper( const scap_machine_info* machine_info = inspector->get_machine_info(); /* Wrapper fields useful for statistical analyses and attributions. Always enabled. */ - output_fields["evt.time"] = std::to_string(now); /* Some ETLs may prefer a consistent timestamp within output_fields. */ + output_fields["evt.time"] = now; /* Some ETLs may prefer a consistent timestamp within output_fields. */ output_fields["falco.version"] = FALCO_VERSION; - output_fields["falco.start_ts"] = std::to_string(agent_info->start_ts_epoch); - output_fields["falco.duration_sec"] = std::to_string((now - agent_info->start_ts_epoch) / ONE_SECOND_IN_NS); + output_fields["falco.start_ts"] = agent_info->start_ts_epoch; + output_fields["falco.duration_sec"] = (uint64_t)((now - agent_info->start_ts_epoch) / ONE_SECOND_IN_NS); output_fields["falco.kernel_release"] = agent_info->uname_r; - output_fields["falco.host_boot_ts"] = std::to_string(machine_info->boot_ts_epoch); + output_fields["falco.host_boot_ts"] = machine_info->boot_ts_epoch; output_fields["falco.hostname"] = machine_info->hostname; /* Explicitly add hostname to log msg in case hostname rule output field is disabled. */ - output_fields["falco.host_num_cpus"] = std::to_string(machine_info->num_cpus); + output_fields["falco.host_num_cpus"] = machine_info->num_cpus; output_fields["evt.source"] = src; for (size_t i = 0; i < sizeof(all_driver_engines) / sizeof(const char*); i++) @@ -222,15 +221,15 @@ void stats_writer::collector::get_metrics_output_fields_wrapper( if (m_last_num_evts != 0 && stats_snapshot_time_delta_sec > 0) { /* Successfully processed userspace event rate. */ - output_fields["falco.evts_rate_sec"] = std::to_string((num_evts - m_last_num_evts) / (double)stats_snapshot_time_delta_sec); + output_fields["falco.evts_rate_sec"] = (double)((num_evts - m_last_num_evts) / (double)stats_snapshot_time_delta_sec); } - output_fields["falco.num_evts"] = std::to_string(num_evts); - output_fields["falco.num_evts_prev"] = std::to_string(m_last_num_evts); + output_fields["falco.num_evts"] = num_evts; + output_fields["falco.num_evts_prev"] = m_last_num_evts; m_last_num_evts = num_evts; } void stats_writer::collector::get_metrics_output_fields_additional( - std::unordered_map& output_fields, + nlohmann::json& output_fields, const std::shared_ptr& inspector, double stats_snapshot_time_delta_sec, const std::string& src) { @@ -258,25 +257,25 @@ void stats_writer::collector::get_metrics_output_fields_additional( if (m_writer->m_config->m_metrics_convert_memory_to_mb && strncmp(utilization[stat].name, "container_memory_used", 21) == 0) { - output_fields[metric_name] = std::to_string(utilization[stat].value.u64 / (double)1024 / (double)1024); + output_fields[metric_name] = (uint64_t)(utilization[stat].value.u64 / (double)1024 / (double)1024); } else { - output_fields[metric_name] = std::to_string(utilization[stat].value.u64); + output_fields[metric_name] = utilization[stat].value.u64; } break; case STATS_VALUE_TYPE_U32: if (m_writer->m_config->m_metrics_convert_memory_to_mb && strncmp(utilization[stat].name, "memory_", 7) == 0) { - output_fields[metric_name] = std::to_string(utilization[stat].value.u32 / (double)1024); + output_fields[metric_name] = (uint32_t)(utilization[stat].value.u32 / (double)1024); } else { - output_fields[metric_name] = std::to_string(utilization[stat].value.u32); + output_fields[metric_name] = utilization[stat].value.u32; } break; case STATS_VALUE_TYPE_D: - output_fields[metric_name] = std::to_string(utilization[stat].value.d); + output_fields[metric_name] = utilization[stat].value.d; break; default: break; @@ -324,13 +323,13 @@ void stats_writer::collector::get_metrics_output_fields_additional( if (m_last_n_evts != 0 && stats_snapshot_time_delta_sec > 0) { /* n_evts is total number of kernel side events. */ - output_fields["scap.evts_rate_sec"] = std::to_string((n_evts - m_last_n_evts) / stats_snapshot_time_delta_sec); + output_fields["scap.evts_rate_sec"] = (double)((n_evts - m_last_n_evts) / stats_snapshot_time_delta_sec); } else { - output_fields["scap.evts_rate_sec"] = std::to_string(0); + output_fields["scap.evts_rate_sec"] = (double)(0); } - output_fields["scap.n_evts_prev"] = std::to_string(m_last_n_evts); + output_fields["scap.n_evts_prev"] = m_last_n_evts; } else if (strncmp(stats_v2[stat].name, "n_drops", 7) == 0) { @@ -338,15 +337,15 @@ void stats_writer::collector::get_metrics_output_fields_additional( if (m_last_n_drops != 0 && stats_snapshot_time_delta_sec > 0) { /* n_drops is total number of kernel side event drops. */ - output_fields["scap.evts_drop_rate_sec"] = std::to_string((n_drops - m_last_n_drops) / stats_snapshot_time_delta_sec); + output_fields["scap.evts_drop_rate_sec"] = (double)((n_drops - m_last_n_drops) / stats_snapshot_time_delta_sec); } else { - output_fields["scap.evts_drop_rate_sec"] = std::to_string(0); + output_fields["scap.evts_drop_rate_sec"] = (double)(0); } - output_fields["scap.n_drops_prev"] = std::to_string(m_last_n_drops); + output_fields["scap.n_drops_prev"] = m_last_n_drops; } - output_fields[metric_name] = std::to_string(stats_v2[stat].value.u64); + output_fields[metric_name] = stats_v2[stat].value.u64; break; default: break; @@ -354,11 +353,11 @@ void stats_writer::collector::get_metrics_output_fields_additional( } if((n_evts - m_last_n_evts) > 0) { - output_fields["scap.n_drops_perc"] = std::to_string((100.0 * (n_drops - m_last_n_drops)) / (n_evts - m_last_n_evts)); + output_fields["scap.n_drops_perc"] = (double)((100.0 * (n_drops - m_last_n_drops)) / (n_evts - m_last_n_evts)); } else { - output_fields["scap.n_drops_perc"] = std::to_string(0); + output_fields["scap.n_drops_perc"] = (double)(0); } m_last_n_evts = n_evts; m_last_n_drops = n_drops; @@ -386,7 +385,7 @@ void stats_writer::collector::collect(const std::shared_ptr& inspector, c double stats_snapshot_time_delta_sec = (stats_snapshot_time_delta / (double)ONE_SECOND_IN_NS); /* Get respective metrics output_fields. */ - std::unordered_map output_fields; + nlohmann::json output_fields; get_metrics_output_fields_wrapper(output_fields, inspector, now, src, num_evts, stats_snapshot_time_delta_sec); get_metrics_output_fields_additional(output_fields, inspector, stats_snapshot_time_delta_sec, src); diff --git a/userspace/falco/stats_writer.h b/userspace/falco/stats_writer.h index 6d502447..548554a7 100644 --- a/userspace/falco/stats_writer.h +++ b/userspace/falco/stats_writer.h @@ -64,12 +64,12 @@ public: /*! \brief Collect snapshot metrics wrapper fields as internal rule formatted output fields. */ - void get_metrics_output_fields_wrapper(std::unordered_map& output_fields, const std::shared_ptr& inspector, uint64_t now, const std::string& src, uint64_t num_evts, double stats_snapshot_time_delta_sec); + void get_metrics_output_fields_wrapper(nlohmann::json& output_fields, const std::shared_ptr& inspector, uint64_t now, const std::string& src, uint64_t num_evts, double stats_snapshot_time_delta_sec); /*! \brief Collect snapshot metrics syscalls related metrics as internal rule formatted output fields. */ - void get_metrics_output_fields_additional(std::unordered_map& output_fields, const std::shared_ptr& inspector, double stats_snapshot_time_delta_sec, const std::string& src); + void get_metrics_output_fields_additional(nlohmann::json& output_fields, const std::shared_ptr& inspector, double stats_snapshot_time_delta_sec, const std::string& src); std::shared_ptr m_writer; @@ -132,7 +132,7 @@ private: bool stop; uint64_t ts; std::string source; - std::unordered_map output_fields; + nlohmann::json output_fields; }; void worker() noexcept;