Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add ability to write capture stats to a file. #155

Merged
merged 2 commits into from
Dec 6, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 11 additions & 3 deletions test/run_performance_tests.sh
Original file line number Diff line number Diff line change
Expand Up @@ -143,13 +143,13 @@ function start_subject_prog() {
if [ -z $RULES_FILE ]; then
RULES_FILE=$SOURCE/../output/rules.yaml
fi
sudo $ROOT/test_mm -s $SOURCE/search_order.yaml -r $RULES_FILE > ./prog-output.txt 2>&1 &
sudo FALCO_STATS_EXTRA_variant=$VARIANT FALCO_STATS_EXTRA_benchmark=$live_test $ROOT/test_mm -S $SOURCE/search_order.yaml -s $STATS_FILE -r $RULES_FILE > ./prog-output.txt 2>&1 &
elif [[ $ROOT == *"falco"* ]]; then
echo " starting falco..."
if [ -z $RULES_FILE ]; then
RULES_FILE=$SOURCE/rules/falco_rules.yaml
fi
sudo $ROOT/userspace/falco/falco -c $SOURCE/falco.yaml -r $RULES_FILE --option=stdout_output.enabled=false > ./prog-output.txt -A 2>&1 &
sudo FALCO_STATS_EXTRA_variant=$VARIANT FALCO_STATS_EXTRA_benchmark=$live_test $ROOT/userspace/falco/falco -c $SOURCE/falco.yaml -s $STATS_FILE -r $RULES_FILE --option=stdout_output.enabled=false > ./prog-output.txt -A 2>&1 &
elif [[ $ROOT == *"sysdig"* ]]; then
echo " starting sysdig..."
sudo $ROOT/userspace/sysdig/sysdig -N -z evt.type=none &
Expand Down Expand Up @@ -323,6 +323,7 @@ usage() {
echo " -r/--root: root directory containing falco/sysdig binaries (i.e. where you ran 'cmake')"
echo " -s/--source: root directory containing falco/sysdig source code"
echo " -R/--results: append test results to this file"
echo " -S/--stats: append capture statistics to this file (only works for falco/test_mm)"
echo " -o/--output: append program output to this file"
echo " -U/--rules: path to rules file (only applicable for falco/test_mm)"
echo " -t/--test: test to run. Argument has the following format:"
Expand All @@ -342,7 +343,7 @@ usage() {
echo " -F/--falco-agent: When running an agent, whether or not to enable falco"
}

OPTS=`getopt -o hv:r:s:R:o:U:t:T: --long help,variant:,root:,source:,results:,output:,rules:,test:,tracedir:,agent-autodrop:,falco-agent: -n $0 -- "$@"`
OPTS=`getopt -o hv:r:s:R:S:o:U:t:T: --long help,variant:,root:,source:,results:,stats:,output:,rules:,test:,tracedir:,agent-autodrop:,falco-agent: -n $0 -- "$@"`

if [ $? != 0 ]; then
echo "Exiting" >&2
Expand All @@ -356,6 +357,7 @@ ROOT=`dirname $0`/../build
SOURCE=$ROOT
SCRIPTDIR=`dirname $0`
RESULTS_FILE=`dirname $0`/results.json
STATS_FILE=`dirname $0`/capture_stats.json
OUTPUT_FILE=`dirname $0`/program-output.txt
RULES_FILE=
TEST=trace:all
Expand All @@ -371,6 +373,7 @@ while true; do
-r | --root ) ROOT="$2"; shift 2;;
-s | --source ) SOURCE="$2"; shift 2;;
-R | --results ) RESULTS_FILE="$2"; shift 2;;
-S | --stats ) STATS_FILE="$2"; shift 2;;
-o | --output ) OUTPUT_FILE="$2"; shift 2;;
-U | --rules ) RULES_FILE="$2"; shift 2;;
-t | --test ) TEST="$2"; shift 2;;
Expand Down Expand Up @@ -405,6 +408,11 @@ if [ -z $RESULTS_FILE ]; then
exit 1
fi

if [ -z $STATS_FILE ]; then
echo "An output file for capture statistics must be provided. Not continuing."
exit 1
fi

if [ -z $OUTPUT_FILE ]; then
echo "An file for program output must be provided. Not continuing."
exit 1
Expand Down
2 changes: 1 addition & 1 deletion userspace/falco/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
28 changes: 25 additions & 3 deletions userspace/falco/falco.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
//
Expand Down Expand Up @@ -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"
);
Expand Down Expand Up @@ -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
Expand All @@ -138,6 +153,8 @@ uint64_t do_inspect(falco_engine *engine,

res = inspector->next(&ev);

writer.handle();

if (g_terminate)
{
break;
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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;

Expand Down
120 changes: 120 additions & 0 deletions userspace/falco/statsfilewriter.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
#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;
}

extern char **environ;

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;
}

// (Undocumented) feature. Take any environment keys prefixed
// with FALCO_STATS_EXTRA_XXX and add them to the output. Used by
// run_performance_tests.sh.
for(uint32_t i=0; environ[i]; i++)
{
char *p = strstr(environ[i], "=");
if(!p)
{
errstr = string("Could not find environment separator in ") + string(environ[i]);
return false;
}
string key(environ[i], p-environ[i]);
string val(p+1, strlen(environ[i])-(p-environ[i])-1);
if(key.compare(0, 18, "FALCO_STATS_EXTRA_") == 0)
{
string sub = key.substr(18);
if (m_extra != "")
{
m_extra += ", ";
}
m_extra += "\"" + sub + "\": " + "\"" + val + "\"";
}
}

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;
if(m_extra != "")
{
m_output << ", " << m_extra;
}
m_output << ", \"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;
}
}
32 changes: 32 additions & 0 deletions userspace/falco/statsfilewriter.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
#pragma once

#include <fstream>
#include <string>
#include <map>

#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;
std::string m_extra;
scap_stats m_last_stats;
};