rule profiling: json output

pull/1752/head
Victor Julien 9 years ago
parent b03c288d9a
commit c1bf0e1b07

@ -309,6 +309,7 @@ const char * SCErrorToString(SCError err)
CASE_CODE (SC_ERR_IPPAIR_INIT);
CASE_CODE (SC_ERR_MT_NO_SELECTOR);
CASE_CODE (SC_ERR_MT_DUPLICATE_TENANT);
CASE_CODE (SC_ERR_NO_JSON_SUPPORT);
}
return "UNKNOWN_ERROR";

@ -298,6 +298,7 @@ typedef enum {
SC_ERR_IPPAIR_INIT,
SC_ERR_MT_NO_SELECTOR,
SC_ERR_MT_DUPLICATE_TENANT,
SC_ERR_NO_JSON_SUPPORT,
} SCError;
const char *SCErrorToString(SCError);

@ -81,6 +81,7 @@ extern int profiling_output_to_file;
int profiling_rules_enabled = 0;
static char *profiling_file_name = "";
static const char *profiling_file_mode = "a";
static int profiling_rule_json = 0;
/**
* Sort orders for dumping profiled rules.
@ -178,6 +179,13 @@ void SCProfilingRulesGlobalInit(void)
profiling_output_to_file = 1;
}
if (ConfNodeChildValueIsTrue(conf, "json")) {
#ifdef HAVE_LIBJANSSON
profiling_rule_json = 1;
#else
SCLogWarning(SC_ERR_NO_JSON_SUPPORT, "no json support compiled in, using plain output");
#endif
}
}
}
}
@ -280,6 +288,134 @@ SCProfileSummarySortByMaxTicks(const void *a, const void *b)
return s0->max > s1->max ? -1 : 1;
}
#ifdef HAVE_LIBJANSSON
static void DumpJson(FILE *fp, SCProfileSummary *summary, uint32_t count, uint64_t total_ticks)
{
char timebuf[64];
uint32_t i;
struct timeval tval;
json_t *js = json_object();
if (js == NULL)
return;
json_t *jsa = json_array();
if (jsa == NULL) {
json_decref(js);
return;
}
gettimeofday(&tval, NULL);
CreateIsoTimeString(&tval, timebuf, sizeof(timebuf));
json_object_set_new(js, "timestamp", json_string(timebuf));
for (i = 0; i < count; i++) {
/* Stop dumping when we hit our first rule with 0 checks. Due
* to sorting this will be the beginning of all the rules with
* 0 checks. */
if (summary[i].checks == 0)
break;
json_t *jsm = json_object();
if (jsm) {
json_object_set_new(jsm, "signature_id", json_integer(summary[i].sid));
json_object_set_new(jsm, "gid", json_integer(summary[i].gid));
json_object_set_new(jsm, "rev", json_integer(summary[i].rev));
json_object_set_new(jsm, "checks", json_integer(summary[i].checks));
json_object_set_new(jsm, "matches", json_integer(summary[i].matches));
json_object_set_new(jsm, "ticks_total", json_integer(summary[i].ticks));
json_object_set_new(jsm, "ticks_max", json_integer(summary[i].max));
json_object_set_new(jsm, "ticks_avg", json_integer(summary[i].avgticks));
json_object_set_new(jsm, "ticks_avg_match", json_integer(summary[i].avgticks_match));
json_object_set_new(jsm, "ticks_avg_nomatch", json_integer(summary[i].avgticks_no_match));
double percent = (long double)summary[i].ticks /
(long double)total_ticks * 100;
json_object_set_new(jsm, "percent", json_integer(percent));
json_array_append(jsa, jsm);
}
}
json_object_set_new(js, "rules", jsa);
char *js_s = json_dumps(js,
JSON_PRESERVE_ORDER|JSON_COMPACT|JSON_ENSURE_ASCII|
#ifdef JSON_ESCAPE_SLASH
JSON_ESCAPE_SLASH
#else
0
#endif
);
if (unlikely(js_s == NULL))
return;
fprintf(fp, "%s", js_s);
free(js_s);
json_decref(js);
}
#endif /* HAVE_LIBJANSSON */
static void DumpText(FILE *fp, SCProfileSummary *summary, uint32_t count, uint64_t total_ticks)
{
uint32_t i;
struct timeval tval;
struct tm *tms;
gettimeofday(&tval, NULL);
struct tm local_tm;
tms = SCLocalTime(tval.tv_sec, &local_tm);
fprintf(fp, " ----------------------------------------------"
"----------------------------\n");
fprintf(fp, " Date: %" PRId32 "/%" PRId32 "/%04d -- "
"%02d:%02d:%02d\n", tms->tm_mon + 1, tms->tm_mday, tms->tm_year + 1900,
tms->tm_hour,tms->tm_min, tms->tm_sec);
fprintf(fp, " ----------------------------------------------"
"----------------------------\n");
fprintf(fp, " %-8s %-12s %-8s %-8s %-12s %-6s %-8s %-8s %-11s %-11s %-11s %-11s\n", "Num", "Rule", "Gid", "Rev", "Ticks", "%", "Checks", "Matches", "Max Ticks", "Avg Ticks", "Avg Match", "Avg No Match");
fprintf(fp, " -------- "
"------------ "
"-------- "
"-------- "
"------------ "
"------ "
"-------- "
"-------- "
"----------- "
"----------- "
"----------- "
"-------------- "
"\n");
for (i = 0; i < MIN(count, profiling_rules_limit); i++) {
/* Stop dumping when we hit our first rule with 0 checks. Due
* to sorting this will be the beginning of all the rules with
* 0 checks. */
if (summary[i].checks == 0)
break;
double percent = (long double)summary[i].ticks /
(long double)total_ticks * 100;
fprintf(fp,
" %-8"PRIu32" %-12u %-8"PRIu32" %-8"PRIu32" %-12"PRIu64" %-6.2f %-8"PRIu64" %-8"PRIu64" %-11"PRIu64" %-11.2f %-11.2f %-11.2f\n",
i + 1,
summary[i].sid,
summary[i].gid,
summary[i].rev,
summary[i].ticks,
percent,
summary[i].checks,
summary[i].matches,
summary[i].max,
summary[i].avgticks,
summary[i].avgticks_match,
summary[i].avgticks_no_match);
}
fprintf(fp,"\n");
}
/**
* \brief Dump rule profiling information to file
*
@ -294,8 +430,6 @@ SCProfilingRuleDump(SCProfileDetectCtx *rules_ctx)
if (rules_ctx == NULL)
return;
struct timeval tval;
struct tm *tms;
if (profiling_output_to_file == 1) {
fp = fopen(profiling_file_name, profiling_file_mode);
@ -379,59 +513,15 @@ SCProfilingRuleDump(SCProfileDetectCtx *rules_ctx)
SCProfileSummarySortByAvgTicksNoMatch);
break;
}
gettimeofday(&tval, NULL);
struct tm local_tm;
tms = SCLocalTime(tval.tv_sec, &local_tm);
fprintf(fp, " ----------------------------------------------"
"----------------------------\n");
fprintf(fp, " Date: %" PRId32 "/%" PRId32 "/%04d -- "
"%02d:%02d:%02d\n", tms->tm_mon + 1, tms->tm_mday, tms->tm_year + 1900,
tms->tm_hour,tms->tm_min, tms->tm_sec);
fprintf(fp, " ----------------------------------------------"
"----------------------------\n");
fprintf(fp, " %-8s %-12s %-8s %-8s %-12s %-6s %-8s %-8s %-11s %-11s %-11s %-11s\n", "Num", "Rule", "Gid", "Rev", "Ticks", "%", "Checks", "Matches", "Max Ticks", "Avg Ticks", "Avg Match", "Avg No Match");
fprintf(fp, " -------- "
"------------ "
"-------- "
"-------- "
"------------ "
"------ "
"-------- "
"-------- "
"----------- "
"----------- "
"----------- "
"-------------- "
"\n");
for (i = 0; i < MIN(count, profiling_rules_limit); i++) {
/* Stop dumping when we hit our first rule with 0 checks. Due
* to sorting this will be the beginning of all the rules with
* 0 checks. */
if (summary[i].checks == 0)
break;
double percent = (long double)summary[i].ticks /
(long double)total_ticks * 100;
fprintf(fp,
" %-8"PRIu32" %-12u %-8"PRIu32" %-8"PRIu32" %-12"PRIu64" %-6.2f %-8"PRIu64" %-8"PRIu64" %-11"PRIu64" %-11.2f %-11.2f %-11.2f\n",
i + 1,
summary[i].sid,
summary[i].gid,
summary[i].rev,
summary[i].ticks,
percent,
summary[i].checks,
summary[i].matches,
summary[i].max,
summary[i].avgticks,
summary[i].avgticks_match,
summary[i].avgticks_no_match);
#ifdef HAVE_LIBJANSSON
if (profiling_rule_json) {
DumpJson(fp, summary, count, total_ticks);
} else
#endif
{
DumpText(fp, summary, count, total_ticks);
}
fprintf(fp,"\n");
if (fp != stdout)
fclose(fp);
SCFree(summary);

@ -1511,9 +1511,12 @@ profiling:
# Sort options: ticks, avgticks, checks, matches, maxticks
sort: avgticks
# Limit the number of items printed at exit.
# Limit the number of items printed at exit (ignored for json).
limit: 100
# output to json
json: true
# per keyword profiling
keywords:
enabled: yes

Loading…
Cancel
Save