]> git.ipfire.org Git - thirdparty/suricata.git/commitdiff
logging: json output 1578/head
authorVictor Julien <victor@inliniac.net>
Thu, 21 May 2015 15:33:53 +0000 (17:33 +0200)
committerVictor Julien <victor@inliniac.net>
Mon, 6 Jul 2015 14:44:40 +0000 (16:44 +0200)
Make JSON output optional.

Cleanups.

src/util-debug.c
src/util-debug.h

index ba8f97b40e46c0292578cc63ecc8dd9146d468ef..f1ac0463e505182323ff41d3d77dbf7a22502893 100644 (file)
@@ -188,6 +188,69 @@ static inline void SCLogPrintToSyslog(int syslog_log_level, const char *msg)
     return;
 }
 
+#ifdef HAVE_LIBJANSSON
+/**
+ */
+int SCLogMessageJSON(struct timeval *tval, char *buffer, size_t buffer_size,
+        SCLogLevel log_level, const char *file,
+        unsigned line, const char *function, SCError error_code,
+        const char *message)
+{
+    json_t *js = json_object();
+    if (unlikely(js == NULL))
+        goto error;
+    json_t *ejs = json_object();
+    if (unlikely(ejs == NULL))
+        goto error;
+
+    char timebuf[64];
+    CreateIsoTimeString(tval, timebuf, sizeof(timebuf));
+    json_object_set_new(js, "timestamp", json_string(timebuf));
+
+    json_object_set_new(js, "event_type", json_string("engine"));
+
+    if (error_code > 0) {
+        json_object_set_new(ejs, "error_code", json_integer(error_code));
+        json_object_set_new(ejs, "error", json_string(SCErrorToString(error_code)));
+    }
+
+    if (message)
+        json_object_set_new(ejs, "message", json_string(message));
+
+    if (log_level >= SC_LOG_DEBUG) {
+        if (function)
+            json_object_set_new(ejs, "function", json_string(function));
+
+        if (file)
+            json_object_set_new(ejs, "file", json_string(file));
+
+        if (line > 0)
+            json_object_set_new(ejs, "line", json_integer(line));
+    }
+
+    json_object_set_new(js, "engine", ejs);
+
+    char *js_s = json_dumps(js,
+            JSON_PRESERVE_ORDER|JSON_COMPACT|JSON_ENSURE_ASCII|
+#ifdef JSON_ESCAPE_SLASH
+            JSON_ESCAPE_SLASH
+#else
+            0
+#endif
+            );
+    snprintf(buffer, buffer_size, "%s", js_s);
+    free(js_s);
+
+    json_object_del(js, "engine");
+    json_object_clear(js);
+    json_decref(js);
+
+    return 0;
+error:
+    return -1;
+}
+#endif /* HAVE_LIBJANSSON */
+
 /**
  * \brief Adds the global log_format to the outgoing buffer
  *
@@ -199,13 +262,20 @@ static inline void SCLogPrintToSyslog(int syslog_log_level, const char *msg)
  *
  * \retval SC_OK on success; else an error code
  */
