diff --git a/userspace/engine/falco_engine.cpp b/userspace/engine/falco_engine.cpp index af77b938..35f99d97 100644 --- a/userspace/engine/falco_engine.cpp +++ b/userspace/engine/falco_engine.cpp @@ -194,6 +194,15 @@ std::unique_ptr falco_engine::load_rules(const std::string &rules_c m_rule_loader.compile(cfg, m_rules); } + if (cfg.res->successful()) + { + m_rule_stats_manager.clear(); + for (const auto &r : m_rules) + { + m_rule_stats_manager.on_rule_loaded(r); + } + } + return std::move(cfg.res); } diff --git a/userspace/engine/stats_manager.cpp b/userspace/engine/stats_manager.cpp index 47a37fc5..6da73ee9 100644 --- a/userspace/engine/stats_manager.cpp +++ b/userspace/engine/stats_manager.cpp @@ -45,37 +45,48 @@ void stats_manager::format( out += "Rule counts by severity:\n"; for (size_t i = 0; i < m_by_priority.size(); i++) { - if (m_by_priority[i] > 0) + auto val = m_by_priority[i].get()->load(); + if (val > 0) { falco_common::format_priority( (falco_common::priority_type) i, fmt, true); transform(fmt.begin(), fmt.end(), fmt.begin(), ::toupper); - out += " " + fmt; - out += ": " + to_string(m_by_priority[i]) + "\n"; + out += " " + fmt + ": " + to_string(val) + "\n"; } } out += "Triggered rules by rule name:\n"; for (size_t i = 0; i < m_by_rule_id.size(); i++) { - if (m_by_rule_id[i] > 0) + auto val = m_by_rule_id[i].get()->load(); + if (val > 0) { - out += " " + rules.at(i)->name; - out += ": " + to_string(m_by_rule_id[i]) + "\n"; + out += " " + rules.at(i)->name + ": " + to_string(val) + "\n"; } } } +void stats_manager::on_rule_loaded(const falco_rule& rule) +{ + while (m_by_rule_id.size() <= rule.id) + { + m_by_rule_id.emplace_back(); + m_by_rule_id[m_by_rule_id.size() - 1].reset(new atomic(0)); + } + while (m_by_priority.size() <= (size_t) rule.priority) + { + m_by_priority.emplace_back(); + m_by_priority[m_by_priority.size() - 1].reset(new atomic(0)); + } +} + void stats_manager::on_event(const falco_rule& rule) { - if (m_by_rule_id.size() <= rule.id) + if (m_by_rule_id.size() <= rule.id + || m_by_priority.size() <= (size_t) rule.priority) { - m_by_rule_id.resize(rule.id + 1, (uint64_t) 0); + throw falco_exception("rule id or priority is out of boubnds"); } - if (m_by_priority.size() <= (size_t) rule.priority) - { - m_by_priority.resize((size_t) rule.priority + 1, (uint64_t) 0); - } - m_total++; - m_by_rule_id[rule.id]++; - m_by_priority[(size_t) rule.priority]++; + m_total.fetch_add(1, std::memory_order_relaxed); + m_by_rule_id[rule.id]->fetch_add(1, std::memory_order_relaxed); + m_by_priority[(size_t) rule.priority]->fetch_add(1, std::memory_order_relaxed); } diff --git a/userspace/engine/stats_manager.h b/userspace/engine/stats_manager.h index 23f9bcca..df0e6c43 100644 --- a/userspace/engine/stats_manager.h +++ b/userspace/engine/stats_manager.h @@ -18,11 +18,16 @@ limitations under the License. #include #include +#include +#include #include "falco_rule.h" #include "indexed_vector.h" /*! - \brief Manager for the internal statistics of the rule engine + \brief Manager for the internal statistics of the rule engine. + The on_event() is thread-safe and non-blocking, and it can be used + concurrently across many callers in parallel. + All the other methods are not thread safe. */ class stats_manager { @@ -36,19 +41,29 @@ public: virtual void clear(); /*! - \brief Callback for when a given rule matches an event + \brief Callback for when a new rule is loaded in the engine. + Rules must be passed through this method before submitting them as + an argument of on_event(). + */ + virtual void on_rule_loaded(const falco_rule& rule); + + /*! + \brief Callback for when a given rule matches an event. + This method is thread-safe. + \throws falco_exception if rule has not been passed to + on_rule_loaded() first */ virtual void on_event(const falco_rule& rule); /*! - \brief Formats the internal statistics into the out string + \brief Formats the internal statistics into the out string. */ virtual void format( const indexed_vector& rules, std::string& out) const; private: - uint64_t m_total; - std::vector m_by_priority; - std::vector m_by_rule_id; + atomic m_total; + std::vector>> m_by_priority; + std::vector>> m_by_rule_id; }; \ No newline at end of file