-
Notifications
You must be signed in to change notification settings - Fork 0
Add rsyslog plugin and tests #2
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 7 commits
999a175
3082cf8
ee28577
7cb88d7
b92bb29
4468e11
0eec661
5916a5a
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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 | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,47 @@ | ||
| #include <iostream> | ||
| #include <unistd.h> | ||
| #include "rsyslog_plugin.h" | ||
|
|
||
| void showUsage() { | ||
| 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; | ||
| } | ||
|
|
||
| int main(int argc, char** argv) { | ||
| string regex_path; | ||
| string module_name; | ||
| int option_val; | ||
|
|
||
| while((option_val = getopt(argc, argv, "r:m:h")) != -1) { | ||
| switch(option_val) { | ||
| case 'r': | ||
| regex_path = optarg; | ||
| break; | ||
| case 'm': | ||
| module_name = optarg; | ||
| break; | ||
| case 'h': | ||
| case '?': | ||
| default: | ||
| showUsage(); | ||
| return 1; | ||
| } | ||
| } | ||
|
|
||
| if(regex_path.empty() || module_name.empty()) { // Missing required rc path | ||
| cerr << "Error: Missing regex_path and module_name." << endl; | ||
| return 1; | ||
|
||
| } | ||
|
|
||
| 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(); | ||
renukamanavalan marked this conversation as resolved.
Show resolved
Hide resolved
zbud-msft marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| return 0; | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,86 @@ | ||
| #include <ios> | ||
| #include <iostream> | ||
| #include <vector> | ||
| #include <fstream> | ||
| #include <regex> | ||
| #include "rsyslog_plugin.h" | ||
| #include "common/json.hpp" | ||
|
|
||
| using json = nlohmann::json; | ||
|
|
||
| bool RsyslogPlugin::onMessage(string msg) { | ||
| string tag; | ||
| event_params_t param_dict; | ||
| 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(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; | ||
| } | ||
| 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()); | ||
| 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()); | ||
| return false; | ||
| } | ||
|
|
||
| string regex_string; | ||
| regex expression; | ||
|
|
||
| for(long unsigned int i = 0; i < m_parser->m_regex_list.size(); i++) { | ||
| try { | ||
| regex_string = m_parser->m_regex_list[i]["regex"]; | ||
| string tag = m_parser->m_regex_list[i]["tag"]; | ||
| vector<string> 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; | ||
| } | ||
| 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; | ||
zbud-msft marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| } | ||
|
|
||
| [[noreturn]] void RsyslogPlugin::run() { | ||
| while(true) { | ||
| string line; | ||
| getline(cin, line); | ||
| if(line.empty()) { | ||
| continue; | ||
| } | ||
| onMessage(line); | ||
| } | ||
| } | ||
|
|
||
| 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; | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,34 @@ | ||
| #ifndef RSYSLOG_PLUGIN_H | ||
| #define RSYSLOG_PLUGIN_H | ||
|
|
||
| #include <string> | ||
| #include "syslog_parser.h" | ||
| #include "common/events.h" | ||
| #include "common/logger.h" | ||
|
|
||
| using namespace std; | ||
| 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 | ||
| * A plugin instance is created for each container/host. | ||
| * | ||
| */ | ||
|
|
||
| class RsyslogPlugin { | ||
| public: | ||
| bool onInit(); | ||
| bool onMessage(string msg); | ||
| void run(); | ||
| RsyslogPlugin(string module_name, string regex_path); | ||
| private: | ||
| SyslogParser* m_parser; | ||
|
||
| event_handle_t m_event_handle; | ||
| string m_regex_path; | ||
| string m_module_name; | ||
|
|
||
| bool createRegexList(); | ||
| }; | ||
|
|
||
| #endif | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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 ' ' |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,33 @@ | ||
| #include <iostream> | ||
| #include "syslog_parser.h" | ||
| #include "common/logger.h" | ||
|
|
||
| /** | ||
| * 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 < m_regex_list.size(); i++) { | ||
| smatch match_results; | ||
| vector<string> 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 regex_list) { | ||
|
||
| m_expressions = expressions; | ||
| m_regex_list = regex_list; | ||
| } | ||
| 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: | ||
| vector<regex> m_expressions; | ||
| json m_regex_list = json::array(); | ||
|
||
|
|
||
| SyslogParser(vector<regex> expressions, json regex_list); | ||
| bool parseMessage(string message, string& tag, event_params_t& param_dict); | ||
| }; | ||
|
|
||
| #endif | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The other components in this repo is using Debian package build infra, not plain Makefile. Could you adapt?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is using debian package -- pretty similar to dhcp-relay