]> git.ipfire.org Git - thirdparty/snort3.git/commitdiff
Merge pull request #2113 in SNORT/snort3 from ~OSERHIIE/snort3:trace_logger to master
authorMichael Altizer (mialtize) <mialtize@cisco.com>
Fri, 10 Apr 2020 23:27:02 +0000 (23:27 +0000)
committerMichael Altizer (mialtize) <mialtize@cisco.com>
Fri, 10 Apr 2020 23:27:02 +0000 (23:27 +0000)
Squashed commit of the following:

commit 5ae02e42ad00e7b23dea2ca7432f54f06c7debf5
Author: Oleksandr Serhiienko <oserhiie@cisco.com>
Date:   Fri Mar 13 17:05:30 2020 +0200

    trace: refactor stdout/syslog logging of trace into logger framework

19 files changed:
src/CMakeLists.txt
src/main/analyzer.cc
src/main/modules.cc
src/main/snort.cc
src/main/snort_config.cc
src/main/snort_config.h
src/main/snort_debug.cc
src/managers/coreinit.lua
src/trace/CMakeLists.txt [new file with mode: 0644]
src/trace/dev_notes.txt [new file with mode: 0644]
src/trace/trace_config.cc [new file with mode: 0644]
src/trace/trace_config.h [new file with mode: 0644]
src/trace/trace_log.cc [new file with mode: 0644]
src/trace/trace_log.h [new file with mode: 0644]
src/trace/trace_log_api.cc [new file with mode: 0644]
src/trace/trace_log_api.h [new file with mode: 0644]
src/trace/trace_log_base.h [new file with mode: 0644]
src/trace/trace_module.cc [new file with mode: 0644]
src/trace/trace_module.h [new file with mode: 0644]

index e9455b3c0c39c91634df73aeaa3e0eac89937060..0e5012d33a4f6b33eef0ac809d3007570aca90d8 100644 (file)
@@ -109,6 +109,7 @@ add_subdirectory(host_tracker)
 add_subdirectory(pub_sub)
 add_subdirectory(time)
 add_subdirectory(profiler)
+add_subdirectory(trace)
 add_subdirectory(utils)
 add_subdirectory(helpers)
 add_subdirectory(lua)
@@ -175,6 +176,7 @@ add_executable( snort
     $<TARGET_OBJECTS:target_based>
     $<TARGET_OBJECTS:tcp_connector>
     $<TARGET_OBJECTS:time>
+    $<TARGET_OBJECTS:trace>
     $<TARGET_OBJECTS:utils>
     ${PIGLET_LIBRARIES}
     ${STATIC_CODEC_PLUGINS}
index 1e2020b6046c39cd0bb35508908ebad1ee072be9..6a337c2664dec890d18b95ecd9bd552959e53de7 100644 (file)
@@ -63,6 +63,7 @@
 #include "side_channel/side_channel.h"
 #include "stream/stream.h"
 #include "time/packet_time.h"
+#include "trace/trace_log_api.h"
 #include "utils/stats.h"
 
 #include "analyzer_command.h"
@@ -590,6 +591,10 @@ void Analyzer::init_unprivileged()
         switcher->push(new IpsContext);
 
     SnortConfig* sc = SnortConfig::get_conf();
+
+    // This should be called as soon as possible
+    // to handle all trace log messages
+    TraceLogApi::thread_init(sc);
     CodecManager::thread_init(sc);
 
     // this depends on instantiated daq capabilities
@@ -676,6 +681,8 @@ void Analyzer::term()
 
     sfthreshold_free();
     RateFilter_Cleanup();
+
+    TraceLogApi::thread_term();
 }
 
 Analyzer::Analyzer(SFDAQInstance* instance, unsigned i, const char* s, uint64_t msg_cnt)
index 8b9ce42ea3b8e667a2177eb36c1004f7beee3c16..81861f332715d58ca91b1f248d014927e5559746 100644 (file)
@@ -58,6 +58,7 @@
 #include "stream/stream.h"
 #include "target_based/sftarget_data.h"
 #include "target_based/snort_protocols.h"
+#include "trace/trace_module.h"
 
 #include "snort_config.h"
 #include "snort_module.h"
@@ -1957,6 +1958,7 @@ void module_init()
     ModuleManager::add_module(new RuleStateModule);
     ModuleManager::add_module(new SearchEngineModule);
     ModuleManager::add_module(new SFDAQModule);
+    ModuleManager::add_module(new TraceModule);
 
     // these could but prolly shouldn't be policy specific
     // or should be broken into policy and non-policy parts
index 9d2e5034057eeaf8ad9b848c547df3c3156849f6..0b6a7150e5d2e9cc29294975ad2f0e4656d0b304 100644 (file)
@@ -67,6 +67,7 @@
 #include "stream/stream_inspectors.h"
 #include "target_based/sftarget_reader.h"
 #include "time/periodic.h"
+#include "trace/trace_log_api.h"
 #include "utils/util.h"
 
 #ifdef PIGLET
@@ -155,6 +156,11 @@ void Snort::init(int argc, char** argv)
      * Set the global snort_conf that will be used during run time */
     sc->merge(snort_cmd_line_conf);
     SnortConfig::set_conf(sc);
+
+    // This call must be immediately after "SnortConfig::set_conf(sc)"
+    // since the first trace call may happen somewhere after this point
+    TraceLogApi::thread_init(sc);
+
     PluginManager::load_so_plugins(sc);
 #ifdef PIGLET
     if ( !Piglet::piglet_mode() )
@@ -331,6 +337,10 @@ void Snort::term()
 
     LogMessage("%s  Snort exiting\n", get_prompt());
 
