add_subdirectory(pub_sub)
add_subdirectory(time)
add_subdirectory(profiler)
+add_subdirectory(trace)
add_subdirectory(utils)
add_subdirectory(helpers)
add_subdirectory(lua)
$<TARGET_OBJECTS:target_based>
$<TARGET_OBJECTS:tcp_connector>
$<TARGET_OBJECTS:time>
+ $<TARGET_OBJECTS:trace>
$<TARGET_OBJECTS:utils>
${PIGLET_LIBRARIES}
${STATIC_CODEC_PLUGINS}
#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"
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
sfthreshold_free();
RateFilter_Cleanup();
+
+ TraceLogApi::thread_term();
}
Analyzer::Analyzer(SFDAQInstance* instance, unsigned i, const char* s, uint64_t msg_cnt)
#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"
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
#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
* 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() )
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)
{
#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"
delete ha_config;
delete global_dbus;
+ delete trace_config;
+
delete profiler;
delete latency;
delete memory;
class FastPatternConfig;
class RuleStateMap;
class ThreadConfig;
+class TraceConfig;
struct srmm_table_t;
struct sopg_table_t;
ThreadConfig* thread_config;
HighAvailabilityConfig* ha_config = nullptr;
+ //------------------------------------------------------
+
+ TraceConfig* trace_config = nullptr;
+
//------------------------------------------------------
//Reload inspector related
#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);
}
}
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]")
#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
{
{ "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
process = { }
search_engine = { }
so_proxy = { }
+trace = { }
-- exceptions:
--- /dev/null
+
+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}
+)
--- /dev/null
+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.
+
--- /dev/null
+//--------------------------------------------------------------------------
+// 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; }
+
--- /dev/null
+//--------------------------------------------------------------------------
+// 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
+
--- /dev/null
+//--------------------------------------------------------------------------
+// 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();
+}
+
--- /dev/null
+//--------------------------------------------------------------------------
+// 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
+
--- /dev/null
+//--------------------------------------------------------------------------
+// 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);
+}
+
--- /dev/null
+//--------------------------------------------------------------------------
+// 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
+
--- /dev/null
+//--------------------------------------------------------------------------
+// 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
+
--- /dev/null
+//--------------------------------------------------------------------------
+// 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;
+}
+
--- /dev/null
+//--------------------------------------------------------------------------
+// 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
+