From 999a17561d58ebb465c70c2cf2dedf2cf90e8c9a Mon Sep 17 00:00:00 2001 From: Ubuntu Date: Tue, 14 Jun 2022 01:19:04 +0000 Subject: [PATCH 1/8] Add rsyslog plugin and tests --- src/sonic-eventd/rsyslog_plugin/main.cpp | 49 +++++++ .../rsyslog_plugin/rsyslog_plugin.cpp | 77 +++++++++++ .../rsyslog_plugin/rsyslog_plugin.h | 43 ++++++ .../rsyslog_plugin/syslog_parser.cpp | 49 +++++++ .../rsyslog_plugin/syslog_parser.h | 28 ++++ .../rsyslog_plugin_ut.cpp | 125 ++++++++++++++++++ .../rsyslog_plugin_tests/test_regex_1.rc.json | 1 + .../rsyslog_plugin_tests/test_regex_2.rc.json | 7 + .../rsyslog_plugin_tests/test_regex_3.rc.json | 6 + .../rsyslog_plugin_tests/test_regex_4.rc.json | 7 + .../rsyslog_plugin_tests/test_syslogs.txt | 4 + 11 files changed, 396 insertions(+) create mode 100644 src/sonic-eventd/rsyslog_plugin/main.cpp create mode 100644 src/sonic-eventd/rsyslog_plugin/rsyslog_plugin.cpp create mode 100644 src/sonic-eventd/rsyslog_plugin/rsyslog_plugin.h create mode 100644 src/sonic-eventd/rsyslog_plugin/syslog_parser.cpp create mode 100644 src/sonic-eventd/rsyslog_plugin/syslog_parser.h create mode 100644 src/sonic-eventd/rsyslog_plugin_tests/rsyslog_plugin_ut.cpp create mode 100644 src/sonic-eventd/rsyslog_plugin_tests/test_regex_1.rc.json create mode 100644 src/sonic-eventd/rsyslog_plugin_tests/test_regex_2.rc.json create mode 100644 src/sonic-eventd/rsyslog_plugin_tests/test_regex_3.rc.json create mode 100644 src/sonic-eventd/rsyslog_plugin_tests/test_regex_4.rc.json create mode 100644 src/sonic-eventd/rsyslog_plugin_tests/test_syslogs.txt diff --git a/src/sonic-eventd/rsyslog_plugin/main.cpp b/src/sonic-eventd/rsyslog_plugin/main.cpp new file mode 100644 index 00000000000..6bf8862b73f --- /dev/null +++ b/src/sonic-eventd/rsyslog_plugin/main.cpp @@ -0,0 +1,49 @@ +#include +#include +#include "rsyslog_plugin.h" +#include "syslog_parser.h" + +using namespace std; + +void showUsage() { + cerr << "Usage for rsyslog_plugin: " << " SOURCES\n" + << "Options:\n" + << "\t-r,required,type=string\t\tPath to regex file" + << "\t-m,required,type=string\t\tYANG module name of source generating syslog message" + << endl; +} + +int main(int argc, char** argv) { + string regex_path; + string module_name; + int option_val; + + while((option_val = getopt(argc, argv, "r:m:")) != -1) { + switch(option_val) { + case 'r': + if(optarg != NULL) { + regex_path = optarg; + } + break; + case 'm': + if(optarg != NULL) { + module_name = optarg; + } + break; + default: + showUsage(); + return 1; + } + } + + if(regex_path.empty() || module_name.empty()) { // Missing required rc path + showUsage(); + return 1; + } + + SyslogParser* parser = new SyslogParser({}, json::array()); + RsyslogPlugin* plugin = new RsyslogPlugin(parser, module_name, regex_path); + + plugin->run(); + return 0; +} diff --git a/src/sonic-eventd/rsyslog_plugin/rsyslog_plugin.cpp b/src/sonic-eventd/rsyslog_plugin/rsyslog_plugin.cpp new file mode 100644 index 00000000000..b6ff5135518 --- /dev/null +++ b/src/sonic-eventd/rsyslog_plugin/rsyslog_plugin.cpp @@ -0,0 +1,77 @@ +#include +#include +#include +#include +#include +#include "rsyslog_plugin.h" +#include "common/logger.h" +#include "common/json.hpp" +#include "common/events.h" + +using namespace std; +using namespace swss; +using json = nlohmann::json; + +void RsyslogPlugin::onMessage(string msg) { + string tag = ""; + event_params_t param_dict; + if(!parser->parseMessage(msg, tag, param_dict)) { + SWSS_LOG_INFO("%s was not able to be parsed into a structured event\n", msg.c_str()); + } else { + int return_code = event_publish(fetchHandle(), tag, ¶m_dict); + if (return_code != 0) { + SWSS_LOG_INFO("rsyslog_plugin was not able to publish event for %s\n", tag.c_str()); + } + } +} + +[[noreturn]] void RsyslogPlugin::run() { + while(true) { + string line; + getline(cin, line); + if(line.empty()) { + continue; + } + onMessage(line); + } +} + +bool RsyslogPlugin::createRegexList() { + fstream regex_file; + regex_file.open(regex_path, ios::in); + if (!regex_file) { + SWSS_LOG_ERROR("No such path exists: %s for source %s\n", regex_path.c_str(), module_name.c_str()); + return false; + } + try { + regex_file >> parser->regex_list; + } catch (exception& exception) { + SWSS_LOG_ERROR("Invalid JSON file: %s, throws exception: %s\n", regex_path.c_str(), exception.what()); + return false; + } + + string regex_string = ""; + regex expression; + + for(long unsigned int i = 0; i < parser->regex_list.size(); i++) { + try { + regex_string = parser->regex_list[i]["regex"]; + regex expr(regex_string); + expression = expr; + } catch (exception& exception) { + SWSS_LOG_ERROR("Invalid regex, throws exception: %s\n", exception.what()); + return false; + } + parser->expressions.push_back(expression); + } + regex_file.close(); + return true; +} + + +RsyslogPlugin::RsyslogPlugin(SyslogParser* syslog_parser, string mod_name, string path) { + parser = syslog_parser; + module_name = mod_name; + regex_path = path; + onInit(); +} diff --git a/src/sonic-eventd/rsyslog_plugin/rsyslog_plugin.h b/src/sonic-eventd/rsyslog_plugin/rsyslog_plugin.h new file mode 100644 index 00000000000..631652cbb5a --- /dev/null +++ b/src/sonic-eventd/rsyslog_plugin/rsyslog_plugin.h @@ -0,0 +1,43 @@ +#ifndef RSYSLOG_PLUGIN_H +#define RSYSLOG_PLUGIN_H + +#include +#include +#include "syslog_parser.h" +#include "common/logger.h" +#include "common/events.h" + +using namespace std; +using json = nlohmann::json; + +/** + * Rsyslog Plugin will utilize an instance of a syslog parser to read syslog messages from rsyslog.d and will continuously read from stdin + * A plugin instance is created for each container/host. + * + */ + +class RsyslogPlugin { +public: + RsyslogPlugin(SyslogParser* syslog_parser, string mod_name, string path); + void onMessage(string msg); + void run(); + bool createRegexList(); + event_handle_t fetchHandle() { + return event_handle; + } + SyslogParser* parser; +private: + string regex_path; + string module_name; + event_handle_t event_handle; + + bool onInit() { + event_handle = events_init_publisher(module_name); + int return_code = createRegexList(); + return (event_handle != NULL || return_code == 0); + } + +}; + +#endif + diff --git a/src/sonic-eventd/rsyslog_plugin/syslog_parser.cpp b/src/sonic-eventd/rsyslog_plugin/syslog_parser.cpp new file mode 100644 index 00000000000..fa56aeff224 --- /dev/null +++ b/src/sonic-eventd/rsyslog_plugin/syslog_parser.cpp @@ -0,0 +1,49 @@ +#include +#include +#include +#include +#include "syslog_parser.h" +#include "common/logger.h" + + +using namespace std; +/** + * Parses syslog message and returns structured event + * + * @param nessage us syslog message being fed in by rsyslog.d + * @return return structured event json for publishing + * +*/ + +bool SyslogParser::parseMessage(string message, string& event_tag, event_params_t& param_map) { + for(long unsigned int i = 0; i < regex_list.size(); i++) { + smatch match_results; + regex_search(message, match_results, expressions[i]); + vector groups; + vector params; + try { + event_tag = regex_list[i]["tag"]; + vector p = regex_list[i]["params"]; + params = p; + } catch (exception& exception) { + SWSS_LOG_ERROR("Invalid regex list, throws exception: %s\n", exception.what()); + return false; + } + // first match in groups is entire message + for(long unsigned int j = 1; j < match_results.size(); j++) { + groups.push_back(match_results.str(j)); + } + if (groups.size() == params.size()) { // found matching regex + transform(params.begin(), params.end(), groups.begin(), inserter(param_map, param_map.end()), [](string a, string b) { + return make_pair(a,b); + }); + return true; + } + } + return false; +} + +SyslogParser::SyslogParser(vector regex_expressions, json list) { + expressions = regex_expressions; + regex_list = list; +} diff --git a/src/sonic-eventd/rsyslog_plugin/syslog_parser.h b/src/sonic-eventd/rsyslog_plugin/syslog_parser.h new file mode 100644 index 00000000000..5e970f84fa9 --- /dev/null +++ b/src/sonic-eventd/rsyslog_plugin/syslog_parser.h @@ -0,0 +1,28 @@ +#ifndef SYSLOG_PARSER_H +#define SYSLOG_PARSER_H + +#include +#include +#include +#include "common/json.hpp" +#include "common/events.h" + +using namespace std; +using json = nlohmann::json; + +/** + * Syslog Parser is responsible for parsing log messages fed by rsyslog.d and returns + * matched result to rsyslog_plugin to use with events publish API + * + */ + +class SyslogParser { +public: + SyslogParser(vector regex_expressions, json list); + bool parseMessage(string message, string& tag, event_params_t& param_dict); + + vector expressions; + json regex_list = json::array(); +}; + +#endif diff --git a/src/sonic-eventd/rsyslog_plugin_tests/rsyslog_plugin_ut.cpp b/src/sonic-eventd/rsyslog_plugin_tests/rsyslog_plugin_ut.cpp new file mode 100644 index 00000000000..12f9a247acf --- /dev/null +++ b/src/sonic-eventd/rsyslog_plugin_tests/rsyslog_plugin_ut.cpp @@ -0,0 +1,125 @@ +#include +#include +#include +#include "gtest/gtest.h" +#include "common/json.hpp" +#include "common/events.h" +#include "rsyslog_plugin/rsyslog_plugin.h" +#include "rsyslog_plugin/syslog_parser.h" + +using namespace std; +using json = nlohmann::json; + +RsyslogPlugin* plugin = NULL; + +json j_list_1 = json::array(); +json j_list_2 = json::array(); +vector test_expressions_1; +vector test_expressions_2; + +void createTests() { + string regex_string_1 = "timestamp (.*) message (.*) other_data (.*)"; + string regex_string_2 = "no match"; + + json j_test_1; + j_test_1["tag"] = "test_tag_1"; + j_test_1["regex"] = regex_string_1; + j_test_1["params"] = { "timestamp", "message", "other_data" }; + j_list_1.push_back(j_test_1); + + json j_test_2; + j_test_2["tag"] = "test_tag_2"; + j_test_2["regex"] = regex_string_2; + j_test_2["params"] = {}; + j_list_2.push_back(j_test_2); + + regex expression_1(regex_string_1); + test_expressions_1.push_back(expression_1); + regex expression_2(regex_string_2); + test_expressions_2.push_back(expression_2); +} + + +TEST(syslog_parser, matching_regex) { + createTests(); + string tag = ""; + event_params_t param_dict; + + event_params_t expected_dict; + expected_dict["timestamp"] = "test_timestamp"; + expected_dict["message"] = "test_message"; + expected_dict["other_data"] = "test_data"; + + SyslogParser* parser = new SyslogParser(test_expressions_1, j_list_1); + + bool success = parser->parseMessage("timestamp test_timestamp message test_message other_data test_data", tag, param_dict); + EXPECT_EQ(true, success); + EXPECT_EQ("test_tag_1", tag); + EXPECT_EQ(expected_dict, param_dict); + + delete parser; +} + +TEST(syslog_parser, no_matching_regex) { + string tag = ""; + event_params_t param_dict; + SyslogParser* parser = new SyslogParser(test_expressions_2, j_list_2); + bool success = parser->parseMessage("Test Message", tag, param_dict); + EXPECT_EQ(false, success); + delete parser; +} + + +void createPlugin(string path) { + SyslogParser* testParser = new SyslogParser({}, json::array()); + plugin = new RsyslogPlugin(testParser, "test_mod_name", path); +} + +TEST(rsyslog_plugin, createRegexList_invalidJS0N) { + createPlugin("./test_regex_1.rc.json"); + if(plugin != NULL) { + EXPECT_EQ(false, plugin->createRegexList()); + } + delete plugin; +} + +TEST(rsyslog_plugin, createRegexList_missingRegex) { + createPlugin("./test_regex_3.rc.json"); + if(plugin != NULL) { + EXPECT_EQ(false, plugin->createRegexList()); + } + delete plugin; +} + +TEST(rsyslog_plugin, createRegexList_invalidRegex) { + createPlugin("./test_regex_4.rc.json"); + if(plugin != NULL) { + EXPECT_EQ(false, plugin->createRegexList()); + } + delete plugin; +} + +TEST(rsyslog_plugin, createRegexList_validRegex) { + createPlugin("./test_regex_2.rc.json"); + if(plugin != NULL) { + auto parser = plugin->parser; + EXPECT_EQ(1, parser->regex_list.size()); + EXPECT_EQ(1, parser->expressions.size()); + + ifstream infile("test_syslogs.txt"); + string log_message; + bool parse_result; + + while(infile >> log_message >> parse_result) { + string tag = ""; + event_params_t param_dict; + EXPECT_EQ(parse_result, parser->parseMessage(log_message, tag, param_dict)); + } + } + delete plugin; +} + +int main(int argc, char* argv[]) { + testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} diff --git a/src/sonic-eventd/rsyslog_plugin_tests/test_regex_1.rc.json b/src/sonic-eventd/rsyslog_plugin_tests/test_regex_1.rc.json new file mode 100644 index 00000000000..72e8ffc0db8 --- /dev/null +++ b/src/sonic-eventd/rsyslog_plugin_tests/test_regex_1.rc.json @@ -0,0 +1 @@ +* diff --git a/src/sonic-eventd/rsyslog_plugin_tests/test_regex_2.rc.json b/src/sonic-eventd/rsyslog_plugin_tests/test_regex_2.rc.json new file mode 100644 index 00000000000..5c9a2e9612e --- /dev/null +++ b/src/sonic-eventd/rsyslog_plugin_tests/test_regex_2.rc.json @@ -0,0 +1,7 @@ +[ + { + "tag": "bgp-state", + "regex": "([a-zA-Z]{3} [0-9]{2} [0-9]{2}:[0-9]{2}:[0-9]{2}.[0-9]{0,6}) .* %ADJCHANGE: neighbor (.*) (Up|Down) .*", + "params": [ "timestamp", "neighbor_ip", "state" ] + } +] diff --git a/src/sonic-eventd/rsyslog_plugin_tests/test_regex_3.rc.json b/src/sonic-eventd/rsyslog_plugin_tests/test_regex_3.rc.json new file mode 100644 index 00000000000..2e67e88f844 --- /dev/null +++ b/src/sonic-eventd/rsyslog_plugin_tests/test_regex_3.rc.json @@ -0,0 +1,6 @@ +[ + { + "tag": "TEST-TAG-NO-REGEX", + "param": [] + } +] diff --git a/src/sonic-eventd/rsyslog_plugin_tests/test_regex_4.rc.json b/src/sonic-eventd/rsyslog_plugin_tests/test_regex_4.rc.json new file mode 100644 index 00000000000..244b601fbac --- /dev/null +++ b/src/sonic-eventd/rsyslog_plugin_tests/test_regex_4.rc.json @@ -0,0 +1,7 @@ +[ + { + "tag": "TEST-TAG-INVALID-REGEX", + "regex": "++", + "params": [] + } +] diff --git a/src/sonic-eventd/rsyslog_plugin_tests/test_syslogs.txt b/src/sonic-eventd/rsyslog_plugin_tests/test_syslogs.txt new file mode 100644 index 00000000000..78f89aec3d2 --- /dev/null +++ b/src/sonic-eventd/rsyslog_plugin_tests/test_syslogs.txt @@ -0,0 +1,4 @@ +"Aug 17 02:39:21.286611 SN6-0101-0114-02T0 INFO bgp#bgpd[62]: %ADJCHANGE: neighbor 100.126.188.90 Down Neighbor deleted" true +"Aug 17 02:46:42.615668 SN6-0101-0114-02T0 INFO bgp#bgpd[62]: %ADJCHANGE: neighbor 100.126.188.90 Up" true +"Aug 17 04:46:51.290979 SN6-0101-0114-02T0 INFO bgp#bgpd[62]: %ADJCHANGE: neighbor 100.126.188.78 Down Neighbor deleted" true +"Aug 17 04:46:51.290979 SN6-0101-0114-02T0 INFO bgp#bgpd[62]: %NOEVENT: no event" false From 3082cf8407f71aa6cd05b292a648a21835ae6211 Mon Sep 17 00:00:00 2001 From: Ubuntu Date: Tue, 14 Jun 2022 01:45:04 +0000 Subject: [PATCH 2/8] Add syslog if init fails --- src/sonic-eventd/rsyslog_plugin/rsyslog_plugin.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/sonic-eventd/rsyslog_plugin/rsyslog_plugin.cpp b/src/sonic-eventd/rsyslog_plugin/rsyslog_plugin.cpp index b6ff5135518..29293fd430f 100644 --- a/src/sonic-eventd/rsyslog_plugin/rsyslog_plugin.cpp +++ b/src/sonic-eventd/rsyslog_plugin/rsyslog_plugin.cpp @@ -73,5 +73,7 @@ RsyslogPlugin::RsyslogPlugin(SyslogParser* syslog_parser, string mod_name, strin parser = syslog_parser; module_name = mod_name; regex_path = path; - onInit(); + if(!onInit()) { + SWSS_LOG_ERROR("Initializing rsyslog plugin failed.\n"); + } } From ee28577a5e03c971e53d067802a3544b7ff533dd Mon Sep 17 00:00:00 2001 From: Ubuntu Date: Tue, 14 Jun 2022 01:47:25 +0000 Subject: [PATCH 3/8] Fix onInit logic --- src/sonic-eventd/rsyslog_plugin/rsyslog_plugin.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sonic-eventd/rsyslog_plugin/rsyslog_plugin.h b/src/sonic-eventd/rsyslog_plugin/rsyslog_plugin.h index 631652cbb5a..252083117b2 100644 --- a/src/sonic-eventd/rsyslog_plugin/rsyslog_plugin.h +++ b/src/sonic-eventd/rsyslog_plugin/rsyslog_plugin.h @@ -34,7 +34,7 @@ class RsyslogPlugin { bool onInit() { event_handle = events_init_publisher(module_name); int return_code = createRegexList(); - return (event_handle != NULL || return_code == 0); + return (event_handle != NULL && return_code == 0); } }; From 7cb88d74f52bdaed5a322e3748a2609aa235ffec Mon Sep 17 00:00:00 2001 From: Ubuntu Date: Wed, 15 Jun 2022 20:07:24 +0000 Subject: [PATCH 4/8] Add makefile and resolve PR comments --- src/sonic-eventd/Makefile | 83 +++++++++++ src/sonic-eventd/rsyslog_plugin/main.cpp | 29 ++-- .../rsyslog_plugin/rsyslog_plugin.cpp | 76 +++++----- .../rsyslog_plugin/rsyslog_plugin.h | 24 ++-- src/sonic-eventd/rsyslog_plugin/subdir.mk | 13 ++ .../rsyslog_plugin/syslog_parser.cpp | 37 ++--- .../rsyslog_plugin/syslog_parser.h | 8 +- .../rsyslog_plugin_ut.cpp | 131 +++++++++--------- .../rsyslog_plugin_tests/subdir.mk | 12 ++ .../rsyslog_plugin_tests/test_regex_5.rc.json | 7 + .../rsyslog_plugin_tests/test_syslogs_2.txt | 3 + 11 files changed, 262 insertions(+), 161 deletions(-) create mode 100644 src/sonic-eventd/Makefile create mode 100644 src/sonic-eventd/rsyslog_plugin/subdir.mk create mode 100644 src/sonic-eventd/rsyslog_plugin_tests/subdir.mk create mode 100644 src/sonic-eventd/rsyslog_plugin_tests/test_regex_5.rc.json create mode 100644 src/sonic-eventd/rsyslog_plugin_tests/test_syslogs_2.txt diff --git a/src/sonic-eventd/Makefile b/src/sonic-eventd/Makefile new file mode 100644 index 00000000000..b21689a76fa --- /dev/null +++ b/src/sonic-eventd/Makefile @@ -0,0 +1,83 @@ +RM := rm -rf +EVENTD_TARGET := eventd +EVENTD_TEST := tests/tests +EVENTD_TOOL := tools/events_tool +RSYSLOG-PLUGIN_TARGET := rsyslog_plugin +RSYSLOG-PLUGIN_TEST: rsyslog_plugin_tests/tests +CP := cp +MKDIR := mkdir +CC := g++ +MV := mv +LIBS := -levent -lhiredis -lswsscommon -lpthread -lboost_thread -lboost_system -lzmq -lboost_serialization -luuid +TEST_LIBS := -L/usr/src/gtest -lgtest -lgtest_main -lgmock -lgmock_main + +CFLAGS += -Wall -std=c++17 -fPIE -I$(PWD)/../sonic-swss-common/common +PWD := $(shell pwd) + +ifneq ($(MAKECMDGOALS),clean) +ifneq ($(strip $(C_DEPS)),) +-include $(C_DEPS) $(OBJS) +endif +endif + +-include src/subdir.mk +-include tests/subdir.mk +-include tools/subdir.mk +-include rsyslog_plugin/subdir.mk + +all: sonic-eventd eventd-tests eventd-tool rsyslog-plugin rsyslog-plugin-tests + +sonic-eventd: $(OBJS) + @echo 'Building target: $@' + @echo 'Invoking: G++ Linker' + $(CC) $(LDFLAGS) -o $(EVENTD_TARGET) $(OBJS) $(LIBS) + @echo 'Finished building target: $@' + @echo ' ' + +eventd-tool: $(TOOL_OBJS) + @echo 'Building target: $@' + @echo 'Invoking: G++ Linker' + $(CC) $(LDFLAGS) -o $(EVENTD_TOOL) $(TOOL_OBJS) $(LIBS) + @echo 'Finished building target: $@' + @echo ' ' + +rsyslog-plugin: $(RSYSLOG-PLUGIN_OBJS) + @echo 'Buidling Target: $@' + @echo 'Invoking: G++ Linker' + $(CC) $(LDFLAGS) -o $(RSYSLOG-PLUGIN_TARGET) $(RSYSLOG-PLUGIN_OBJS) $(LIBS) + @echo 'Finished building target: $@' + @echo ' ' + +eventd-tests: $(TEST_OBJS) + @echo 'Building target: $@' + @echo 'Invoking: G++ Linker' + $(CC) $(LDFLAGS) -o $(EVENTD_TEST) $(TEST_OBJS) $(LIBS) $(TEST_LIBS) + @echo 'Finished building target: $@' + $(EVENTD_TEST) + @echo 'Finished running tests' + @echo ' ' + +rsyslog-plugin-tests: $(RSYSLOG-PLUGIN-TEST_OBJS) + @echo 'BUILDING target: $@' + @echo 'Invoking G++ Linker' + $(CC) $(LDFLAGS) -o $(RSYSLOG-PLUGIN_TEST) $(RSYSLOG-PLUGIN-TEST_OBJS) $(LIBS) $(TEST_LIBS) + @echo 'Finished building target: $@' + $(RSYSLOG-PLUGIN_TEST) + @echo 'Finished running tests' + @echo ' ' + +install: + $(MKDIR) -p $(DESTDIR)/usr/sbin + $(MV) $(EVENTD_TARGET) $(DESTDIR)/usr/sbin + $(MV) $(EVENTD_TOOL) $(DESTDIR)/usr/sbin + $(MV) $(RSYSLOG-PLUGIN_TARGET) $(DESTDIR)/usr/sbin + +deinstall: + $(RM) $(DESTDIR)/usr/sbin/$(EVENTD_TARGET) + $(RM) $(DESTDIR)/usr/sbin/$(RSYSLOG-PLUGIN_TARGET) + $(RM) -rf $(DESTDIR)/usr/sbin + +clean: + -@echo ' ' + +.PHONY: all clean dependents diff --git a/src/sonic-eventd/rsyslog_plugin/main.cpp b/src/sonic-eventd/rsyslog_plugin/main.cpp index 6bf8862b73f..033d45f4ad5 100644 --- a/src/sonic-eventd/rsyslog_plugin/main.cpp +++ b/src/sonic-eventd/rsyslog_plugin/main.cpp @@ -6,10 +6,10 @@ using namespace std; void showUsage() { - cerr << "Usage for rsyslog_plugin: " << " SOURCES\n" - << "Options:\n" - << "\t-r,required,type=string\t\tPath to regex file" - << "\t-m,required,type=string\t\tYANG module name of source generating syslog message" + cout << "Usage for rsyslog_plugin: \n" << "options\n" + << "\t-r,required,type=string\t\tPath to regex file\n" + << "\t-m,required,type=string\t\tYANG module name of source generating syslog message\n" + << "\t-h \t\tHelp" << endl; } @@ -18,18 +18,16 @@ int main(int argc, char** argv) { string module_name; int option_val; - while((option_val = getopt(argc, argv, "r:m:")) != -1) { + while((option_val = getopt(argc, argv, "r:m:h")) != -1) { switch(option_val) { case 'r': - if(optarg != NULL) { - regex_path = optarg; - } + regex_path = optarg; break; case 'm': - if(optarg != NULL) { - module_name = optarg; - } + module_name = optarg; break; + case 'h': + case '?': default: showUsage(); return 1; @@ -37,12 +35,15 @@ int main(int argc, char** argv) { } if(regex_path.empty() || module_name.empty()) { // Missing required rc path - showUsage(); + cerr << "Error: Missing regex_path and module_name." << endl; return 1; } - SyslogParser* parser = new SyslogParser({}, json::array()); - RsyslogPlugin* plugin = new RsyslogPlugin(parser, module_name, regex_path); + RsyslogPlugin* plugin = new RsyslogPlugin(module_name, regex_path); + if(!plugin->onInit()) { + SWSS_LOG_ERROR("Rsyslog plugin was not able to be initialized.\n"); + return 1; + } plugin->run(); return 0; diff --git a/src/sonic-eventd/rsyslog_plugin/rsyslog_plugin.cpp b/src/sonic-eventd/rsyslog_plugin/rsyslog_plugin.cpp index 29293fd430f..b6e7b43b17b 100644 --- a/src/sonic-eventd/rsyslog_plugin/rsyslog_plugin.cpp +++ b/src/sonic-eventd/rsyslog_plugin/rsyslog_plugin.cpp @@ -6,74 +6,82 @@ #include "rsyslog_plugin.h" #include "common/logger.h" #include "common/json.hpp" -#include "common/events.h" using namespace std; using namespace swss; using json = nlohmann::json; -void RsyslogPlugin::onMessage(string msg) { - string tag = ""; +bool RsyslogPlugin::onMessage(string msg) { + string tag; event_params_t param_dict; - if(!parser->parseMessage(msg, tag, param_dict)) { - SWSS_LOG_INFO("%s was not able to be parsed into a structured event\n", msg.c_str()); + if(!m_parser->parseMessage(msg, tag, param_dict)) { + SWSS_LOG_DEBUG("%s was not able to be parsed into a structured event\n", msg.c_str()); + return false; } else { - int return_code = event_publish(fetchHandle(), tag, ¶m_dict); - if (return_code != 0) { - SWSS_LOG_INFO("rsyslog_plugin was not able to publish event for %s\n", tag.c_str()); - } - } -} - -[[noreturn]] void RsyslogPlugin::run() { - while(true) { - string line; - getline(cin, line); - if(line.empty()) { - continue; + int return_code = event_publish(m_event_handle, tag, ¶m_dict); + if (return_code != 0) { + SWSS_LOG_ERROR("rsyslog_plugin was not able to publish event for %s. last thrown event error: %d\n", tag.c_str(), event_last_error()); + return false; } - onMessage(line); + return true; } } bool RsyslogPlugin::createRegexList() { fstream regex_file; - regex_file.open(regex_path, ios::in); + regex_file.open(m_regex_path, ios::in); if (!regex_file) { - SWSS_LOG_ERROR("No such path exists: %s for source %s\n", regex_path.c_str(), module_name.c_str()); + SWSS_LOG_ERROR("No such path exists: %s for source %s\n", m_regex_path.c_str(), m_module_name.c_str()); return false; } try { - regex_file >> parser->regex_list; + regex_file >> m_parser->m_regex_list; } catch (exception& exception) { - SWSS_LOG_ERROR("Invalid JSON file: %s, throws exception: %s\n", regex_path.c_str(), exception.what()); + SWSS_LOG_ERROR("Invalid JSON file: %s, throws exception: %s\n", m_regex_path.c_str(), exception.what()); return false; } - string regex_string = ""; + string regex_string; regex expression; - for(long unsigned int i = 0; i < parser->regex_list.size(); i++) { + for(long unsigned int i = 0; i < m_parser->m_regex_list.size(); i++) { try { - regex_string = parser->regex_list[i]["regex"]; + regex_string = m_parser->m_regex_list[i]["regex"]; + string tag = m_parser->m_regex_list[i]["tag"]; + vector params = m_parser->m_regex_list[i]["params"]; regex expr(regex_string); expression = expr; } catch (exception& exception) { SWSS_LOG_ERROR("Invalid regex, throws exception: %s\n", exception.what()); return false; } - parser->expressions.push_back(expression); + m_parser->m_expressions.push_back(expression); } regex_file.close(); return true; } - -RsyslogPlugin::RsyslogPlugin(SyslogParser* syslog_parser, string mod_name, string path) { - parser = syslog_parser; - module_name = mod_name; - regex_path = path; - if(!onInit()) { - SWSS_LOG_ERROR("Initializing rsyslog plugin failed.\n"); +[[noreturn]] void RsyslogPlugin::run() { + while(true) { + string line; + getline(cin, line); + if(line.empty()) { + continue; + } + if(!onMessage(line)) { + SWSS_LOG_DEBUG("RsyslogPlugin was not able to parse or publish the log message: %s\n", line.c_str()); + } } } + +bool RsyslogPlugin::onInit() { + m_event_handle = events_init_publisher(m_module_name); + bool return_code = createRegexList(); + return (m_event_handle != NULL && return_code); +} + +RsyslogPlugin::RsyslogPlugin(string module_name, string regex_path) { + m_parser = new SyslogParser({}, json::array()); + m_module_name = module_name; + m_regex_path = regex_path; +} diff --git a/src/sonic-eventd/rsyslog_plugin/rsyslog_plugin.h b/src/sonic-eventd/rsyslog_plugin/rsyslog_plugin.h index 252083117b2..de387c3c068 100644 --- a/src/sonic-eventd/rsyslog_plugin/rsyslog_plugin.h +++ b/src/sonic-eventd/rsyslog_plugin/rsyslog_plugin.h @@ -18,25 +18,17 @@ using json = nlohmann::json; class RsyslogPlugin { public: - RsyslogPlugin(SyslogParser* syslog_parser, string mod_name, string path); - void onMessage(string msg); + bool onInit(); + bool onMessage(string msg); void run(); - bool createRegexList(); - event_handle_t fetchHandle() { - return event_handle; - } - SyslogParser* parser; + RsyslogPlugin(string module_name, string regex_path); private: - string regex_path; - string module_name; - event_handle_t event_handle; - - bool onInit() { - event_handle = events_init_publisher(module_name); - int return_code = createRegexList(); - return (event_handle != NULL && return_code == 0); - } + SyslogParser* m_parser; + event_handle_t m_event_handle; + string m_regex_path; + string m_module_name; + bool createRegexList(); }; #endif diff --git a/src/sonic-eventd/rsyslog_plugin/subdir.mk b/src/sonic-eventd/rsyslog_plugin/subdir.mk new file mode 100644 index 00000000000..e5af1085da4 --- /dev/null +++ b/src/sonic-eventd/rsyslog_plugin/subdir.mk @@ -0,0 +1,13 @@ +CC := g++ + +RSYSLOG-PLUGIN_TEST_OBJS += ./rsyslog_plugin/rsyslog_plugin.o ./rsyslog_plugin/syslog_parser.o +RSYSLOG-PLUGIN_OBJS += ./rsyslog_plugin/rsyslog_plugin.o ./rsyslog_plugin/syslog_parser.o ./rsyslog_plugin/main.o + +C_DEPS += ./rsyslog_plugin/rsyslog_plugin.d ./rsyslog_plugin/syslog_parser.d ./rsyslog_plugin/main.d + +rsyslog_plugin/%.o: rsyslog_plugin/%.cpp + @echo 'Building file: $<' + @echo 'Invoking: GCC C++ Compiler' + $(CC) -D__FILENAME__="$(subst rsyslog_plugin/,,$<)" $(CFLAGS) -c -fmessage-length=0 -MMD -MP -MF"$(@:%.o=%.d)" -MT"$(@)" -o "$(@)" "$<" + @echo 'Finished building: $< + '@echo ' ' diff --git a/src/sonic-eventd/rsyslog_plugin/syslog_parser.cpp b/src/sonic-eventd/rsyslog_plugin/syslog_parser.cpp index fa56aeff224..6d3ab8505ad 100644 --- a/src/sonic-eventd/rsyslog_plugin/syslog_parser.cpp +++ b/src/sonic-eventd/rsyslog_plugin/syslog_parser.cpp @@ -16,34 +16,23 @@ using namespace std; */ bool SyslogParser::parseMessage(string message, string& event_tag, event_params_t& param_map) { - for(long unsigned int i = 0; i < regex_list.size(); i++) { + for(long unsigned int i = 0; i < m_regex_list.size(); i++) { smatch match_results; - regex_search(message, match_results, expressions[i]); - vector groups; - vector params; - try { - event_tag = regex_list[i]["tag"]; - vector p = regex_list[i]["params"]; - params = p; - } catch (exception& exception) { - SWSS_LOG_ERROR("Invalid regex list, throws exception: %s\n", exception.what()); - return false; - } - // first match in groups is entire message - for(long unsigned int j = 1; j < match_results.size(); j++) { - groups.push_back(match_results.str(j)); - } - if (groups.size() == params.size()) { // found matching regex - transform(params.begin(), params.end(), groups.begin(), inserter(param_map, param_map.end()), [](string a, string b) { - return make_pair(a,b); - }); - return true; + vector params = m_regex_list[i]["params"]; + if(!regex_search(message, match_results, m_expressions[i]) || params.size() != match_results.size() - 1) { + continue; } + // found matching regex + event_tag = m_regex_list[i]["tag"]; + transform(params.begin(), params.end(), match_results.begin() + 1, inserter(param_map, param_map.end()), [](string a, string b) { + return make_pair(a,b); + }); + return true; } return false; } -SyslogParser::SyslogParser(vector regex_expressions, json list) { - expressions = regex_expressions; - regex_list = list; +SyslogParser::SyslogParser(vector expressions, json regex_list) { + m_expressions = expressions; + m_regex_list = regex_list; } diff --git a/src/sonic-eventd/rsyslog_plugin/syslog_parser.h b/src/sonic-eventd/rsyslog_plugin/syslog_parser.h index 5e970f84fa9..d6b39326b29 100644 --- a/src/sonic-eventd/rsyslog_plugin/syslog_parser.h +++ b/src/sonic-eventd/rsyslog_plugin/syslog_parser.h @@ -18,11 +18,11 @@ using json = nlohmann::json; class SyslogParser { public: - SyslogParser(vector regex_expressions, json list); - bool parseMessage(string message, string& tag, event_params_t& param_dict); + vector m_expressions; + json m_regex_list = json::array(); - vector expressions; - json regex_list = json::array(); + SyslogParser(vector expressions, json regex_list); + bool parseMessage(string message, string& tag, event_params_t& param_dict); }; #endif diff --git a/src/sonic-eventd/rsyslog_plugin_tests/rsyslog_plugin_ut.cpp b/src/sonic-eventd/rsyslog_plugin_tests/rsyslog_plugin_ut.cpp index 12f9a247acf..b40832b34fb 100644 --- a/src/sonic-eventd/rsyslog_plugin_tests/rsyslog_plugin_ut.cpp +++ b/src/sonic-eventd/rsyslog_plugin_tests/rsyslog_plugin_ut.cpp @@ -10,39 +10,19 @@ using namespace std; using json = nlohmann::json; -RsyslogPlugin* plugin = NULL; - -json j_list_1 = json::array(); -json j_list_2 = json::array(); -vector test_expressions_1; -vector test_expressions_2; - -void createTests() { - string regex_string_1 = "timestamp (.*) message (.*) other_data (.*)"; - string regex_string_2 = "no match"; - - json j_test_1; - j_test_1["tag"] = "test_tag_1"; - j_test_1["regex"] = regex_string_1; - j_test_1["params"] = { "timestamp", "message", "other_data" }; - j_list_1.push_back(j_test_1); - - json j_test_2; - j_test_2["tag"] = "test_tag_2"; - j_test_2["regex"] = regex_string_2; - j_test_2["params"] = {}; - j_list_2.push_back(j_test_2); - - regex expression_1(regex_string_1); - test_expressions_1.push_back(expression_1); - regex expression_2(regex_string_2); - test_expressions_2.push_back(expression_2); -} - - TEST(syslog_parser, matching_regex) { - createTests(); - string tag = ""; + json j_list = json::array(); + vector test_expressions; + string regex_string = "timestamp (.*) message (.*) other_data (.*)"; + json j_test; + j_test["tag"] = "test_tag"; + j_test["regex"] = regex_string; + j_test["params"] = { "timestamp", "message", "other_data" }; + j_list.push_back(j_test); + regex expression(regex_string); + test_expressions.push_back(expression); + + string tag; event_params_t param_dict; event_params_t expected_dict; @@ -50,72 +30,85 @@ TEST(syslog_parser, matching_regex) { expected_dict["message"] = "test_message"; expected_dict["other_data"] = "test_data"; - SyslogParser* parser = new SyslogParser(test_expressions_1, j_list_1); + SyslogParser* parser = new SyslogParser(test_expressions, j_list); bool success = parser->parseMessage("timestamp test_timestamp message test_message other_data test_data", tag, param_dict); EXPECT_EQ(true, success); - EXPECT_EQ("test_tag_1", tag); + EXPECT_EQ("test_tag", tag); EXPECT_EQ(expected_dict, param_dict); delete parser; } TEST(syslog_parser, no_matching_regex) { - string tag = ""; + json j_list = json::array(); + vector test_expressions; + string regex_string = "no match"; + json j_test; + j_test["tag"] = "test_tag"; + j_test["regex"] = regex_string; + j_test["params"] = vector(); + j_list.push_back(j_test); + regex expression(regex_string); + test_expressions.push_back(expression); + + string tag; event_params_t param_dict; - SyslogParser* parser = new SyslogParser(test_expressions_2, j_list_2); + SyslogParser* parser = new SyslogParser(test_expressions, j_list); bool success = parser->parseMessage("Test Message", tag, param_dict); EXPECT_EQ(false, success); delete parser; } -void createPlugin(string path) { - SyslogParser* testParser = new SyslogParser({}, json::array()); - plugin = new RsyslogPlugin(testParser, "test_mod_name", path); +RsyslogPlugin* createPlugin(string path) { + RsyslogPlugin* plugin = new RsyslogPlugin("test_mod_name", path); + return plugin; } -TEST(rsyslog_plugin, createRegexList_invalidJS0N) { - createPlugin("./test_regex_1.rc.json"); - if(plugin != NULL) { - EXPECT_EQ(false, plugin->createRegexList()); - } +TEST(rsyslog_plugin, onInit_invalidJS0N) { + auto plugin = createPlugin("./test_regex_1.rc.json"); + EXPECT_EQ(false, plugin->onInit()); delete plugin; } -TEST(rsyslog_plugin, createRegexList_missingRegex) { - createPlugin("./test_regex_3.rc.json"); - if(plugin != NULL) { - EXPECT_EQ(false, plugin->createRegexList()); - } +TEST(rsyslog_plugin, onInit_missingRegex) { + auto plugin = createPlugin("./test_regex_3.rc.json"); + EXPECT_EQ(false, plugin->onInit()); delete plugin; } -TEST(rsyslog_plugin, createRegexList_invalidRegex) { - createPlugin("./test_regex_4.rc.json"); - if(plugin != NULL) { - EXPECT_EQ(false, plugin->createRegexList()); +TEST(rsyslog_plugin, onInit_invalidRegex) { + auto plugin = createPlugin("./test_regex_4.rc.json"); + EXPECT_EQ(false, plugin->onInit()); + delete plugin; +} + +TEST(rsyslog_plugin, onMessage) { + auto plugin = createPlugin("./test_regex_2.rc.json"); + EXPECT_EQ(true, plugin->onInit()); + + ifstream infile("test_syslogs.txt"); + string log_message; + bool parse_result; + while(infile >> log_message >> parse_result) { + EXPECT_EQ(parse_result, plugin->onMessage(log_message)); } + infile.close(); delete plugin; } -TEST(rsyslog_plugin, createRegexList_validRegex) { - createPlugin("./test_regex_2.rc.json"); - if(plugin != NULL) { - auto parser = plugin->parser; - EXPECT_EQ(1, parser->regex_list.size()); - EXPECT_EQ(1, parser->expressions.size()); - - ifstream infile("test_syslogs.txt"); - string log_message; - bool parse_result; - - while(infile >> log_message >> parse_result) { - string tag = ""; - event_params_t param_dict; - EXPECT_EQ(parse_result, parser->parseMessage(log_message, tag, param_dict)); - } +TEST(rsyslog_plugin, onMessage_noParams) { + auto plugin = createPlugin("./test_regex_5.rc.json"); + EXPECT_EQ(true, plugin->onInit()); + + ifstream infile("test_syslogs_2.txt"); + string log_message; + bool parse_result; + while(infile >> log_message >> parse_result) { + EXPECT_EQ(parse_result, plugin->onMessage(log_message)); } + infile.close(); delete plugin; } diff --git a/src/sonic-eventd/rsyslog_plugin_tests/subdir.mk b/src/sonic-eventd/rsyslog_plugin_tests/subdir.mk new file mode 100644 index 00000000000..dd2e47364a2 --- /dev/null +++ b/src/sonic-eventd/rsyslog_plugin_tests/subdir.mk @@ -0,0 +1,12 @@ +CC := g++ + +RSYSLOG-PLUGIN_TEST_OBJS += ./rsyslog_plugin_tests/rsyslog_plugin_ut.o + +C_DEPS += ./rsyslog_plugin_tests/rsyslog_plugin_ut.d + +rsyslog_plugin_tests/%.o: rsyslog_plugin_tests/%.cpp + @echo 'Building file: $<' + @echo 'Invoking: GCC C++ Compiler' + $(CC) -D__FILENAME__="$(subst rsyslog_plugin_tests/,,$<)" $(CFLAGS) -c -fmessage-length=0 -MMD -MP -MF"$(@:%.o=%.d)" -MT"$(@)" -o "$(@)" "$<" + @echo 'Finished building: $< + '@echo ' ' diff --git a/src/sonic-eventd/rsyslog_plugin_tests/test_regex_5.rc.json b/src/sonic-eventd/rsyslog_plugin_tests/test_regex_5.rc.json new file mode 100644 index 00000000000..ddaf37c931a --- /dev/null +++ b/src/sonic-eventd/rsyslog_plugin_tests/test_regex_5.rc.json @@ -0,0 +1,7 @@ +[ + { + "tag": "test_tag", + "regex": ".*", + "params": [] + } +] diff --git a/src/sonic-eventd/rsyslog_plugin_tests/test_syslogs_2.txt b/src/sonic-eventd/rsyslog_plugin_tests/test_syslogs_2.txt new file mode 100644 index 00000000000..d56615f6168 --- /dev/null +++ b/src/sonic-eventd/rsyslog_plugin_tests/test_syslogs_2.txt @@ -0,0 +1,3 @@ +testMessage true +another_test_message true + true From b92bb297a00121e0807c2400855394ca61e6eb80 Mon Sep 17 00:00:00 2001 From: Ubuntu Date: Wed, 15 Jun 2022 21:02:20 +0000 Subject: [PATCH 5/8] Remove redundant headers, etc --- src/sonic-eventd/rsyslog_plugin/main.cpp | 3 --- src/sonic-eventd/rsyslog_plugin/rsyslog_plugin.cpp | 3 --- src/sonic-eventd/rsyslog_plugin/rsyslog_plugin.h | 5 ++--- src/sonic-eventd/rsyslog_plugin/syslog_parser.cpp | 5 ----- 4 files changed, 2 insertions(+), 14 deletions(-) diff --git a/src/sonic-eventd/rsyslog_plugin/main.cpp b/src/sonic-eventd/rsyslog_plugin/main.cpp index 033d45f4ad5..10821c98455 100644 --- a/src/sonic-eventd/rsyslog_plugin/main.cpp +++ b/src/sonic-eventd/rsyslog_plugin/main.cpp @@ -1,9 +1,6 @@ #include #include #include "rsyslog_plugin.h" -#include "syslog_parser.h" - -using namespace std; void showUsage() { cout << "Usage for rsyslog_plugin: \n" << "options\n" diff --git a/src/sonic-eventd/rsyslog_plugin/rsyslog_plugin.cpp b/src/sonic-eventd/rsyslog_plugin/rsyslog_plugin.cpp index b6e7b43b17b..c4e027960aa 100644 --- a/src/sonic-eventd/rsyslog_plugin/rsyslog_plugin.cpp +++ b/src/sonic-eventd/rsyslog_plugin/rsyslog_plugin.cpp @@ -4,11 +4,8 @@ #include #include #include "rsyslog_plugin.h" -#include "common/logger.h" #include "common/json.hpp" -using namespace std; -using namespace swss; using json = nlohmann::json; bool RsyslogPlugin::onMessage(string msg) { diff --git a/src/sonic-eventd/rsyslog_plugin/rsyslog_plugin.h b/src/sonic-eventd/rsyslog_plugin/rsyslog_plugin.h index de387c3c068..fea6cef63e1 100644 --- a/src/sonic-eventd/rsyslog_plugin/rsyslog_plugin.h +++ b/src/sonic-eventd/rsyslog_plugin/rsyslog_plugin.h @@ -2,13 +2,12 @@ #define RSYSLOG_PLUGIN_H #include -#include #include "syslog_parser.h" -#include "common/logger.h" #include "common/events.h" +#include "common/logger.h" using namespace std; -using json = nlohmann::json; +using namespace swss; /** * Rsyslog Plugin will utilize an instance of a syslog parser to read syslog messages from rsyslog.d and will continuously read from stdin diff --git a/src/sonic-eventd/rsyslog_plugin/syslog_parser.cpp b/src/sonic-eventd/rsyslog_plugin/syslog_parser.cpp index 6d3ab8505ad..e5b1dca78e5 100644 --- a/src/sonic-eventd/rsyslog_plugin/syslog_parser.cpp +++ b/src/sonic-eventd/rsyslog_plugin/syslog_parser.cpp @@ -1,12 +1,7 @@ #include -#include -#include -#include #include "syslog_parser.h" #include "common/logger.h" - -using namespace std; /** * Parses syslog message and returns structured event * From 4468e1197b83f255bf46dda7446582181abd5454 Mon Sep 17 00:00:00 2001 From: Ubuntu Date: Wed, 15 Jun 2022 21:26:25 +0000 Subject: [PATCH 6/8] Add logic for empty regex expressions --- src/sonic-eventd/rsyslog_plugin_tests/rsyslog_plugin_ut.cpp | 6 ++++++ src/sonic-eventd/rsyslog_plugin_tests/test_regex_6.rc.json | 0 2 files changed, 6 insertions(+) create mode 100644 src/sonic-eventd/rsyslog_plugin_tests/test_regex_6.rc.json diff --git a/src/sonic-eventd/rsyslog_plugin_tests/rsyslog_plugin_ut.cpp b/src/sonic-eventd/rsyslog_plugin_tests/rsyslog_plugin_ut.cpp index b40832b34fb..2a8f41e7c84 100644 --- a/src/sonic-eventd/rsyslog_plugin_tests/rsyslog_plugin_ut.cpp +++ b/src/sonic-eventd/rsyslog_plugin_tests/rsyslog_plugin_ut.cpp @@ -72,6 +72,12 @@ TEST(rsyslog_plugin, onInit_invalidJS0N) { delete plugin; } +TEST(rsyslog_plugin, onInit_emptyJSON) { + auto plugin = createPlugin("./test_regex_6.rc.json"); + EXPECT_EQ(false, plugin->onInit()); + delete plugin; +} + TEST(rsyslog_plugin, onInit_missingRegex) { auto plugin = createPlugin("./test_regex_3.rc.json"); EXPECT_EQ(false, plugin->onInit()); diff --git a/src/sonic-eventd/rsyslog_plugin_tests/test_regex_6.rc.json b/src/sonic-eventd/rsyslog_plugin_tests/test_regex_6.rc.json new file mode 100644 index 00000000000..e69de29bb2d From 0eec6615673aee323d2e370281358c350b355709 Mon Sep 17 00:00:00 2001 From: Ubuntu Date: Thu, 16 Jun 2022 00:31:47 +0000 Subject: [PATCH 7/8] Remove redundant syslog messages --- src/sonic-eventd/rsyslog_plugin/rsyslog_plugin.cpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/sonic-eventd/rsyslog_plugin/rsyslog_plugin.cpp b/src/sonic-eventd/rsyslog_plugin/rsyslog_plugin.cpp index c4e027960aa..1ad52fb8382 100644 --- a/src/sonic-eventd/rsyslog_plugin/rsyslog_plugin.cpp +++ b/src/sonic-eventd/rsyslog_plugin/rsyslog_plugin.cpp @@ -54,6 +54,10 @@ bool RsyslogPlugin::createRegexList() { } m_parser->m_expressions.push_back(expression); } + if(m_parser->m_expressions.empty()) { + SWSS_LOG_ERROR("Empty list of regex expressions.\n"); + return false; + } regex_file.close(); return true; } @@ -65,9 +69,7 @@ bool RsyslogPlugin::createRegexList() { if(line.empty()) { continue; } - if(!onMessage(line)) { - SWSS_LOG_DEBUG("RsyslogPlugin was not able to parse or publish the log message: %s\n", line.c_str()); - } + onMessage(line); } } From 5916a5a7e8e43a987e43bc604a4151b1d5ccdcce Mon Sep 17 00:00:00 2001 From: Ubuntu Date: Mon, 20 Jun 2022 20:40:09 +0000 Subject: [PATCH 8/8] Resolve PR comments --- src/sonic-eventd/rsyslog_plugin/main.cpp | 42 ++++---- .../rsyslog_plugin/rsyslog_plugin.cpp | 73 +++++++------- .../rsyslog_plugin/rsyslog_plugin.h | 14 +-- .../rsyslog_plugin/syslog_parser.cpp | 29 +++--- .../rsyslog_plugin/syslog_parser.h | 6 +- .../rsyslog_plugin_ut.cpp | 96 ++++++++++--------- 6 files changed, 138 insertions(+), 122 deletions(-) diff --git a/src/sonic-eventd/rsyslog_plugin/main.cpp b/src/sonic-eventd/rsyslog_plugin/main.cpp index 10821c98455..53162608c5a 100644 --- a/src/sonic-eventd/rsyslog_plugin/main.cpp +++ b/src/sonic-eventd/rsyslog_plugin/main.cpp @@ -1,7 +1,13 @@ #include +#include #include #include "rsyslog_plugin.h" +#define SUCCESS_CODE 0 +#define INVALID_REGEX_ERROR_CODE 1 +#define EVENT_INIT_PUBLISH_ERROR_CODE 2 +#define MISSING_ARGS_ERROR_CODE 3 + void showUsage() { cout << "Usage for rsyslog_plugin: \n" << "options\n" << "\t-r,required,type=string\t\tPath to regex file\n" @@ -11,17 +17,17 @@ void showUsage() { } int main(int argc, char** argv) { - string regex_path; - string module_name; - int option_val; + string regexPath; + string moduleName; + int optionVal; - while((option_val = getopt(argc, argv, "r:m:h")) != -1) { - switch(option_val) { + while((optionVal = getopt(argc, argv, "r:m:h")) != -1) { + switch(optionVal) { case 'r': - regex_path = optarg; + regexPath = optarg; break; case 'm': - module_name = optarg; + moduleName = optarg; break; case 'h': case '?': @@ -31,17 +37,21 @@ int main(int argc, char** argv) { } } - if(regex_path.empty() || module_name.empty()) { // Missing required rc path - cerr << "Error: Missing regex_path and module_name." << endl; - return 1; + if(regexPath.empty() || moduleName.empty()) { // Missing required rc path + cerr << "Error: Missing regexPath and moduleName." << endl; + return MISSING_ARGS_ERROR_CODE; } - - RsyslogPlugin* plugin = new RsyslogPlugin(module_name, regex_path); - if(!plugin->onInit()) { - SWSS_LOG_ERROR("Rsyslog plugin was not able to be initialized.\n"); - return 1; + + unique_ptr plugin(new RsyslogPlugin(moduleName, regexPath)); + int returnCode = plugin->onInit(); + if(returnCode == INVALID_REGEX_ERROR_CODE) { + SWSS_LOG_ERROR("Rsyslog plugin was not able to be initialized due to invalid regex file provided.\n"); + return returnCode; + } else if(returnCode == EVENT_INIT_PUBLISH_ERROR_CODE) { + SWSS_LOG_ERROR("Rsyslog plugin was not able to be initialized due to event_init_publish call failing.\n"); + return returnCode; } plugin->run(); - return 0; + return SUCCESS_CODE; } diff --git a/src/sonic-eventd/rsyslog_plugin/rsyslog_plugin.cpp b/src/sonic-eventd/rsyslog_plugin/rsyslog_plugin.cpp index 1ad52fb8382..ca50f465a79 100644 --- a/src/sonic-eventd/rsyslog_plugin/rsyslog_plugin.cpp +++ b/src/sonic-eventd/rsyslog_plugin/rsyslog_plugin.cpp @@ -1,4 +1,3 @@ -#include #include #include #include @@ -10,55 +9,58 @@ using json = nlohmann::json; bool RsyslogPlugin::onMessage(string msg) { string tag; - event_params_t param_dict; - if(!m_parser->parseMessage(msg, tag, param_dict)) { + event_params_t paramDict; + if(!m_parser->parseMessage(msg, tag, paramDict)) { SWSS_LOG_DEBUG("%s was not able to be parsed into a structured event\n", msg.c_str()); - return false; + return false; } else { - int return_code = event_publish(m_event_handle, tag, ¶m_dict); - if (return_code != 0) { + int returnCode = event_publish(m_eventHandle, tag, ¶mDict); + if (returnCode != 0) { SWSS_LOG_ERROR("rsyslog_plugin was not able to publish event for %s. last thrown event error: %d\n", tag.c_str(), event_last_error()); - return false; + return false; } - return true; + return true; } } bool RsyslogPlugin::createRegexList() { - fstream regex_file; - regex_file.open(m_regex_path, ios::in); - if (!regex_file) { - SWSS_LOG_ERROR("No such path exists: %s for source %s\n", m_regex_path.c_str(), m_module_name.c_str()); + fstream regexFile; + regexFile.open(m_regexPath, ios::in); + if (!regexFile) { + SWSS_LOG_ERROR("No such path exists: %s for source %s\n", m_regexPath.c_str(), m_moduleName.c_str()); return false; } try { - regex_file >> m_parser->m_regex_list; - } catch (exception& exception) { - SWSS_LOG_ERROR("Invalid JSON file: %s, throws exception: %s\n", m_regex_path.c_str(), exception.what()); + regexFile >> m_parser->m_regexList; + } catch (invalid_argument& iaException) { + SWSS_LOG_ERROR("Invalid JSON file: %s, throws exception: %s\n", m_regexPath.c_str(), iaException.what()); return false; } - string regex_string; + string regexString; regex expression; - for(long unsigned int i = 0; i < m_parser->m_regex_list.size(); i++) { + for(long unsigned int i = 0; i < m_parser->m_regexList.size(); i++) { try { - regex_string = m_parser->m_regex_list[i]["regex"]; - string tag = m_parser->m_regex_list[i]["tag"]; - vector params = m_parser->m_regex_list[i]["params"]; - regex expr(regex_string); + regexString = m_parser->m_regexList[i]["regex"]; + string tag = m_parser->m_regexList[i]["tag"]; + vector params = m_parser->m_regexList[i]["params"]; + regex expr(regexString); expression = expr; - } catch (exception& exception) { - SWSS_LOG_ERROR("Invalid regex, throws exception: %s\n", exception.what()); + } catch (domain_error& deException) { + SWSS_LOG_ERROR("Missing required key, throws exception: %s\n", deException.what()); return false; - } + } catch (regex_error& reException) { + SWSS_LOG_ERROR("Invalid regex, throws exception: %s\n", reException.what()); + return false; + } m_parser->m_expressions.push_back(expression); } if(m_parser->m_expressions.empty()) { SWSS_LOG_ERROR("Empty list of regex expressions.\n"); return false; } - regex_file.close(); + regexFile.close(); return true; } @@ -73,14 +75,19 @@ bool RsyslogPlugin::createRegexList() { } } -bool RsyslogPlugin::onInit() { - m_event_handle = events_init_publisher(m_module_name); - bool return_code = createRegexList(); - return (m_event_handle != NULL && return_code); +int RsyslogPlugin::onInit() { + m_eventHandle = events_init_publisher(m_moduleName); + bool success = createRegexList(); + if(!success) { + return 1; // invalid regex error code + } else if(m_eventHandle == NULL) { + return 2; // event init publish error code + } + return 0; } -RsyslogPlugin::RsyslogPlugin(string module_name, string regex_path) { - m_parser = new SyslogParser({}, json::array()); - m_module_name = module_name; - m_regex_path = regex_path; +RsyslogPlugin::RsyslogPlugin(string moduleName, string regexPath) { + m_parser = unique_ptr(new SyslogParser()); + m_moduleName = moduleName; + m_regexPath = regexPath; } diff --git a/src/sonic-eventd/rsyslog_plugin/rsyslog_plugin.h b/src/sonic-eventd/rsyslog_plugin/rsyslog_plugin.h index fea6cef63e1..e5c5b13fca7 100644 --- a/src/sonic-eventd/rsyslog_plugin/rsyslog_plugin.h +++ b/src/sonic-eventd/rsyslog_plugin/rsyslog_plugin.h @@ -2,6 +2,7 @@ #define RSYSLOG_PLUGIN_H #include +#include #include "syslog_parser.h" #include "common/events.h" #include "common/logger.h" @@ -17,16 +18,15 @@ using namespace swss; class RsyslogPlugin { public: - bool onInit(); + int onInit(); bool onMessage(string msg); void run(); - RsyslogPlugin(string module_name, string regex_path); + RsyslogPlugin(string moduleName, string regexPath); private: - SyslogParser* m_parser; - event_handle_t m_event_handle; - string m_regex_path; - string m_module_name; - + unique_ptr m_parser; + event_handle_t m_eventHandle; + string m_regexPath; + string m_moduleName; bool createRegexList(); }; diff --git a/src/sonic-eventd/rsyslog_plugin/syslog_parser.cpp b/src/sonic-eventd/rsyslog_plugin/syslog_parser.cpp index e5b1dca78e5..a025cc02953 100644 --- a/src/sonic-eventd/rsyslog_plugin/syslog_parser.cpp +++ b/src/sonic-eventd/rsyslog_plugin/syslog_parser.cpp @@ -10,24 +10,19 @@ * */ -bool SyslogParser::parseMessage(string message, string& event_tag, event_params_t& param_map) { - for(long unsigned int i = 0; i < m_regex_list.size(); i++) { - smatch match_results; - vector params = m_regex_list[i]["params"]; - if(!regex_search(message, match_results, m_expressions[i]) || params.size() != match_results.size() - 1) { +bool SyslogParser::parseMessage(string message, string& eventTag, event_params_t& paramMap) { + for(long unsigned int i = 0; i < m_regexList.size(); i++) { + smatch matchResults; + vector params = m_regexList[i]["params"]; + if(!regex_search(message, matchResults, m_expressions[i]) || params.size() != matchResults.size() - 1) { continue; - } - // found matching regex - event_tag = m_regex_list[i]["tag"]; - transform(params.begin(), params.end(), match_results.begin() + 1, inserter(param_map, param_map.end()), [](string a, string b) { - return make_pair(a,b); - }); - return true; + } + // found matching regex + eventTag = m_regexList[i]["tag"]; + transform(params.begin(), params.end(), matchResults.begin() + 1, inserter(paramMap, paramMap.end()), [](string a, string b) { + return make_pair(a,b); + }); + return true; } return false; } - -SyslogParser::SyslogParser(vector expressions, json regex_list) { - m_expressions = expressions; - m_regex_list = regex_list; -} diff --git a/src/sonic-eventd/rsyslog_plugin/syslog_parser.h b/src/sonic-eventd/rsyslog_plugin/syslog_parser.h index d6b39326b29..53128f1edf9 100644 --- a/src/sonic-eventd/rsyslog_plugin/syslog_parser.h +++ b/src/sonic-eventd/rsyslog_plugin/syslog_parser.h @@ -19,10 +19,8 @@ using json = nlohmann::json; class SyslogParser { public: vector m_expressions; - json m_regex_list = json::array(); - - SyslogParser(vector expressions, json regex_list); - bool parseMessage(string message, string& tag, event_params_t& param_dict); + json m_regexList = json::array(); + bool parseMessage(string message, string& tag, event_params_t& paramDict); }; #endif diff --git a/src/sonic-eventd/rsyslog_plugin_tests/rsyslog_plugin_ut.cpp b/src/sonic-eventd/rsyslog_plugin_tests/rsyslog_plugin_ut.cpp index 2a8f41e7c84..5893c70f66c 100644 --- a/src/sonic-eventd/rsyslog_plugin_tests/rsyslog_plugin_ut.cpp +++ b/src/sonic-eventd/rsyslog_plugin_tests/rsyslog_plugin_ut.cpp @@ -11,51 +11,57 @@ using namespace std; using json = nlohmann::json; TEST(syslog_parser, matching_regex) { - json j_list = json::array(); - vector test_expressions; - string regex_string = "timestamp (.*) message (.*) other_data (.*)"; - json j_test; - j_test["tag"] = "test_tag"; - j_test["regex"] = regex_string; - j_test["params"] = { "timestamp", "message", "other_data" }; - j_list.push_back(j_test); - regex expression(regex_string); - test_expressions.push_back(expression); + json jList = json::array(); + vector testExpressions; + string regexString = "timestamp (.*) message (.*) other_data (.*)"; + json jTest; + jTest["tag"] = "test_tag"; + jTest["regex"] = regexString; + jTest["params"] = { "timestamp", "message", "other_data" }; + jList.push_back(jTest); + regex expression(regexString); + testExpressions.push_back(expression); string tag; - event_params_t param_dict; + event_params_t paramDict; - event_params_t expected_dict; - expected_dict["timestamp"] = "test_timestamp"; - expected_dict["message"] = "test_message"; - expected_dict["other_data"] = "test_data"; + event_params_t expectedDict; + expectedDict["timestamp"] = "test_timestamp"; + expectedDict["message"] = "test_message"; + expectedDict["other_data"] = "test_data"; - SyslogParser* parser = new SyslogParser(test_expressions, j_list); + SyslogParser* parser = new SyslogParser(); + parser->m_expressions = testExpressions; + parser->m_regexList = jList; - bool success = parser->parseMessage("timestamp test_timestamp message test_message other_data test_data", tag, param_dict); + bool success = parser->parseMessage("timestamp test_timestamp message test_message other_data test_data", tag, paramDict); EXPECT_EQ(true, success); EXPECT_EQ("test_tag", tag); - EXPECT_EQ(expected_dict, param_dict); + EXPECT_EQ(expectedDict, paramDict); delete parser; } TEST(syslog_parser, no_matching_regex) { - json j_list = json::array(); - vector test_expressions; - string regex_string = "no match"; - json j_test; - j_test["tag"] = "test_tag"; - j_test["regex"] = regex_string; - j_test["params"] = vector(); - j_list.push_back(j_test); - regex expression(regex_string); - test_expressions.push_back(expression); + json jList = json::array(); + vector testExpressions; + string regexString = "no match"; + json jTest; + jTest["tag"] = "test_tag"; + jTest["regex"] = regexString; + jTest["params"] = vector(); + jList.push_back(jTest); + regex expression(regexString); + testExpressions.push_back(expression); string tag; - event_params_t param_dict; - SyslogParser* parser = new SyslogParser(test_expressions, j_list); - bool success = parser->parseMessage("Test Message", tag, param_dict); + event_params_t paramDict; + + SyslogParser* parser = new SyslogParser(); + parser->m_expressions = testExpressions; + parser->m_regexList = jList; + + bool success = parser->parseMessage("Test Message", tag, paramDict); EXPECT_EQ(false, success); delete parser; } @@ -68,37 +74,37 @@ RsyslogPlugin* createPlugin(string path) { TEST(rsyslog_plugin, onInit_invalidJS0N) { auto plugin = createPlugin("./test_regex_1.rc.json"); - EXPECT_EQ(false, plugin->onInit()); + EXPECT_NE(0, plugin->onInit()); delete plugin; } TEST(rsyslog_plugin, onInit_emptyJSON) { auto plugin = createPlugin("./test_regex_6.rc.json"); - EXPECT_EQ(false, plugin->onInit()); + EXPECT_NE(0, plugin->onInit()); delete plugin; } TEST(rsyslog_plugin, onInit_missingRegex) { auto plugin = createPlugin("./test_regex_3.rc.json"); - EXPECT_EQ(false, plugin->onInit()); + EXPECT_NE(0, plugin->onInit()); delete plugin; } TEST(rsyslog_plugin, onInit_invalidRegex) { auto plugin = createPlugin("./test_regex_4.rc.json"); - EXPECT_EQ(false, plugin->onInit()); + EXPECT_NE(0, plugin->onInit()); delete plugin; } TEST(rsyslog_plugin, onMessage) { auto plugin = createPlugin("./test_regex_2.rc.json"); - EXPECT_EQ(true, plugin->onInit()); + EXPECT_EQ(0, plugin->onInit()); ifstream infile("test_syslogs.txt"); - string log_message; - bool parse_result; - while(infile >> log_message >> parse_result) { - EXPECT_EQ(parse_result, plugin->onMessage(log_message)); + string logMessage; + bool parseResult; + while(infile >> logMessage >> parseResult) { + EXPECT_EQ(parseResult, plugin->onMessage(logMessage)); } infile.close(); delete plugin; @@ -106,13 +112,13 @@ TEST(rsyslog_plugin, onMessage) { TEST(rsyslog_plugin, onMessage_noParams) { auto plugin = createPlugin("./test_regex_5.rc.json"); - EXPECT_EQ(true, plugin->onInit()); + EXPECT_EQ(0, plugin->onInit()); ifstream infile("test_syslogs_2.txt"); - string log_message; - bool parse_result; - while(infile >> log_message >> parse_result) { - EXPECT_EQ(parse_result, plugin->onMessage(log_message)); + string logMessage; + bool parseResult; + while(infile >> logMessage >> parseResult) { + EXPECT_EQ(parseResult, plugin->onMessage(logMessage)); } infile.close(); delete plugin;