+    // This call must be before SnortConfig cleanup
+    // since the "TraceLogApi::thread_term()" uses SnortConfig
+    TraceLogApi::thread_term();
+
     /* free allocated memory */
     if (SnortConfig::get_conf() == snort_cmd_line_conf)
     {
index 935a8fad649fbf2dd8c8ab0ffd5a3f18feb70430..c3edd8c745dbf6b1c1b537270195e7f81747225a 100644 (file)
@@ -59,6 +59,7 @@
 #include "sfip/sf_ip.h"
 #include "target_based/sftarget_reader.h"
 #include "target_based/snort_protocols.h"
+#include "trace/trace_config.h"
 #include "utils/dnet_header.h"
 #include "utils/util.h"
 #include "utils/util_cstring.h"
@@ -264,6 +265,8 @@ SnortConfig::~SnortConfig()
     delete ha_config;
     delete global_dbus;
 
+    delete trace_config;
+
     delete profiler;
     delete latency;
     delete memory;
index 5c2c18bdde91ec77cce488f6e5a63a25444cf420..b52c15b521d7a1edc83fa2691f3e7a6b46dbafc7 100644 (file)
@@ -128,6 +128,7 @@ enum TunnelFlags
 class FastPatternConfig;
 class RuleStateMap;
 class ThreadConfig;
+class TraceConfig;
 
 struct srmm_table_t;
 struct sopg_table_t;
@@ -412,6 +413,10 @@ public:
     ThreadConfig* thread_config;
     HighAvailabilityConfig* ha_config = nullptr;
 
+    //------------------------------------------------------
+
+    TraceConfig* trace_config = nullptr;
+
     //------------------------------------------------------
     //Reload inspector related
 
index 57b03e8fa2bd2eae36133bb7b527837f42a88b8d..90169bbc536c954a209e4d3f40c3fc1a15cd63ef 100644 (file)
 
 #include "snort_debug.h"
 
-#include <syslog.h>
-
 #include <cstring>
 
-#include "log/messages.h"
+#include "trace/trace_log_api.h"
 #include "utils/safec.h"
 
-#include "snort_config.h"
+#define STD_BUF_SIZE 1024
 
 namespace snort
 {
-template <int (output)(const char*, FILE*)>
-static inline void trace_vprintf(const char* name, TraceLevel log_level,
+template <void (log_func)(const char*, const char*, uint8_t, const char*)>
+void trace_vprintf(const char* name, TraceLevel log_level,
     const char* trace_option, const char* fmt, va_list ap)
 {
-    char buf[STD_BUF];
-    int buf_len = sizeof(buf);
-    char* buf_ptr = buf;
-
-    if ( name )
-    {
-        int size = snprintf(buf, buf_len, "%s:%s:%d: ", name, trace_option, log_level);
-        if ( size >= buf_len )
-            size = buf_len - 1;
-        if ( size > 0 )
-        {
-            buf_ptr += size;
-            buf_len -= size;
-        }
-    }
-
-    vsnprintf(buf_ptr, buf_len, fmt, ap);
+    char buf[STD_BUF_SIZE];
+    vsnprintf(buf, sizeof(buf), fmt, ap);
 
-    if ( SnortConfig::get_conf() and SnortConfig::log_syslog() )
-        syslog(LOG_DAEMON | LOG_DEBUG, "%s", buf);
-    else
-        output(buf, stdout);
+    log_func(buf, name, log_level, trace_option);
 }
 
 void trace_vprintf(const char* name, TraceLevel log_level,
     const char* trace_option, const char* fmt, va_list ap)
 {
-    trace_vprintf<fputs>(name, log_level, trace_option, fmt, ap);
+    trace_vprintf<TraceLogApi::log>(name, log_level, trace_option, fmt, ap);
 }
 }
 
@@ -89,12 +69,13 @@ struct TestCase
     const char* expected;
 };
 
-static char testing_dump[STD_BUF];
-static int test_fputs(const char* str, FILE*)
-{
-    memcpy_s(testing_dump, STD_BUF, str, STD_BUF);
+static char testing_dump[STD_BUF_SIZE];
 
-    return 0;
+void test_log(const char* log_msg, const char* name,
+    uint8_t log_level, const char* trace_option)
+{
+    snprintf(testing_dump, sizeof(testing_dump), "%s:%s:%d: %s",
+        name, trace_option, log_level, log_msg);
 }
 
 TEST_CASE("macros", "[trace]")
@@ -129,10 +110,10 @@ TEST_CASE("macros", "[trace]")
 #undef trace_printf
 
 //These templates expand to replace the default expansion of trace_vprintf.
-//This custom expansion replaces output (expands to fputs in snort_debug.h macros)
-//with test_fputs for capturing what would be passed to the console.
-#define trace_print trace_print<trace_vprintf<test_fputs>>
-#define trace_printf trace_printf<trace_vprintf<test_fputs>>
+//This custom expansion replaces log_func (expands to TraceLogApi::log())
+//with test_log for capturing what would be passed to the console.
+#define trace_print trace_print<trace_vprintf<test_log>>
+#define trace_printf trace_printf<trace_vprintf<test_log>>
 
 enum
 {
@@ -152,189 +133,191 @@ const TraceOptionString test_trace_values[] =
     { "option5", TEST_TRACE_OPTION5 },
 };
 
-TEST_CASE("trace all=0", "[trace]")
+TEST_CASE("Trace logging", "[trace]")
 {
-    Trace test("test");
+    SECTION("trace all=0")
+    {
+        Trace test("test");
 
-    Parameter p("all", Parameter::PT_INT, "0:255", "0", "enabling traces in module");
-    Value trace_val((double)0);
-    trace_val.set(&p);
+        Parameter p("all", Parameter::PT_INT, "0:255", "0", "enable traces in module");
+        Value trace_val((double)0);
+        trace_val.set(&p);
 
-    test.set(trace_val);
+        test.set(trace_val);
 
-    testing_dump[0] = '\0';
-    debug_log(test, "my message");
-    CHECK( testing_dump[0] == '\0' );
-}
-
-TEST_CASE("debug_log", "[trace]")
-{
-    Trace test("test");
+        testing_dump[0] = '\0';
+        debug_log(test, "my message");
+        CHECK( testing_dump[0] == '\0' );
+    }
+    SECTION("debug_log")
+    {
+        Trace test("test");
 
-    Parameter p("all", Parameter::PT_INT, "0:255", "0", "enabling traces in module");
-    Value trace_val((double)1);
-    trace_val.set(&p);
+        Parameter p("all", Parameter::PT_INT, "0:255", "0", "enable traces in module");
+        Value trace_val((double)1);
+        trace_val.set(&p);
 
-    test.set(trace_val);
+        test.set(trace_val);
 
-    testing_dump[0] = '\0';
-    debug_log(test, "my message");
-    CHECK( !strcmp(testing_dump, "test:all:1: my message") );
+        testing_dump[0] = '\0';
+        debug_log(test, "my message");
+        CHECK( !strcmp(testing_dump, "test:all:1: my message") );
 
-    Parameter p_all("all", Parameter::PT_INT, "0:255", "0", "p_all");
-    Parameter p1("option1", Parameter::PT_INT, "0:255", "0", "p1");
-    Parameter p2("option3", Parameter::PT_INT, "0:255", "0", "p2");
-    Value trace_val1("trace");
+        Parameter p_all("all", Parameter::PT_INT, "0:255", "0", "p_all");
+        Parameter p1("option1", Parameter::PT_INT, "0:255", "0", "p1");
+        Parameter p2("option3", Parameter::PT_INT, "0:255", "0", "p2");
+        Value trace_val1("trace");
 
-    Trace testing_opt("testing_opt", test_trace_values,
-        (sizeof(test_trace_values) / sizeof(TraceOptionString)));
+        Trace testing_opt("testing_opt", test_trace_values,
+            (sizeof(test_trace_values) / sizeof(TraceOptionString)));
 
-    // set log_level = 1 for TEST_TRACE_OPTION1
-    trace_val1.set(&p1);
-    trace_val1.set_enum(1);
-    testing_opt.set(trace_val1);
+        // set log_level = 1 for TEST_TRACE_OPTION1
+        trace_val1.set(&p1);
+        trace_val1.set_enum(1);
+        testing_opt.set(trace_val1);
 
-    // set log_level = 5 for TEST_TRACE_OPTION3
-    trace_val1.set(&p2);
-    trace_val1.set_enum(5);
-    testing_opt.set(trace_val1);
+        // set log_level = 5 for TEST_TRACE_OPTION3
+        trace_val1.set(&p2);
+        trace_val1.set_enum(5);
+        testing_opt.set(trace_val1);
 
-    // set log_level = 2 for TEST_TRACE_OPTION2, TEST_TRACE_OPTION4, TEST_TRACE_OPTION5
-    trace_val1.set(&p_all);
-    trace_val1.set_enum(2);
-    testing_opt.set(trace_val1);
+        // set log_level = 2 for TEST_TRACE_OPTION2, TEST_TRACE_OPTION4, TEST_TRACE_OPTION5
+        trace_val1.set(&p_all);
+        trace_val1.set_enum(2);
+        testing_opt.set(trace_val1);
 
-    testing_dump[0] = '\0';
-    debug_log(testing_opt, TEST_TRACE_OPTION1, "my other masked message");
-    CHECK( !strcmp(testing_dump, "testing_opt:option1:1: my other masked message") );
+        testing_dump[0] = '\0';
+        debug_log(testing_opt, TEST_TRACE_OPTION1, "my other masked message");
+        CHECK( !strcmp(testing_dump, "testing_opt:option1:1: my other masked message") );
 
-    testing_dump[0] = '\0';
-    debug_log(3, testing_opt, TEST_TRACE_OPTION2, "log option2 message");
-    CHECK( testing_dump[0] == '\0' );
+        testing_dump[0] = '\0';
+        debug_log(3, testing_opt, TEST_TRACE_OPTION2, "log option2 message");
+        CHECK( testing_dump[0] == '\0' );
 
-    testing_dump[0] = '\0';
-    debug_log(testing_opt, TEST_TRACE_OPTION2, "log option2 message");
-    CHECK( !strcmp(testing_dump, "testing_opt:option2:1: log option2 message") );
+        testing_dump[0] = '\0';
+        debug_log(testing_opt, TEST_TRACE_OPTION2, "log option2 message");
+        CHECK( !strcmp(testing_dump, "testing_opt:option2:1: log option2 message") );
 
-    testing_dump[0] = '\0';
-    debug_log(6, testing_opt, TEST_TRACE_OPTION3, "log option3 message");
-    CHECK( testing_dump[0] == '\0' );
+        testing_dump[0] = '\0';
+        debug_log(6, testing_opt, TEST_TRACE_OPTION3, "log option3 message");
+        CHECK( testing_dump[0] == '\0' );
 
-    testing_dump[0] = '\0';
-    debug_log(3, testing_opt, TEST_TRACE_OPTION3, "log option3 message");
-    CHECK( !strcmp(testing_dump, "testing_opt:option3:3: log option3 message") );
+        testing_dump[0] = '\0';
+        debug_log(3, testing_opt, TEST_TRACE_OPTION3, "log option3 message");
+        CHECK( !strcmp(testing_dump, "testing_opt:option3:3: log option3 message") );
 
-    testing_dump[0] = '\0';
-    debug_log(2, testing_opt, TEST_TRACE_OPTION4, "log option4 message");
-    CHECK( !strcmp(testing_dump, "testing_opt:option4:2: log option4 message") );
+        testing_dump[0] = '\0';
+        debug_log(2, testing_opt, TEST_TRACE_OPTION4, "log option4 message");
+        CHECK( !strcmp(testing_dump, "testing_opt:option4:2: log option4 message") );
 
-    testing_dump[0] = '\0';
-    debug_log(4, testing_opt, TEST_TRACE_OPTION5, "log option5 message");
-    CHECK( testing_dump[0] == '\0' );
-}
+        testing_dump[0] = '\0';
+        debug_log(4, testing_opt, TEST_TRACE_OPTION5, "log option5 message");
+        CHECK( testing_dump[0] == '\0' );
+    }
+    SECTION("debug_logf")
+    {
+        Trace test("test");
+
+        Parameter p("all", Parameter::PT_INT, "0:255", "0", "enable traces in module");
+        Value trace_val((double)1);
+        trace_val.set(&p);
+        test.set(trace_val);
+
+        testing_dump[0] = '\0';
+        debug_logf(test, "%s %s", "my", "message");
+        CHECK( !strcmp(testing_dump, "test:all:1: my message") );
+
+        Parameter p_all("all", Parameter::PT_INT, "0:255", "0", "p_all");
+        Parameter p1("option1", Parameter::PT_INT, "0:255", "0", "p1");
+        Parameter p2("option3", Parameter::PT_INT, "0:255", "0", "p2");
+        Value trace_val1("trace");
+
+        Trace testing_opt("testing_opt", test_trace_values,
+            (sizeof(test_trace_values) / sizeof(TraceOptionString)));
+
+        // set log_level = 1 for TEST_TRACE_OPTION1
+        trace_val1.set(&p1);
+        trace_val1.set_enum(1);
+        testing_opt.set(trace_val1);
+
+        // set log_level = 5 for TEST_TRACE_OPTION3
+        trace_val1.set(&p2);
+        trace_val1.set_enum(5);
+        testing_opt.set(trace_val1);
+
+        // set log_level = 3 for TEST_TRACE_OPTION2, TEST_TRACE_OPTION4, TEST_TRACE_OPTION5
+        trace_val1.set(&p_all);
+        trace_val1.set_enum(3);
+        testing_opt.set(trace_val1);
+
+        testing_dump[0] = '\0';
+        debug_logf(testing_opt, TEST_TRACE_OPTION1, "%s %s %s", "log", "option1", "message");
+        CHECK( !strcmp(testing_dump, "testing_opt:option1:1: log option1 message") );
+
+        testing_dump[0] = '\0';
+        debug_logf(testing_opt, TEST_TRACE_OPTION2, "%s %s %s", "log", "option2", "message");
+        CHECK( !strcmp(testing_dump, "testing_opt:option2:1: log option2 message") );
+
+        testing_dump[0] = '\0';
+        debug_logf(4, testing_opt, TEST_TRACE_OPTION2, "%s %s %s", "log", "option2", "message");
+        CHECK( testing_dump[0] == '\0' );
+
+        testing_dump[0] = '\0';
+        debug_logf(3, testing_opt, TEST_TRACE_OPTION3, "%s %s %s", "log", "option3", "message");
+        CHECK( !strcmp(testing_dump, "testing_opt:option3:3: log option3 message") );
+
+        testing_dump[0] = '\0';
+        debug_logf(6, testing_opt, TEST_TRACE_OPTION3, "%s %s %s", "log", "option3", "message");
+        CHECK( testing_dump[0] == '\0' );
+
+        testing_dump[0] = '\0';
+        debug_logf(2, testing_opt, TEST_TRACE_OPTION4, "%s %s %s", "log", "option4", "message");
+        CHECK( !strcmp(testing_dump, "testing_opt:option4:2: log option4 message") );
+
+        testing_dump[0] = '\0';
+        debug_logf(4, testing_opt, TEST_TRACE_OPTION5, "%s %s %s", "log", "option5", "message");
+        CHECK( testing_dump[0] == '\0' );
+    }
+    SECTION("safety")
+    {
+        Trace test("test");
 
-TEST_CASE("debug_logf", "[trace]")
-{
-    Trace test("test");
-
-    Parameter p("all", Parameter::PT_INT, "0:255", "0", "enabling traces in module");
-    Value trace_val((double)1);
-    trace_val.set(&p);
-    test.set(trace_val);
-
-    testing_dump[0] = '\0';
-    debug_logf(test, "%s %s", "my", "message");
-    CHECK( !strcmp(testing_dump, "test:all:1: my message") );
-
-    Parameter p_all("all", Parameter::PT_INT, "0:255", "0", "p_all");
-    Parameter p1("option1", Parameter::PT_INT, "0:255", "0", "p1");
-    Parameter p2("option3", Parameter::PT_INT, "0:255", "0", "p2");
-    Value trace_val1("trace");
-
-    Trace testing_opt("testing_opt", test_trace_values,
-        (sizeof(test_trace_values) / sizeof(TraceOptionString)));
-
-    // set log_level = 1 for TEST_TRACE_OPTION1
-    trace_val1.set(&p1);
-    trace_val1.set_enum(1);
-    testing_opt.set(trace_val1);
-
-    // set log_level = 5 for TEST_TRACE_OPTION3
-    trace_val1.set(&p2);
-    trace_val1.set_enum(5);
-    testing_opt.set(trace_val1);
-
-    // set log_level = 3 for TEST_TRACE_OPTION2, TEST_TRACE_OPTION4, TEST_TRACE_OPTION5
-    trace_val1.set(&p_all);
-    trace_val1.set_enum(3);
-    testing_opt.set(trace_val1);
-
-    testing_dump[0] = '\0';
-    debug_logf(testing_opt, TEST_TRACE_OPTION1, "%s %s %s", "log", "option1", "message");
-    CHECK( !strcmp(testing_dump, "testing_opt:option1:1: log option1 message") );
-
-    testing_dump[0] = '\0';
-    debug_logf(testing_opt, TEST_TRACE_OPTION2, "%s %s %s", "log", "option2", "message");
-    CHECK( !strcmp(testing_dump, "testing_opt:option2:1: log option2 message") );
-
-    testing_dump[0] = '\0';
-    debug_logf(4, testing_opt, TEST_TRACE_OPTION2, "%s %s %s", "log", "option2", "message");
-    CHECK( testing_dump[0] == '\0' );
-
-    testing_dump[0] = '\0';
-    debug_logf(3, testing_opt, TEST_TRACE_OPTION3, "%s %s %s", "log", "option3", "message");
-    CHECK( !strcmp(testing_dump, "testing_opt:option3:3: log option3 message") );
-
-    testing_dump[0] = '\0';
-    debug_logf(6, testing_opt, TEST_TRACE_OPTION3, "%s %s %s", "log", "option3", "message");
-    CHECK( testing_dump[0] == '\0' );
-
-    testing_dump[0] = '\0';
-    debug_logf(2, testing_opt, TEST_TRACE_OPTION4, "%s %s %s", "log", "option4", "message");
-    CHECK( !strcmp(testing_dump, "testing_opt:option4:2: log option4 message") );
-
-    testing_dump[0] = '\0';
-    debug_logf(4, testing_opt, TEST_TRACE_OPTION5, "%s %s %s", "log", "option5", "message");
-    CHECK( testing_dump[0] == '\0' );
-}
+        Parameter p("all", Parameter::PT_INT, "0:255", "0", "enable traces in module");
+        Value trace_val((double)1);
+        trace_val.set(&p);
 
-TEST_CASE("safety", "[trace]")
-{
-    Trace test("test");
+        test.set(trace_val);
 
-    Parameter p("all", Parameter::PT_INT, "0:255", "0", "enabling traces in module");
-    Value trace_val((double)1);
-    trace_val.set(&p);
+        char message[STD_BUF_SIZE + 1];
 
-    test.set(trace_val);
+        for( int i = 0; i < STD_BUF_SIZE; i++ )
+            message[i] = 'A';
+        message[STD_BUF_SIZE] = '\0';
 
-    char message[STD_BUF + 1];
+        testing_dump[0] = '\0';
+        debug_log(test, message);
+        CHECK( (strlen(testing_dump) == STD_BUF_SIZE - 1) );
 
-    for( int i = 0; i < STD_BUF; i++ )
-        message[i] = 'A';
-    message[STD_BUF] = '\0';
+        Trace testing_opt("testing_opt", test_trace_values,
+            (sizeof(test_trace_values) / sizeof(TraceOptionString)));
 
-    testing_dump[0] = '\0';
-    debug_log(test, message);
-    CHECK( (strlen(testing_dump) == STD_BUF - 1) );
+        Parameter p1("option3", Parameter::PT_INT, "0:255", "0", "p1");
+        Value trace_val1("trace");
+        trace_val1.set(&p1);
+        trace_val1.set_enum(5);
+        testing_opt.set(trace_val1);
 
-    Trace testing_opt("testing_opt", test_trace_values,
-        (sizeof(test_trace_values) / sizeof(TraceOptionString)));
+        testing_dump[0] = '\0';
+        debug_log(3, testing_opt, TEST_TRACE_OPTION3, message);
+        CHECK( (strlen(testing_dump) == STD_BUF_SIZE - 1) );
 
-    Parameter p1("option3", Parameter::PT_INT, "0:255", "0", "p1");
-    Value trace_val1("trace");
-    trace_val1.set(&p1);
-    trace_val1.set_enum(5);
-    testing_opt.set(trace_val1);
+        testing_dump[0] = '\0';
+        debug_log(6, testing_opt, TEST_TRACE_OPTION3, message);
+        CHECK( (strlen(testing_dump) == 0) );
+    }
+}
 
-    testing_dump[0] = '\0';
-    debug_log(3, testing_opt, TEST_TRACE_OPTION3, message);
-    CHECK( (strlen(testing_dump) == STD_BUF - 1) );
+#endif  // DEBUG_MSGS
 
-    testing_dump[0] = '\0';
-    debug_log(6, testing_opt, TEST_TRACE_OPTION3, message);
-    CHECK( (strlen(testing_dump) == 0) );
-}
-#endif
+#endif  // UNIT_TEST
 
-#endif
index 7f607870dc494425b3de5185c0c47c4e318551c9..bf02b77eae78287a813b3696a9d7e9fb5a2b02b1 100644 (file)
@@ -39,6 +39,7 @@ packets = { }
 process = { }
 search_engine = { }
 so_proxy = { }
+trace = { }
 
 -- exceptions:
 
diff --git a/src/trace/CMakeLists.txt b/src/trace/CMakeLists.txt
new file mode 100644 (file)
index 0000000..adbb81c
--- /dev/null
@@ -0,0 +1,16 @@
+
+set ( TRACE_SOURCES
+    trace_config.cc
+    trace_config.h
+    trace_log.cc
+    trace_log.h
+    trace_log_api.cc
+    trace_log_api.h
+    trace_log_base.h
+    trace_module.cc
+    trace_module.h
+)
+
+add_library ( trace OBJECT
+    ${TRACE_SOURCES}
+)
diff --git a/src/trace/dev_notes.txt b/src/trace/dev_notes.txt
new file mode 100644 (file)
index 0000000..962fdfa
--- /dev/null
@@ -0,0 +1,66 @@
+This directory contains the trace logger framework.
+
+* TraceLogger
+
+    The TraceLogger encapsulates the logging method for traces. A particular thread-local logger
+    is created per each packet thread and one for the main thread. The logging configuration
+    happens in the module. The logger factory is used to init/cleanup loggers.
+
+    Include "trace_log_base.h" to get TraceLogger base class.
+    Derived loggers placed into "trace_log.h/trace_log.cc".
+
+* TraceLoggerFactory
+
+    The base TraceLoggerFactory is used to create a particular TraceLogger instance per each
+    thread. One factory instance exists which used to init/cleanup loggers and placed
+    into TraceConfig. The factory object instantiates in the module due to configuration.
+
+    Include "trace_log_base.h" to get TraceLoggerFactory base class and template function
+    to create particular objects. Derived factories placed into "trace_log.h/trace_log.cc".
+
+* TraceConfig
+
+    This is a class that handles a pointer to TraceLoggerFactory and used by TraceLogApi as
+    a global access point. Pointer to TraceConfig is placed into SnortConfig. It will be
+    overwritten during reloading and new TraceLoggerFactory pointer will be used by TraceLogApi
+    since that point.
+
+    TraceConfig placed into "trace_config.h".
+
+* TraceModule
+
+    This module provides configuration for trace logs. The main goal of TraceModule
+    is to create a concrete logger factory based on the configuration, init/reload TraceConfig
+    pointer and move it into SnortConfig.
+
+    This is a built-in module (from coreinit.lua)
+
+    The module placed into "trace_module.h/trace_module.cc".
+
+* TraceLogApi
+
+    TraceLogApi is a facade API class used to init/term trace logger framework and make logs
+    per each thread. TraceLogger is encapsulated in TraceLogApi. This, in a couple with
+    the TraceConfig, is a single common entry point to trace logger framework.
+
+    TraceLogApi placed into "trace_log_api.h/trace_log_api.cc"
+
+* Configuration override
+
+    By default, the factory will be initialized based on Snort run mode (stdout or syslog).
+    But this can be explicitly overwritten in TraceModule's configuration to specify which
+    kind of logger to use.
+
+    Changes will be applied in case of reloading too.
+
+* External dependencies
+
+    Include TraceLogApi header somewhere in the code where it needs to make trace logs.
+    Make sure that TraceLogApi::thread_init()/thread_term() are provided for thread where
+    TraceLogApi::log() is going used.
+
+    TraceConfig should be configured and moved into SnortConfig before TraceLogApi init.
+
+    To create specific TraceLogger/TraceLoggerFactory pair just inherit base classes placed
+    into "trace_log_base.h" and init TraceConfig with a new factory during configuration.
+
diff --git a/src/trace/trace_config.cc b/src/trace/trace_config.cc
new file mode 100644 (file)
index 0000000..f280607
--- /dev/null
@@ -0,0 +1,32 @@
+//--------------------------------------------------------------------------
+// Copyright (C) 2020-2020 Cisco and/or its affiliates. All rights reserved.
+//
+// This program is free software; you can redistribute it and/or modify it
+// under the terms of the GNU General Public License Version 2 as published
+// by the Free Software Foundation.  You may not use, modify or distribute
+// this program under any other version of the GNU General Public License.
+//
+// This program is distributed in the hope that it will be useful, but
+// WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+//--------------------------------------------------------------------------
+// trace_config.cc author Oleksandr Serhiienko <oserhiie@cisco.com>
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "trace_config.h"
+
+#include "trace_log_base.h"
+
+using namespace snort;
+
+TraceConfig::~TraceConfig()
+{ delete logger_factory; }
+
diff --git a/src/trace/trace_config.h b/src/trace/trace_config.h
new file mode 100644 (file)
index 0000000..ea8be45
--- /dev/null
@@ -0,0 +1,38 @@
+//--------------------------------------------------------------------------
+// Copyright (C) 2020-2020 Cisco and/or its affiliates. All rights reserved.
+//
+// This program is free software; you can redistribute it and/or modify it
+// under the terms of the GNU General Public License Version 2 as published
+// by the Free Software Foundation.  You may not use, modify or distribute
+// this program under any other version of the GNU General Public License.
+//
+// This program is distributed in the hope that it will be useful, but
+// WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+//--------------------------------------------------------------------------
+// trace_config.h author Oleksandr Serhiienko <oserhiie@cisco.com>
+
+#ifndef TRACE_CONFIG_H
+#define TRACE_CONFIG_H
+
+namespace snort
+{
+class TraceLoggerFactory;
+}
+
+class TraceConfig
+{
+public:
+    TraceConfig() = default;
+    ~TraceConfig();
+
+    snort::TraceLoggerFactory* logger_factory = nullptr;
+};
+
+#endif // TRACE_CONFIG_H
+
diff --git a/src/trace/trace_log.cc b/src/trace/trace_log.cc
new file mode 100644 (file)
index 0000000..fe43ceb
--- /dev/null
@@ -0,0 +1,100 @@
+//--------------------------------------------------------------------------
+// Copyright (C) 2020-2020 Cisco and/or its affiliates. All rights reserved.
+//
+// This program is free software; you can redistribute it and/or modify it
+// under the terms of the GNU General Public License Version 2 as published
+// by the Free Software Foundation.  You may not use, modify or distribute
+// this program under any other version of the GNU General Public License.
+//
+// This program is distributed in the hope that it will be useful, but
+// WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+//--------------------------------------------------------------------------
+// trace_log.cc author Oleksandr Serhiienko <oserhiie@cisco.com>
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "trace_log.h"
+
+#include <cstdio>
+#include <syslog.h>
+
+using namespace snort;
+
+//-----------------------------------------------
+//  Loggers
+//-----------------------------------------------
+
+// Stdout
+
+class StdoutTraceLogger : public TraceLogger
+{
+public:
+    StdoutTraceLogger();
+
+    void log(const char* log_msg, const char* name,
+        uint8_t log_level, const char* trace_option) override;
+
+private:
+    FILE* file;
+};
+
+StdoutTraceLogger::StdoutTraceLogger()
+    : file(stdout)
+{ }
+
+void StdoutTraceLogger::log(const char* log_msg, const char* name,
+    uint8_t log_level, const char* trace_option)
+{
+    fprintf(file, "%s:%s:%d: %s", name, trace_option, log_level, log_msg);
+}
+
+// Syslog
+
+class SyslogTraceLogger : public TraceLogger
+{
+public:
+    SyslogTraceLogger();
+
+    void log(const char* log_msg, const char* name,
+        uint8_t log_level, const char* trace_option) override;
+
+private:
+    int priority;
+};
+
+SyslogTraceLogger::SyslogTraceLogger()
+    : priority(LOG_DAEMON | LOG_DEBUG)
+{ }
+
+void SyslogTraceLogger::log(const char* log_msg, const char* name,
+    uint8_t log_level, const char* trace_option)
+{
+    syslog(priority, "%s:%s:%d: %s", name, trace_option, log_level, log_msg);
+}
+
+//-----------------------------------------------
+//  Logger factories
+//-----------------------------------------------
+
+// Stdout
+
+TraceLogger* StdoutLoggerFactory::instantiate()
+{
+    return new StdoutTraceLogger();
+}
+
+// Syslog
+
+TraceLogger* SyslogLoggerFactory::instantiate()
+{
+    return new SyslogTraceLogger();
+}
+
diff --git a/src/trace/trace_log.h b/src/trace/trace_log.h
new file mode 100644 (file)
index 0000000..34096ee
--- /dev/null
@@ -0,0 +1,50 @@
+//--------------------------------------------------------------------------
+// Copyright (C) 2020-2020 Cisco and/or its affiliates. All rights reserved.
+//
+// This program is free software; you can redistribute it and/or modify it
+// under the terms of the GNU General Public License Version 2 as published
+// by the Free Software Foundation.  You may not use, modify or distribute
+// this program under any other version of the GNU General Public License.
+//
+// This program is distributed in the hope that it will be useful, but
+// WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+//--------------------------------------------------------------------------
+// trace_log.h author Oleksandr Serhiienko <oserhiie@cisco.com>
+
+#ifndef TRACE_LOG_H
+#define TRACE_LOG_H
+
+#include "trace_log_base.h"
+
+//-----------------------------------------------
+//  Logger factories
+//-----------------------------------------------
+
+class StdoutLoggerFactory : public snort::TraceLoggerFactory
+{
+public:
+    StdoutLoggerFactory() = default;
+    StdoutLoggerFactory(const StdoutLoggerFactory&) = delete;
+    StdoutLoggerFactory& operator=(const StdoutLoggerFactory&) = delete;
+
+    snort::TraceLogger* instantiate() override;
+};
+
+class SyslogLoggerFactory : public snort::TraceLoggerFactory
+{
+public:
+    SyslogLoggerFactory() = default;
+    SyslogLoggerFactory(const SyslogLoggerFactory&) = delete;
+    SyslogLoggerFactory& operator=(const SyslogLoggerFactory&) = delete;
+
+    snort::TraceLogger* instantiate() override;
+};
+
+#endif // TRACE_LOG_H
+
diff --git a/src/trace/trace_log_api.cc b/src/trace/trace_log_api.cc
new file mode 100644 (file)
index 0000000..b3023c4
--- /dev/null
@@ -0,0 +1,54 @@
+//--------------------------------------------------------------------------
+// Copyright (C) 2020-2020 Cisco and/or its affiliates. All rights reserved.
+//
+// This program is free software; you can redistribute it and/or modify it
+// under the terms of the GNU General Public License Version 2 as published
+// by the Free Software Foundation.  You may not use, modify or distribute
+// this program under any other version of the GNU General Public License.
+//
+// This program is distributed in the hope that it will be useful, but
+// WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+//--------------------------------------------------------------------------
+// trace_log_api.cc author Oleksandr Serhiienko <oserhiie@cisco.com>
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "trace_log_api.h"
+
+#include "main/snort_config.h"
+#include "main/thread.h"
+
+#include "trace_config.h"
+#include "trace_log_base.h"
+
+using namespace snort;
+
+static THREAD_LOCAL TraceLogger* g_trace_logger = nullptr;
+
+void TraceLogApi::thread_init(SnortConfig* sc)
+{
+    if ( sc->trace_config and sc->trace_config->logger_factory )
+        g_trace_logger = sc->trace_config->logger_factory->instantiate();
+}
+
+void TraceLogApi::thread_term()
+{
+    delete g_trace_logger;
+    g_trace_logger = nullptr;
+}
+
+void TraceLogApi::log(const char* log_msg, const char* name,
+    uint8_t log_level, const char* trace_option)
+{
+    if ( g_trace_logger )
+        g_trace_logger->log(log_msg, name, log_level, trace_option);
+}
+
diff --git a/src/trace/trace_log_api.h b/src/trace/trace_log_api.h
new file mode 100644 (file)
index 0000000..afde508
--- /dev/null
@@ -0,0 +1,41 @@
+//--------------------------------------------------------------------------
+// Copyright (C) 2020-2020 Cisco and/or its affiliates. All rights reserved.
+//
+// This program is free software; you can redistribute it and/or modify it
+// under the terms of the GNU General Public License Version 2 as published
+// by the Free Software Foundation.  You may not use, modify or distribute
+// this program under any other version of the GNU General Public License.
+//
+// This program is distributed in the hope that it will be useful, but
+// WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+//--------------------------------------------------------------------------
+// trace_log_api.h author Oleksandr Serhiienko <oserhiie@cisco.com>
+
+#ifndef TRACE_LOG_API_H
+#define TRACE_LOG_API_H
+
+#include <cstdint>
+
+namespace snort
+{
+struct SnortConfig;
+
+class TraceLogApi
+{
+public:
+    static void thread_init(SnortConfig* sc);
+    static void thread_term();
+
+    static void log(const char* log_msg, const char* name,
+        uint8_t log_level, const char* trace_option);
+};
+}
+
+#endif // TRACE_LOG_API_H
+
diff --git a/src/trace/trace_log_base.h b/src/trace/trace_log_base.h
new file mode 100644 (file)
index 0000000..61dff13
--- /dev/null
@@ -0,0 +1,46 @@
+//--------------------------------------------------------------------------
+// Copyright (C) 2020-2020 Cisco and/or its affiliates. All rights reserved.
+//
+// This program is free software; you can redistribute it and/or modify it
+// under the terms of the GNU General Public License Version 2 as published
+// by the Free Software Foundation.  You may not use, modify or distribute
+// this program under any other version of the GNU General Public License.
+//
+// This program is distributed in the hope that it will be useful, but
+// WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+//--------------------------------------------------------------------------
+// trace_log_base.h author Oleksandr Serhiienko <oserhiie@cisco.com>
+
+#ifndef TRACE_LOG_BASE_H
+#define TRACE_LOG_BASE_H
+
+#include <cstdint>
+
+namespace snort
+{
+class TraceLogger
+{
+public:
+    virtual ~TraceLogger() = default;
+
+    virtual void log(const char* log_msg, const char* name,
+        uint8_t log_level, const char* trace_option) = 0;
+};
+
+class TraceLoggerFactory
+{
+public:
+    virtual ~TraceLoggerFactory() = default;
+
+    virtual TraceLogger* instantiate() = 0;
+};
+}
+
+#endif // TRACE_LOG_BASE_H
+
diff --git a/src/trace/trace_module.cc b/src/trace/trace_module.cc
new file mode 100644 (file)
index 0000000..ef7c23e
--- /dev/null
@@ -0,0 +1,132 @@
+//--------------------------------------------------------------------------
+// Copyright (C) 2020-2020 Cisco and/or its affiliates. All rights reserved.
+//
+// This program is free software; you can redistribute it and/or modify it
+// under the terms of the GNU General Public License Version 2 as published
+// by the Free Software Foundation.  You may not use, modify or distribute
+// this program under any other version of the GNU General Public License.
+//
+// This program is distributed in the hope that it will be useful, but
+// WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+//--------------------------------------------------------------------------
+// trace_module.cc author Serhii Vlasiuk <svlasiuk@cisco.com>
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "trace_module.h"
+
+#include <syslog.h>
+
+#include "main/snort_config.h"
+
+#include "trace_config.h"
+#include "trace_log.h"
+
+using namespace snort;
+
+static const Parameter trace_params[] =
+{
+    { "output", Parameter::PT_ENUM, "stdout | syslog", nullptr,
+      "output method for trace log messages" },
+
+    { nullptr, Parameter::PT_MAX, nullptr, nullptr, nullptr }
+};
+
+#define trace_help \
+    "configure trace log messages"
+
+TraceModule::TraceModule() : Module("trace", trace_help, trace_params, false)
+{ }
+
+TraceModule::~TraceModule()
+{
+    delete t_config;
+}
+
+bool TraceModule::begin(const char* fqn, int, SnortConfig* sc)
+{
+    if ( !strcmp(fqn, "trace") )
+    {
+        assert(!t_config);
+        t_config = new TraceConfig();
+
+        // Init default output type based on Snort run-mode
+        if ( sc->test_mode() )
+            log_output_type = OUTPUT_TYPE_NO_INIT;
+        else if ( sc->daemon_mode() or sc->log_syslog() )
+            log_output_type = OUTPUT_TYPE_SYSLOG;
+        else
+            log_output_type = OUTPUT_TYPE_STDOUT;
+    }
+
+    return true;
+}
+
+bool TraceModule::set(const char*, Value& v, SnortConfig* sc)
+{
+    if ( v.is("output") )
+    {
+        if ( sc->test_mode() )
+            return true;
+
+        switch ( v.get_uint8() )
+        {
+            case OUTPUT_TYPE_STDOUT:
+                log_output_type = OUTPUT_TYPE_STDOUT;
+                break;
+            case OUTPUT_TYPE_SYSLOG:
+                log_output_type = OUTPUT_TYPE_SYSLOG;
+                break;
+            default:
+                return false;
+        }
+
+        return true;
+    }
+
+    return false;
+}
+
+bool TraceModule::end(const char* fqn, int, SnortConfig* sc)
+{
+    if ( !strcmp(fqn, "trace") )
+    {
+        switch ( log_output_type )
+        {
+            case OUTPUT_TYPE_STDOUT:
+                t_config->logger_factory = new StdoutLoggerFactory();
+                break;
+            case OUTPUT_TYPE_SYSLOG:
+                t_config->logger_factory = new SyslogLoggerFactory();
+                break;
+            case OUTPUT_TYPE_NO_INIT:
+                t_config->logger_factory = nullptr;
+                break;
+        }
+
+        delete sc->trace_config;
+
+        sc->trace_config = t_config;
+        t_config = nullptr;
+
+        // "output=syslog" config override case
+        // do not closelog() here since it will be closed in Snort::clean_exit()
+        if ( !sc->log_syslog() and log_output_type == OUTPUT_TYPE_SYSLOG
+             and !local_syslog )
+        {
+            local_syslog = true;
+            openlog("snort", LOG_PID | LOG_CONS, LOG_DAEMON);
+        }
+    }
+
+    return true;
+}
+
diff --git a/src/trace/trace_module.h b/src/trace/trace_module.h
new file mode 100644 (file)
index 0000000..0dca7da
--- /dev/null
@@ -0,0 +1,55 @@
+//--------------------------------------------------------------------------
+// Copyright (C) 2020-2020 Cisco and/or its affiliates. All rights reserved.
+//
+// This program is free software; you can redistribute it and/or modify it
+// under the terms of the GNU General Public License Version 2 as published
+// by the Free Software Foundation.  You may not use, modify or distribute
+// this program under any other version of the GNU General Public License.
+//
+// This program is distributed in the hope that it will be useful, but
+// WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+//--------------------------------------------------------------------------
+// trace_module.h author Serhii Vlasiuk <svlasiuk@cisco.com>
+
+#ifndef TRACE_MODULE_H
+#define TRACE_MODULE_H
+
+#include "framework/module.h"
+
+class TraceConfig;
+
+class TraceModule : public snort::Module
+{
+private:
+    enum OutputType
+    {
+        OUTPUT_TYPE_STDOUT,
+        OUTPUT_TYPE_SYSLOG,
+        OUTPUT_TYPE_NO_INIT
+    };
+
+public:
+    TraceModule();
+    ~TraceModule() override;
+
+    bool begin(const char*, int, snort::SnortConfig*) override;
+    bool set(const char*, snort::Value&, snort::SnortConfig*) override;
+    bool end(const char*, int, snort::SnortConfig*) override;
+
+    Usage get_usage() const override
+    { return GLOBAL; }
+
+private:
+    OutputType log_output_type = OUTPUT_TYPE_NO_INIT;
+    TraceConfig* t_config = nullptr;
+    bool local_syslog = false;
+};
+
+#endif  // TRACE_MODULE_H
+