-static SCError SCLogMessageGetBuffer(struct timeval *tval, int color, char *buffer, size_t buffer_size,
+static SCError SCLogMessageGetBuffer(
+        struct timeval *tval, int color, SCLogOPType type,
+                     char *buffer, size_t buffer_size,
                      const char *log_format,
 
                      const SCLogLevel log_level, const char *file,
                      const unsigned int line, const char *function,
                      const SCError error_code, const char *message)
 {
+#ifdef HAVE_LIBJANSSON
+    if (type == SC_LOG_OP_TYPE_JSON)
+        return SCLogMessageJSON(tval, buffer, buffer_size, log_level, file, line, function, error_code, message);
+#endif
+
     char *temp = buffer;
     const char *s = NULL;
     struct tm *tms = NULL;
@@ -480,7 +550,8 @@ SCError SCLogMessage(const SCLogLevel log_level, const char *file,
 
         switch (op_iface_ctx->iface) {
             case SC_LOG_OP_IFACE_CONSOLE:
-                if (SCLogMessageGetBuffer(&tval, op_iface_ctx->use_color, buffer, sizeof(buffer),
+                if (SCLogMessageGetBuffer(&tval, op_iface_ctx->use_color, op_iface_ctx->type,
+                                          buffer, sizeof(buffer),
                                           op_iface_ctx->log_format ?
                                               op_iface_ctx->log_format : sc_log_config->log_format,
                                           log_level, file, line, function,
@@ -490,7 +561,7 @@ SCError SCLogMessage(const SCLogLevel log_level, const char *file,
                 }
                 break;
             case SC_LOG_OP_IFACE_FILE:
-                if (SCLogMessageGetBuffer(&tval, 0, buffer, sizeof(buffer),
+                if (SCLogMessageGetBuffer(&tval, 0, op_iface_ctx->type, buffer, sizeof(buffer),
                                           op_iface_ctx->log_format ?
                                               op_iface_ctx->log_format : sc_log_config->log_format,
                                           log_level, file, line, function,
@@ -500,7 +571,7 @@ SCError SCLogMessage(const SCLogLevel log_level, const char *file,
                 }
                 break;
             case SC_LOG_OP_IFACE_SYSLOG:
-                if (SCLogMessageGetBuffer(&tval, 0, buffer, sizeof(buffer),
+                if (SCLogMessageGetBuffer(&tval, 0, op_iface_ctx->type, buffer, sizeof(buffer),
                                           op_iface_ctx->log_format ?
                                               op_iface_ctx->log_format : sc_log_config->log_format,
                                           log_level, file, line, function,
@@ -599,7 +670,8 @@ static inline SCLogOPIfaceCtx *SCLogAllocLogOPIfaceCtx()
  */
 static inline SCLogOPIfaceCtx *SCLogInitFileOPIface(const char *file,
                                                     const char *log_format,
-                                                    int log_level)
+                                                    int log_level,
+                                                    SCLogOPType type)
 {
     SCLogOPIfaceCtx *iface_ctx = SCLogAllocLogOPIfaceCtx();
 
@@ -613,6 +685,7 @@ static inline SCLogOPIfaceCtx *SCLogInitFileOPIface(const char *file,
     }
 
     iface_ctx->iface = SC_LOG_OP_IFACE_FILE;
+    iface_ctx->type = type;
 
     if ( (iface_ctx->file_d = fopen(file, "w+")) == NULL) {
         printf("Error opening file %s\n", file);
@@ -659,7 +732,7 @@ error:
  * \initonly
  */
 static inline SCLogOPIfaceCtx *SCLogInitConsoleOPIface(const char *log_format,
-                                                       SCLogLevel log_level)
+                                                       SCLogLevel log_level, SCLogOPType type)
 {
     SCLogOPIfaceCtx *iface_ctx = SCLogAllocLogOPIfaceCtx();
 
@@ -669,6 +742,7 @@ static inline SCLogOPIfaceCtx *SCLogInitConsoleOPIface(const char *log_format,
     }
 
     iface_ctx->iface = SC_LOG_OP_IFACE_CONSOLE;
+    iface_ctx->type = type;
 
     /* console log format is overridden by envvars */
     const char *tmp_log_format = log_format;
@@ -721,7 +795,8 @@ static inline SCLogOPIfaceCtx *SCLogInitConsoleOPIface(const char *log_format,
  */
 static inline SCLogOPIfaceCtx *SCLogInitSyslogOPIface(int facility,
                                                       const char *log_format,
-                                                      SCLogLevel log_level)
+                                                      SCLogLevel log_level,
+                                                      SCLogOPType type)
 {
     SCLogOPIfaceCtx *iface_ctx = SCLogAllocLogOPIfaceCtx();
 
@@ -731,6 +806,7 @@ static inline SCLogOPIfaceCtx *SCLogInitSyslogOPIface(int facility,
     }
 
     iface_ctx->iface = SC_LOG_OP_IFACE_SYSLOG;
+    iface_ctx->type = type;
 
     if (facility == -1)
         facility = SC_LOG_DEF_SYSLOG_FACILITY;
@@ -906,18 +982,18 @@ static inline void SCLogSetOPIface(SCLogInitData *sc_lid, SCLogConfig *sc_lc)
 
         switch (op_iface) {
             case SC_LOG_OP_IFACE_CONSOLE:
-                op_ifaces_ctx = SCLogInitConsoleOPIface(NULL, SC_LOG_LEVEL_MAX);
+                op_ifaces_ctx = SCLogInitConsoleOPIface(NULL, SC_LOG_LEVEL_MAX,0);
                 break;
             case SC_LOG_OP_IFACE_FILE:
                 s = getenv(SC_LOG_ENV_LOG_FILE);
                 if (s == NULL) {
                     char *str = SCLogGetLogFilename(SC_LOG_DEF_LOG_FILE);
                     if (str != NULL) {
-                        op_ifaces_ctx = SCLogInitFileOPIface(str, NULL, SC_LOG_LEVEL_MAX);
+                        op_ifaces_ctx = SCLogInitFileOPIface(str, NULL, SC_LOG_LEVEL_MAX,0);
                         SCFree(str);
                     }
                 } else {
-                    op_ifaces_ctx = SCLogInitFileOPIface(s, NULL, SC_LOG_LEVEL_MAX);
+                    op_ifaces_ctx = SCLogInitFileOPIface(s, NULL, SC_LOG_LEVEL_MAX,0);
                 }
                 break;
             case SC_LOG_OP_IFACE_SYSLOG:
@@ -925,13 +1001,12 @@ static inline void SCLogSetOPIface(SCLogInitData *sc_lid, SCLogConfig *sc_lc)
                 if (s == NULL)
                     s = SC_LOG_DEF_SYSLOG_FACILITY_STR;
 
-                op_ifaces_ctx = SCLogInitSyslogOPIface(SCMapEnumNameToValue(s, SCSyslogGetFacilityMap()), NULL, -1);
+                op_ifaces_ctx = SCLogInitSyslogOPIface(SCMapEnumNameToValue(s, SCSyslogGetFacilityMap()), NULL, -1,0);
                 break;
         }
         sc_lc->op_ifaces = op_ifaces_ctx;
         sc_lc->op_ifaces_cnt++;
     }
-
     return;
 }
 
@@ -1113,11 +1188,12 @@ SCLogOPIfaceCtx *SCLogInitOPIfaceCtx(const char *iface_name,
 
     switch (iface) {
         case SC_LOG_OP_IFACE_CONSOLE:
-            return SCLogInitConsoleOPIface(log_format, log_level);
+            return SCLogInitConsoleOPIface(log_format, log_level, SC_LOG_OP_TYPE_REGULAR);
         case SC_LOG_OP_IFACE_FILE:
-            return SCLogInitFileOPIface(arg, log_format, log_level);
+            return SCLogInitFileOPIface(arg, log_format, log_level, SC_LOG_OP_TYPE_REGULAR);
         case SC_LOG_OP_IFACE_SYSLOG:
-            return SCLogInitSyslogOPIface(SCMapEnumNameToValue(arg, SCSyslogGetFacilityMap()), log_format, log_level);
+            return SCLogInitSyslogOPIface(SCMapEnumNameToValue(arg, SCSyslogGetFacilityMap()),
+                    log_format, log_level, SC_LOG_OP_TYPE_REGULAR);
         default:
 #ifdef DEBUG
             printf("Output Interface \"%s\" not supported by the logging module",
@@ -1230,6 +1306,22 @@ void SCLogLoadConfig(int daemon, int verbose)
         if (enabled != NULL && ConfValIsFalse(enabled))
             continue;
 
+        SCLogOPType type = SC_LOG_OP_TYPE_REGULAR;
+        const char *type_s = ConfNodeLookupChildValue(output, "type");
+        if (type_s != NULL) {
+            if (strcmp(type_s, "regular") == 0)
+                type = SC_LOG_OP_TYPE_REGULAR;
+            else if (strcmp(type_s, "json") == 0) {
+#ifdef HAVE_LIBJANSSON
+                type = SC_LOG_OP_TYPE_JSON;
+#else
+                SCLogError(SC_ERR_INVALID_ARGUMENT, "libjansson support not "
+                        "compiled in, can't use 'json' logging");
+                exit(EXIT_FAILURE);
+#endif /* HAVE_LIBJANSSON */
+            }
+        }
+
         /* if available use the log format setting for this output,
          * otherwise fall back to the global setting. */
         format = ConfNodeLookupChildValue(output, "format");
@@ -1247,7 +1339,7 @@ void SCLogLoadConfig(int daemon, int verbose)
         }
 
         if (strcmp(output->name, "console") == 0) {
-            op_iface_ctx = SCLogInitConsoleOPIface(format, level);
+            op_iface_ctx = SCLogInitConsoleOPIface(format, level, type);
         }
         else if (strcmp(output->name, "file") == 0) {
             const char *filename = ConfNodeLookupChildValue(output, "filename");
@@ -1257,7 +1349,7 @@ void SCLogLoadConfig(int daemon, int verbose)
                 exit(EXIT_FAILURE);
             }
             have_logging = 1;
-            op_iface_ctx = SCLogInitFileOPIface(filename, format, level);
+            op_iface_ctx = SCLogInitFileOPIface(filename, format, level, type);
         }
         else if (strcmp(output->name, "syslog") == 0) {
             int facility = SC_LOG_DEF_SYSLOG_FACILITY;
@@ -1275,7 +1367,7 @@ void SCLogLoadConfig(int daemon, int verbose)
             printf("Initialization syslog logging with format \"%s\".\n",
                 format);
             have_logging = 1;
-            op_iface_ctx = SCLogInitSyslogOPIface(facility, format, level);
+            op_iface_ctx = SCLogInitSyslogOPIface(facility, format, level, type);
         }
         else {
             SCLogWarning(SC_ERR_INVALID_ARGUMENT, "Invalid logging method: %s, "
@@ -1299,144 +1391,10 @@ void SCLogLoadConfig(int daemon, int verbose)
     SCLogDebug("sc_lc->log_format: %s", sc_log_config->log_format);
     SCLogDebug("SCLogSetOPFilter: filter: %s", sc_log_config->op_filter);
 
-    //exit(1);
-    /* \todo Can we free sc_lid now? */
     if (sc_lid != NULL)
         SCFree(sc_lid);
 }
 
-/**
- * \brief Initializes the logging module if the environment variables are set.
- *        Used at the start of the engine, for cases, where there is an error
- *        in the yaml parsing code, and we want to enable the logging module.
- */
-void SCLogInitLogModuleIfEnvSet(void)
-{
-    SCLogConfig *sc_lc = NULL;
-    const char *s = NULL;
-    const char *filter = NULL;
-    int opts = 0;
-    const char *ep;
-    int eo = 0;
-    SCLogOPIfaceCtx *op_ifaces_ctx = NULL;
-    int op_iface = 0;
-    char *format = NULL;
-    SCLogLevel log_level = SC_LOG_NOTSET;
-
-    /* sc_log_config is a global variable */
-    if ( (sc_log_config = SCMalloc(sizeof(SCLogConfig))) == NULL)
-        return;
-    memset(sc_log_config, 0, sizeof(SCLogConfig));
-    sc_lc = sc_log_config;
-
-    /* Check if the user has set the op_iface env var.  Only if it is set,
-     * we proceed with the initialization */
-    s = getenv(SC_LOG_ENV_LOG_OP_IFACE);
-    if (s != NULL) {
-        op_iface = SCMapEnumNameToValue(s, sc_log_op_iface_map);
-
-        if(op_iface < 0 || op_iface >= SC_LOG_OP_IFACE_MAX) {
-            op_iface = SC_LOG_DEF_LOG_OP_IFACE;
-#ifndef UNITTESTS
-            printf("Warning: Invalid output interface supplied by user.  "
-                   "Falling back on default_output_interface \"%s\"\n",
-                   SCMapEnumValueToName(op_iface, sc_log_op_iface_map));
-#endif
-        }
-    } else {
-        SCLogFreeLogConfig(sc_lc);
-        sc_log_config = NULL;
-        return;
-    }
-
-    switch (op_iface) {
-        case SC_LOG_OP_IFACE_CONSOLE:
-            op_ifaces_ctx = SCLogInitConsoleOPIface(NULL, -1);
-            break;
-        case SC_LOG_OP_IFACE_FILE:
-            s = getenv(SC_LOG_ENV_LOG_FILE);
-            if (s == NULL) {
-                char *str = SCLogGetLogFilename(SC_LOG_DEF_LOG_FILE);
-                if (str != NULL) {
-                    op_ifaces_ctx = SCLogInitFileOPIface(str, NULL, SC_LOG_LEVEL_MAX);
-                    SCFree(str);
-                }
-            } else {
-                op_ifaces_ctx = SCLogInitFileOPIface(s, NULL, -1);
-            }
-            break;
-        case SC_LOG_OP_IFACE_SYSLOG:
-            s = getenv(SC_LOG_ENV_LOG_FACILITY);
-            if (s == NULL)
-                s = SC_LOG_DEF_SYSLOG_FACILITY_STR;
-
-            op_ifaces_ctx = SCLogInitSyslogOPIface(SCMapEnumNameToValue(s, SCSyslogGetFacilityMap()), NULL, -1);
-            break;
-    }
-    sc_lc->op_ifaces = op_ifaces_ctx;
-
-
-    /* Set the filter */
-    filter = getenv(SC_LOG_ENV_LOG_OP_FILTER);
-    if (filter != NULL && strcmp(filter, "") != 0) {
-        sc_lc->op_filter_regex = pcre_compile(filter, opts, &ep, &eo, NULL);
-        if (sc_lc->op_filter_regex == NULL) {
-            printf("pcre compile of \"%s\" failed at offset %d : %s\n", filter,
-                   eo, ep);
-            return;
-        }
-
-        sc_lc->op_filter_regex_study = pcre_study(sc_lc->op_filter_regex, 0,
-                                                  &ep);
-        if (ep != NULL) {
-            printf("pcre study failed: %s\n", ep);
-            return;
-        }
-    }
-
-    /* Set the log_format */
-    format = getenv(SC_LOG_ENV_LOG_FORMAT);
-    if (format == NULL || strlen(format) > SC_LOG_MAX_LOG_FORMAT_LEN) {
-        format = SC_LOG_DEF_LOG_FORMAT;
-#ifndef UNITTESTS
-        printf("Warning: Invalid global_log_format supplied by user or format "
-               "length exceeded limit of \"%d\" characters.  Falling back on "
-               "default log_format \"%s\"\n", SC_LOG_MAX_LOG_FORMAT_LEN,
-               format);
-#endif
-    }
-
-    if (format != NULL &&
-        (sc_lc->log_format = SCStrdup(format)) == NULL) {
-        printf("Error allocating memory\n");
-        exit(EXIT_FAILURE);
-    }
-
-    /* Set the log_level */
-    s = getenv(SC_LOG_ENV_LOG_LEVEL);
-    if (s != NULL)
-        log_level = SCMapEnumNameToValue(s, sc_log_level_map);
-
-    if (log_level >= 0 && log_level < SC_LOG_LEVEL_MAX)
-        sc_lc->log_level = log_level;
-    else {
-        sc_lc->log_level = SC_LOG_DEF_LOG_LEVEL;
-#ifndef UNITTESTS
-        printf("Warning: Invalid global_log_level assigned by user.  Falling "
-               "back on default_log_level \"%s\"\n",
-               SCMapEnumValueToName(sc_lc->log_level, sc_log_level_map));
-#endif
-    }
-
-    /* we also set it to a global var, as it is easier to access it */
-    sc_log_global_log_level = sc_lc->log_level;
-
-    sc_log_module_initialized = 1;
-    sc_log_module_cleaned = 0;
-
-    return;
-}
-
 /**
  * \brief Returns a full file path given a filename uses log dir specified in
  *        conf or DEFAULT_LOG_DIR
index 9356e9a89a3866299517a224a2efa2678c703ecd..02ea30e2b08b3683a5704baa5afc25cd1bf7bcb4 100644 (file)
@@ -70,6 +70,11 @@ typedef enum {
     SC_LOG_OP_IFACE_MAX,
 } SCLogOPIface;
 
+typedef enum {
+    SC_LOG_OP_TYPE_REGULAR = 0,
+    SC_LOG_OP_TYPE_JSON,
+} SCLogOPType;
+
 /* The default log_format, if it is not supplied by the user */
 #ifdef RELEASE
 #define SC_LOG_DEF_LOG_FORMAT "%t - <%d> - "
@@ -112,7 +117,8 @@ typedef struct SCLogOPBuffer_ {
 typedef struct SCLogOPIfaceCtx_ {
     SCLogOPIface iface;
 
-    int use_color;
+    int16_t use_color;
+    int16_t type;
 
     /* the output file to be used if the interface is SC_LOG_IFACE_FILE */
     const char *file;
@@ -511,8 +517,6 @@ void SCLogAppendOPIfaceCtx(SCLogOPIfaceCtx *, SCLogInitData *);
 
 void SCLogInitLogModule(SCLogInitData *);
 
-void SCLogInitLogModuleIfEnvSet(void);
-
 void SCLogDeInitLogModule(void);
 
 SCError SCLogMessage(const SCLogLevel, const char *, const unsigned int,