Skip to content

Commit

Permalink
Merge branch 'zbud-msft' into syslog_telemetry_shared
Browse files Browse the repository at this point in the history
  • Loading branch information
zbud-msft authored Jun 27, 2022
2 parents 1700020 + 5916a5a commit b80b884
Show file tree
Hide file tree
Showing 17 changed files with 451 additions and 4 deletions.
27 changes: 23 additions & 4 deletions src/sonic-eventd/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ 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++
Expand All @@ -21,8 +23,10 @@ endif
-include src/subdir.mk
-include tests/subdir.mk
-include tools/subdir.mk

all: sonic-eventd eventd-tests eventd-tool
-include rsyslog_plugin/subdir.mk
-include rsyslog_plugin_tests/subdir.mk

all: sonic-eventd eventd-tests eventd-tool rsyslog-plugin rsyslog-plugin-tests

sonic-eventd: $(OBJS)
@echo 'Building target: $@'
Expand All @@ -38,6 +42,13 @@ eventd-tool: $(TOOL_OBJS)
@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'
Expand All @@ -47,18 +58,26 @@ eventd-tests: $(TEST_OBJS)
@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

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


57 changes: 57 additions & 0 deletions src/sonic-eventd/rsyslog_plugin/main.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
#include <iostream>
#include <memory>
#include <unistd.h>
#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"
<< "\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 regexPath;
string moduleName;
int optionVal;

while((optionVal = getopt(argc, argv, "r:m:h")) != -1) {
switch(optionVal) {
case 'r':
regexPath = optarg;
break;
case 'm':
moduleName = optarg;
break;
case 'h':
case '?':
default:
showUsage();
return 1;
}
}

if(regexPath.empty() || moduleName.empty()) { // Missing required rc path
cerr << "Error: Missing regexPath and moduleName." << endl;
return MISSING_ARGS_ERROR_CODE;
}

unique_ptr<RsyslogPlugin> 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 SUCCESS_CODE;
}
93 changes: 93 additions & 0 deletions src/sonic-eventd/rsyslog_plugin/rsyslog_plugin.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
#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 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;
} else {
int returnCode = event_publish(m_eventHandle, tag, &paramDict);
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 true;
}
}

bool RsyslogPlugin::createRegexList() {
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 {
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 regexString;
regex expression;

for(long unsigned int i = 0; i < m_parser->m_regexList.size(); i++) {
try {
regexString = m_parser->m_regexList[i]["regex"];
string tag = m_parser->m_regexList[i]["tag"];
vector<string> params = m_parser->m_regexList[i]["params"];
regex expr(regexString);
expression = expr;
} 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;
}
regexFile.close();
return true;
}

[[noreturn]] void RsyslogPlugin::run() {
while(true) {
string line;
getline(cin, line);
if(line.empty()) {
continue;
}
onMessage(line);
}
}

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 moduleName, string regexPath) {
m_parser = unique_ptr<SyslogParser>(new SyslogParser());
m_moduleName = moduleName;
m_regexPath = regexPath;
}
34 changes: 34 additions & 0 deletions src/sonic-eventd/rsyslog_plugin/rsyslog_plugin.h
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 <memory>
#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:
int onInit();
bool onMessage(string msg);
void run();
RsyslogPlugin(string moduleName, string regexPath);
private:
unique_ptr<SyslogParser> m_parser;
event_handle_t m_eventHandle;
string m_regexPath;
string m_moduleName;
bool createRegexList();
};

#endif

13 changes: 13 additions & 0 deletions src/sonic-eventd/rsyslog_plugin/subdir.mk
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 ' '
28 changes: 28 additions & 0 deletions src/sonic-eventd/rsyslog_plugin/syslog_parser.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
#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& eventTag, event_params_t& paramMap) {
for(long unsigned int i = 0; i < m_regexList.size(); i++) {
smatch matchResults;
vector<string> params = m_regexList[i]["params"];
if(!regex_search(message, matchResults, m_expressions[i]) || params.size() != matchResults.size() - 1) {
continue;
}
// 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;
}
26 changes: 26 additions & 0 deletions src/sonic-eventd/rsyslog_plugin/syslog_parser.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
#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_regexList = json::array();
bool parseMessage(string message, string& tag, event_params_t& paramDict);
};

#endif
Loading

0 comments on commit b80b884

Please sign in to comment.