mirror of
https://github.com/falcosecurity/falco.git
synced 2025-08-31 22:28:22 +00:00
Add ability to write capture stats to a file.
With -s, periodically fetch capture stats from the inspector and write them to the provided file. Separate class StatsFileWriter handles the details. It does rely on a timer + SIGALRM handler so you can only practically create a single object, but it does keep the code/state separate. The output format has a sample number, the set of current stats, a delta with the difference from the prior sample, and the percentage of events dropped during that sample.
This commit is contained in:
@@ -9,7 +9,7 @@ include_directories("${CURL_INCLUDE_DIR}")
|
||||
include_directories("${YAMLCPP_INCLUDE_DIR}")
|
||||
include_directories("${DRAIOS_DEPENDENCIES_DIR}/yaml-${DRAIOS_YAML_VERSION}/target/include")
|
||||
|
||||
add_executable(falco configuration.cpp logger.cpp falco_outputs.cpp falco.cpp)
|
||||
add_executable(falco configuration.cpp logger.cpp falco_outputs.cpp statsfilewriter.cpp falco.cpp)
|
||||
|
||||
target_link_libraries(falco falco_engine sinsp)
|
||||
target_link_libraries(falco
|
||||
|
@@ -36,6 +36,7 @@ along with falco. If not, see <http://www.gnu.org/licenses/>.
|
||||
#include "configuration.h"
|
||||
#include "falco_engine.h"
|
||||
#include "config_falco.h"
|
||||
#include "statsfilewriter.h"
|
||||
|
||||
bool g_terminate = false;
|
||||
//
|
||||
@@ -97,6 +98,8 @@ static void usage()
|
||||
" -P, --pidfile <pid_file> When run as a daemon, write pid to specified file\n"
|
||||
" -r <rules_file> Rules file (defaults to value set in configuration file, or /etc/falco_rules.yaml).\n"
|
||||
" Can be specified multiple times to read from multiple files.\n"
|
||||
" -s <stats_file> If specified, write statistics related to falco's reading/processing of events\n"
|
||||
" to this file. (Only useful in live mode).\n"
|
||||
" -v Verbose output.\n"
|
||||
"\n"
|
||||
);
|
||||
@@ -124,11 +127,23 @@ std::list<string> cmdline_options;
|
||||
//
|
||||
uint64_t do_inspect(falco_engine *engine,
|
||||
falco_outputs *outputs,
|
||||
sinsp* inspector)
|
||||
sinsp* inspector,
|
||||
string &stats_filename)
|
||||
{
|
||||
uint64_t num_evts = 0;
|
||||
int32_t res;
|
||||
sinsp_evt* ev;
|
||||
StatsFileWriter writer;
|
||||
|
||||
if (stats_filename != "")
|
||||
{
|
||||
string errstr;
|
||||
|
||||
if (!writer.init(inspector, stats_filename, 5, errstr))
|
||||
{
|
||||
throw falco_exception(errstr);
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Loop through the events
|
||||
@@ -138,6 +153,8 @@ uint64_t do_inspect(falco_engine *engine,
|
||||
|
||||
res = inspector->next(&ev);
|
||||
|
||||
writer.handle();
|
||||
|
||||
if (g_terminate)
|
||||
{
|
||||
break;
|
||||
@@ -202,6 +219,7 @@ int falco_init(int argc, char **argv)
|
||||
string pidfilename = "/var/run/falco.pid";
|
||||
bool describe_all_rules = false;
|
||||
string describe_rule = "";
|
||||
string stats_filename = "";
|
||||
bool verbose = false;
|
||||
bool all_events = false;
|
||||
string* k8s_api = 0;
|
||||
@@ -246,7 +264,7 @@ int falco_init(int argc, char **argv)
|
||||
// Parse the args
|
||||
//
|
||||
while((op = getopt_long(argc, argv,
|
||||
"hc:AdD:e:k:K:Ll:m:o:P:p:r:vw:",
|
||||
"hc:AdD:e:k:K:Ll:m:o:P:p:r:s:vw:",
|
||||
long_options, &long_index)) != -1)
|
||||
{
|
||||
switch(op)
|
||||
@@ -318,6 +336,9 @@ int falco_init(int argc, char **argv)
|
||||
case 'r':
|
||||
rules_filenames.push_back(optarg);
|
||||
break;
|
||||
case 's':
|
||||
stats_filename = optarg;
|
||||
break;
|
||||
case 'v':
|
||||
verbose = true;
|
||||
break;
|
||||
@@ -588,7 +609,8 @@ int falco_init(int argc, char **argv)
|
||||
|
||||
num_evts = do_inspect(engine,
|
||||
outputs,
|
||||
inspector);
|
||||
inspector,
|
||||
stats_filename);
|
||||
|
||||
duration = ((double)clock()) / CLOCKS_PER_SEC - duration;
|
||||
|
||||
|
90
userspace/falco/statsfilewriter.cpp
Normal file
90
userspace/falco/statsfilewriter.cpp
Normal file
@@ -0,0 +1,90 @@
|
||||
#include <sys/time.h>
|
||||
#include <signal.h>
|
||||
|
||||
#include "statsfilewriter.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
static bool g_save_stats = false;
|
||||
static void timer_handler (int signum)
|
||||
{
|
||||
g_save_stats = true;
|
||||
}
|
||||
|
||||
StatsFileWriter::StatsFileWriter()
|
||||
: m_num_stats(0), m_inspector(NULL)
|
||||
{
|
||||
}
|
||||
|
||||
StatsFileWriter::~StatsFileWriter()
|
||||
{
|
||||
m_output.close();
|
||||
}
|
||||
|
||||
bool StatsFileWriter::init(sinsp *inspector, string &filename, uint32_t interval_sec, string &errstr)
|
||||
{
|
||||
struct itimerval timer;
|
||||
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));
|
||||
handler.sa_handler = &timer_handler;
|
||||
if (sigaction(SIGALRM, &handler, NULL) == -1)
|
||||
{
|
||||
errstr = string("Could not set up signal handler for periodic timer: ") + strerror(errno);
|
||||
return false;
|
||||
}
|
||||
|
||||
timer.it_value.tv_sec = interval_sec;
|
||||
timer.it_value.tv_usec = 0;
|
||||
timer.it_interval = timer.it_value;
|
||||
if (setitimer(ITIMER_REAL, &timer, NULL) == -1)
|
||||
{
|
||||
errstr = string("Could not set up periodic timer: ") + strerror(errno);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void StatsFileWriter::handle()
|
||||
{
|
||||
if (g_save_stats)
|
||||
{
|
||||
scap_stats cstats;
|
||||
scap_stats delta;
|
||||
|
||||
g_save_stats = false;
|
||||
m_num_stats++;
|
||||
m_inspector->get_capture_stats(&cstats);
|
||||
|
||||
if(m_num_stats == 1)
|
||||
{
|
||||
delta = cstats;
|
||||
}
|
||||
else
|
||||
{
|
||||
delta.n_evts = cstats.n_evts - m_last_stats.n_evts;
|
||||
delta.n_drops = cstats.n_drops - m_last_stats.n_drops;
|
||||
delta.n_preemptions = cstats.n_preemptions - m_last_stats.n_preemptions;
|
||||
}
|
||||
|
||||
m_output << "{\"sample\": " << m_num_stats <<
|
||||
", \"cur\": {" <<
|
||||
"\"events\": " << cstats.n_evts <<
|
||||
", \"drops\": " << cstats.n_drops <<
|
||||
", \"preemptions\": " << cstats.n_preemptions <<
|
||||
"}, \"delta\": {" <<
|
||||
"\"events\": " << delta.n_evts <<
|
||||
", \"drops\": " << delta.n_drops <<
|
||||
", \"preemptions\": " << delta.n_preemptions <<
|
||||
"}, \"drop_pct\": " << (delta.n_evts == 0 ? 0 : (100.0*delta.n_drops/delta.n_evts)) <<
|
||||
"}," << endl;
|
||||
|
||||
m_last_stats = cstats;
|
||||
}
|
||||
}
|
30
userspace/falco/statsfilewriter.h
Normal file
30
userspace/falco/statsfilewriter.h
Normal file
@@ -0,0 +1,30 @@
|
||||
#pragma once
|
||||
|
||||
#include <fstream>
|
||||
|
||||
#include <sinsp.h>
|
||||
|
||||
// Periodically collects scap stats files and writes them to a file as
|
||||
// json.
|
||||
|
||||
class StatsFileWriter {
|
||||
public:
|
||||
StatsFileWriter();
|
||||
virtual ~StatsFileWriter();
|
||||
|
||||
// Returns success as bool. On false fills in errstr.
|
||||
bool init(sinsp *inspector, std::string &filename,
|
||||
uint32_t interval_sec,
|
||||
string &errstr);
|
||||
|
||||
// Should be called often (like for each event in a sinsp
|
||||
// loop).
|
||||
void handle();
|
||||
|
||||
protected:
|
||||
uint32_t m_num_stats;
|
||||
sinsp *m_inspector;
|
||||
std::ofstream m_output;
|
||||
|
||||
scap_stats m_last_stats;
|
||||
};
|
Reference in New Issue
Block a user