]> git.ipfire.org Git - thirdparty/suricata.git/commitdiff
rule profiling: json output 1752/head
authorVictor Julien <victor@inliniac.net>
Tue, 3 Nov 2015 09:58:36 +0000 (10:58 +0100)
committerVictor Julien <victor@inliniac.net>
Sun, 22 Nov 2015 10:24:09 +0000 (11:24 +0100)
src/util-error.c
src/util-error.h
src/util-profiling-rules.c
suricata.yaml.in

index 6e783f42e4cf2f170ec53e4887add879c6fbda0e..461e18702e76481d5a28be402b5f427572409996 100644 (file)
@@ -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";
index d1e42a8cdd4eec368f61d3b8b961b4dc9b1390e3..b7df4766f1852be939106d96019bbc5c696828d3 100644 (file)
@@ -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);
index 6ba77e514234448dc4a3a2a8f20e9c6694cbc972..945bc8b3c283a7141ae73805e2bdb9d92c399825 100644 (file)
@@ -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);
index d67b77f91028e04bde16b75cea7f73957d422be5..af54b5274dd57e733c7e0177ba7f7738e24f75be 100644 (file)
@@ -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