mirror of
https://github.com/falcosecurity/falco.git
synced 2025-09-01 14:47:00 +00:00
refactor(userspace/falco): re-implement stats writer
Signed-off-by: Jason Dellaluce <jasondellaluce@gmail.com>
This commit is contained in:
@@ -17,44 +17,33 @@ limitations under the License.
|
|||||||
#include <sys/time.h>
|
#include <sys/time.h>
|
||||||
#include <signal.h>
|
#include <signal.h>
|
||||||
#include <nlohmann/json.hpp>
|
#include <nlohmann/json.hpp>
|
||||||
|
#include <atomic>
|
||||||
|
|
||||||
#include "statsfilewriter.h"
|
#include "statsfilewriter.h"
|
||||||
|
#include "logger.h"
|
||||||
#include "banned.h" // This raises a compilation error when certain functions are used
|
#include "banned.h" // This raises a compilation error when certain functions are used
|
||||||
#include "logger.h"
|
#include "logger.h"
|
||||||
|
|
||||||
using namespace std;
|
// note: uint16_t is enough because we don't care about
|
||||||
|
// overflows here. Threads calling stats_writer::handle() will just
|
||||||
|
// check that this value changed since their last observation.
|
||||||
|
static std::atomic<uint16_t> s_last_tick((uint16_t) 0);
|
||||||
|
|
||||||
static bool g_save_stats = false;
|
static void timer_handler(int signum)
|
||||||
static void timer_handler (int signum)
|
|
||||||
{
|
{
|
||||||
g_save_stats = true;
|
s_last_tick.fetch_add(1, std::memory_order_relaxed);
|
||||||
}
|
}
|
||||||
|
|
||||||
StatsFileWriter::StatsFileWriter()
|
bool stats_writer::set_timer(uint32_t interval_msec, string &err)
|
||||||
: m_num_stats(0)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
StatsFileWriter::~StatsFileWriter()
|
|
||||||
{
|
|
||||||
m_output.close();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool StatsFileWriter::init(std::shared_ptr<sinsp> inspector, string &filename, uint32_t interval_msec, string &errstr)
|
|
||||||
{
|
{
|
||||||
struct itimerval timer;
|
struct itimerval timer;
|
||||||
struct sigaction handler;
|
struct sigaction handler;
|
||||||
|
|
||||||
m_inspector = inspector;
|
|
||||||
|
|
||||||
m_output.exceptions ( ofstream::failbit | ofstream::badbit );
|
|
||||||
m_output.open(filename, ios_base::app);
|
|
||||||
|
|
||||||
memset (&handler, 0, sizeof (handler));
|
memset (&handler, 0, sizeof (handler));
|
||||||
handler.sa_handler = &timer_handler;
|
handler.sa_handler = &timer_handler;
|
||||||
if (sigaction(SIGALRM, &handler, NULL) == -1)
|
if (sigaction(SIGALRM, &handler, NULL) == -1)
|
||||||
{
|
{
|
||||||
errstr = string("Could not set up signal handler for periodic timer: ") + strerror(errno);
|
err = string("Could not set up signal handler for periodic timer: ") + strerror(errno);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -63,34 +52,99 @@ bool StatsFileWriter::init(std::shared_ptr<sinsp> inspector, string &filename, u
|
|||||||
timer.it_interval = timer.it_value;
|
timer.it_interval = timer.it_value;
|
||||||
if (setitimer(ITIMER_REAL, &timer, NULL) == -1)
|
if (setitimer(ITIMER_REAL, &timer, NULL) == -1)
|
||||||
{
|
{
|
||||||
errstr = string("Could not set up periodic timer: ") + strerror(errno);
|
err = string("Could not set up periodic timer: ") + strerror(errno);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void StatsFileWriter::handle()
|
stats_writer::stats_writer()
|
||||||
|
: m_initialized(false), m_total_samples(0)
|
||||||
{
|
{
|
||||||
if (g_save_stats)
|
// the stats writter do nothing
|
||||||
|
}
|
||||||
|
|
||||||
|
stats_writer::stats_writer(const std::string &filename)
|
||||||
|
: m_initialized(true), m_total_samples(0)
|
||||||
|
{
|
||||||
|
m_output.exceptions(ofstream::failbit | ofstream::badbit);
|
||||||
|
m_output.open(filename, ios_base::app);
|
||||||
|
m_worker = std::thread(&stats_writer::worker, this);
|
||||||
|
}
|
||||||
|
|
||||||
|
stats_writer::~stats_writer()
|
||||||
|
{
|
||||||
|
if (m_initialized)
|
||||||
{
|
{
|
||||||
scap_stats cstats;
|
stop_worker();
|
||||||
scap_stats delta;
|
m_output.close();
|
||||||
nlohmann::json jmsg;
|
}
|
||||||
|
}
|
||||||
|
|
||||||
g_save_stats = false;
|
void stats_writer::handle(const std::shared_ptr<sinsp>& inspector, stats_writer::state& s)
|
||||||
m_num_stats++;
|
{
|
||||||
m_inspector->get_capture_stats(&cstats);
|
if (m_initialized)
|
||||||
|
{
|
||||||
if(m_num_stats == 1)
|
auto tick = s_last_tick.load(std::memory_order_relaxed);
|
||||||
|
if (tick != s.last_tick)
|
||||||
{
|
{
|
||||||
delta = cstats;
|
// gather stats sample and fill-up message
|
||||||
|
stats_writer::msg msg;
|
||||||
|
msg.stop = false;
|
||||||
|
inspector->get_capture_stats(&msg.stats);
|
||||||
|
if(s.samples == 1)
|
||||||
|
{
|
||||||
|
msg.delta = msg.stats;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
msg.delta.n_evts = msg.stats.n_evts - s.last_stats.n_evts;
|
||||||
|
msg.delta.n_drops = msg.stats.n_drops - s.last_stats.n_drops;
|
||||||
|
msg.delta.n_preemptions = msg.stats.n_preemptions - s.last_stats.n_preemptions;
|
||||||
|
}
|
||||||
|
|
||||||
|
// update state
|
||||||
|
s.samples++;
|
||||||
|
s.last_tick = tick;
|
||||||
|
s.last_stats = msg.stats;
|
||||||
|
|
||||||
|
// push message into the queue
|
||||||
|
push(msg);
|
||||||
}
|
}
|
||||||
else
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void stats_writer::stop_worker()
|
||||||
|
{
|
||||||
|
stats_writer::msg msg;
|
||||||
|
msg.stop = true;
|
||||||
|
push(msg);
|
||||||
|
if(m_worker.joinable())
|
||||||
|
{
|
||||||
|
m_worker.join();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void stats_writer::push(const stats_writer::msg& m)
|
||||||
|
{
|
||||||
|
if (!m_queue.try_push(m))
|
||||||
|
{
|
||||||
|
fprintf(stderr, "Fatal error: Stats queue reached maximum capacity. Exiting.\n");
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void stats_writer::worker() noexcept
|
||||||
|
{
|
||||||
|
stats_writer::msg m;
|
||||||
|
while(true)
|
||||||
|
{
|
||||||
|
// Block until a message becomes available.
|
||||||
|
m_queue.pop(m);
|
||||||
|
if (m.stop)
|
||||||
{
|
{
|
||||||
delta.n_evts = cstats.n_evts - m_last_stats.n_evts;
|
return;
|
||||||
delta.n_drops = cstats.n_drops - m_last_stats.n_drops;
|
|
||||||
delta.n_preemptions = cstats.n_preemptions - m_last_stats.n_preemptions;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
try
|
try
|
||||||
@@ -108,9 +162,7 @@ void StatsFileWriter::handle()
|
|||||||
}
|
}
|
||||||
catch(const exception &e)
|
catch(const exception &e)
|
||||||
{
|
{
|
||||||
falco_logger::log(LOG_ERR, "StatsFileWriter (handle): " + string(e.what()) + "\n");
|
falco_logger::log(LOG_ERR, "stats_writer (worker): " + string(e.what()) + "\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
m_last_stats = cstats;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -27,27 +27,6 @@ limitations under the License.
|
|||||||
// Periodically collects scap stats files and writes them to a file as
|
// Periodically collects scap stats files and writes them to a file as
|
||||||
// json.
|
// json.
|
||||||
|
|
||||||
class StatsFileWriter {
|
|
||||||
public:
|
|
||||||
StatsFileWriter();
|
|
||||||
virtual ~StatsFileWriter();
|
|
||||||
|
|
||||||
// Returns success as bool. On false fills in errstr.
|
|
||||||
bool init(std::shared_ptr<sinsp> inspector, std::string &filename,
|
|
||||||
uint32_t interval_msec,
|
|
||||||
string &errstr);
|
|
||||||
|
|
||||||
// Should be called often (like for each event in a sinsp
|
|
||||||
// loop).
|
|
||||||
void handle();
|
|
||||||
|
|
||||||
protected:
|
|
||||||
uint32_t m_num_stats;
|
|
||||||
std::shared_ptr<sinsp> m_inspector;
|
|
||||||
std::ofstream m_output;
|
|
||||||
scap_stats m_last_stats;
|
|
||||||
};
|
|
||||||
|
|
||||||
class stats_writer
|
class stats_writer
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
@@ -64,12 +43,12 @@ public:
|
|||||||
explicit stats_writer(const std::string &filename);
|
explicit stats_writer(const std::string &filename);
|
||||||
~stats_writer();
|
~stats_writer();
|
||||||
|
|
||||||
|
void handle(const std::shared_ptr<sinsp>& inspector, stats_writer::state& s);
|
||||||
|
|
||||||
static bool set_timer(uint32_t interval_msec, std::string &err);
|
static bool set_timer(uint32_t interval_msec, std::string &err);
|
||||||
|
|
||||||
void handle(const std::shared_ptr<sinsp>& inspector, state& s);
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
struct worker_msg
|
struct msg
|
||||||
{
|
{
|
||||||
bool stop;
|
bool stop;
|
||||||
scap_stats delta;
|
scap_stats delta;
|
||||||
@@ -78,11 +57,11 @@ private:
|
|||||||
|
|
||||||
void worker() noexcept;
|
void worker() noexcept;
|
||||||
void stop_worker();
|
void stop_worker();
|
||||||
inline void push(const worker_msg& m);
|
inline void push(const stats_writer::msg& m);
|
||||||
|
|
||||||
bool m_initialized;
|
bool m_initialized;
|
||||||
uint64_t m_total_samples;
|
uint64_t m_total_samples;
|
||||||
std::thread m_worker;
|
std::thread m_worker;
|
||||||
std::ofstream m_output;
|
std::ofstream m_output;
|
||||||
tbb::concurrent_bounded_queue<worker_msg> m_queue;
|
tbb::concurrent_bounded_queue<stats_writer::msg> m_queue;
|
||||||
};
|
};
|
Reference in New Issue
Block a user