-
Notifications
You must be signed in to change notification settings - Fork 1.5k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Ubuntu
committed
Jun 14, 2022
1 parent
091ced5
commit 999a175
Showing
11 changed files
with
396 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,49 @@ | ||
#include <iostream> | ||
#include <unistd.h> | ||
#include "rsyslog_plugin.h" | ||
#include "syslog_parser.h" | ||
|
||
using namespace std; | ||
|
||
void showUsage() { | ||
cerr << "Usage for rsyslog_plugin: " << " <option(s)> 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; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,77 @@ | ||
#include <ios> | ||
#include <iostream> | ||
#include <vector> | ||
#include <fstream> | ||
#include <regex> | ||
#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(); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,43 @@ | ||
#ifndef RSYSLOG_PLUGIN_H | ||
#define RSYSLOG_PLUGIN_H | ||
|
||
#include <string> | ||
#include <fstream> | ||
#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 | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,49 @@ | ||
#include <iostream> | ||
#include <ios> | ||
#include <fstream> | ||
#include <regex> | ||
#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<string> groups; | ||
vector<string> params; | ||
try { | ||
event_tag = regex_list[i]["tag"]; | ||
vector<string> 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> regex_expressions, json list) { | ||
expressions = regex_expressions; | ||
regex_list = list; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
#ifndef SYSLOG_PARSER_H | ||
#define SYSLOG_PARSER_H | ||
|
||
#include <vector> | ||
#include <string> | ||
#include <regex> | ||
#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> regex_expressions, json list); | ||
bool parseMessage(string message, string& tag, event_params_t& param_dict); | ||
|
||
vector<regex> expressions; | ||
json regex_list = json::array(); | ||
}; | ||
|
||
#endif |
125 changes: 125 additions & 0 deletions
125
src/sonic-eventd/rsyslog_plugin_tests/rsyslog_plugin_ut.cpp
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,125 @@ | ||
#include <iostream> | ||
#include <fstream> | ||
#include <regex> | ||
#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<regex> test_expressions_1; | ||
vector<regex> 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(); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
* |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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" ] | ||
} | ||
] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
[ | ||
{ | ||
"tag": "TEST-TAG-NO-REGEX", | ||
"param": [] | ||
} | ||
] |
Oops, something went wrong.