refactor(userspace/engine): make stats manager thread-safe for on_event method

Signed-off-by: Jason Dellaluce <jasondellaluce@gmail.com>
This commit is contained in:
Jason Dellaluce 2022-06-21 16:50:04 +00:00 committed by poiana
parent 3839fdca1e
commit 1b8847c06b
3 changed files with 56 additions and 21 deletions

View File

@ -194,6 +194,15 @@ std::unique_ptr<load_result> 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);
}

View File

@ -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<uint64_t>(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<uint64_t>(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);
}

View File

@ -18,11 +18,16 @@ limitations under the License.
#include <vector>
#include <string>
#include <atomic>
#include <memory>
#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<falco_rule>& rules,
std::string& out) const;
private:
uint64_t m_total;
std::vector<uint64_t> m_by_priority;
std::vector<uint64_t> m_by_rule_id;
atomic<uint64_t> m_total;
std::vector<std::unique_ptr<atomic<uint64_t>>> m_by_priority;
std::vector<std::unique_ptr<atomic<uint64_t>>> m_by_rule_id;
};