Skip to content

[VOQ][saidump] Enhance saidump with new option -r to parser the JSON file and displays/format the right output #1288

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

Merged
merged 17 commits into from
Sep 25, 2023
187 changes: 184 additions & 3 deletions saidump/saidump.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@
#include <string>
#include <set>
#include <sstream>
#include <iostream>
#include <fstream>
#include <regex>

extern "C" {
#include <sai.h>
Expand All @@ -10,18 +13,26 @@ extern "C" {
#include "swss/table.h"
#include "meta/sai_serialize.h"
#include "sairediscommon.h"
#include "swss/json.h"
#include "swss/json.hpp"

#include <getopt.h>

// TODO split to multiple cpp

using namespace swss;
using namespace std;
using json = nlohmann::json;

// 100 MB
const int64_t RDB_FILE_MAX_SIZE = 1024 * 1024 * 100;

struct CmdOptions
{
bool skipAttributes;
bool dumpTempView;
bool dumpGraph;
string rdb_file;
};

CmdOptions g_cmdOptions;
Expand All @@ -31,11 +42,13 @@ void printUsage()
{
SWSS_LOG_ENTER();

std::cout << "Usage: saidump [-t] [-g] [-h]" << std::endl;
std::cout << "Usage: saidump [-t] [-g] [-r] [-h]" << std::endl;
std::cout << " -t --tempView:" << std::endl;
std::cout << " Dump temp view" << std::endl;
std::cout << " -g --dumpGraph:" << std::endl;
std::cout << " Dump current graph" << std::endl;
std::cout << " -r --rdb:" << std::endl;
std::cout << " Dump by parsing the Redis persistence file dump.rdb that is generated by SAVE command." << std::endl;
std::cout << " -h --help:" << std::endl;
std::cout << " Print out this message" << std::endl;
}
Expand All @@ -49,14 +62,15 @@ CmdOptions handleCmdLine(int argc, char **argv)
options.dumpTempView = false;
options.dumpGraph = false;

const char* const optstring = "gth";
const char* const optstring = "gtr:h";

while (true)
{
static struct option long_options[] =
{
{ "dumpGraph", no_argument, 0, 'g' },
{ "tempView", no_argument, 0, 't' },
{ "rdb", required_argument, 0, 'r' },
{ "help", no_argument, 0, 'h' },
{ 0, 0, 0, 0 }
};
Expand All @@ -82,6 +96,11 @@ CmdOptions handleCmdLine(int argc, char **argv)
options.dumpTempView = true;
break;

case 'r':
SWSS_LOG_WARN("Dumping from dump.rdb");
options.rdb_file = string(optarg);
break;

case 'h':
printUsage();
exit(EXIT_SUCCESS);
Expand Down Expand Up @@ -399,7 +418,159 @@ void dumpGraph(const TableDump& td)
std::cout << "}" << std::endl;
}

int main(int argc, char ** argv)
/*
preprocess the input json file to make sure it's a valid json file.
*/
int pre_process_file(string file_name)
{
ifstream input_file(file_name);

if (!input_file.is_open())
{
cerr << "Failed to open the input file." << endl;
return SAI_STATUS_FAILURE;
}

input_file.seekg(0, ios::end); // Move to the end of the file
int64_t file_size = input_file.tellg(); // Get the current position

if (file_size >= RDB_FILE_MAX_SIZE)
{
SWSS_LOG_ERROR("Get %s's size failure or its size %ld >= %ld MB.\n", file_name.c_str(), file_size, RDB_FILE_MAX_SIZE / 1024 / 1024);

// Close the input file
input_file.close();
return SAI_STATUS_FAILURE;
}
input_file.seekg(0, ios::beg); // Move to the begin of the file

// Read the content of the input file into a string
string content((istreambuf_iterator<char>(input_file)),
istreambuf_iterator<char>());


input_file.close();

content = regex_replace(content, regex("\\},\\{\\r"), ",");

//erase the 1st and last char.
if (content.length() >= 2 && content[0] == '[' && content[content.length()-1] == ']') {
content.erase(0, 1);
content.erase(content.length() - 1);
}

ofstream outputFile(file_name);

if (!outputFile.is_open())
{
cerr << "Failed to open the output file." << endl;
return SAI_STATUS_FAILURE;
}

outputFile << content;
outputFile.close();

return SAI_STATUS_SUCCESS;
}

int dump_from_redis_rdb_file(string file_name)
{
ifstream input_file(file_name);
if (!input_file.is_open())
{
SWSS_LOG_NOTICE("The file %s does not exist for dumping from redis dump.rdb file.", file_name);
return SAI_STATUS_FAILURE;
}

input_file.seekg(0, ios::end); // Move to the end of the file
int64_t file_size = input_file.tellg(); // Get the current position
if (file_size >= RDB_FILE_MAX_SIZE)
{
SWSS_LOG_ERROR("Get %s's size failure or its size %ld >= %ld MB.\n", file_name.c_str(), file_size, RDB_FILE_MAX_SIZE / 1024 / 1024);

// Close the input file
input_file.close();
return SAI_STATUS_FAILURE;
}
input_file.seekg(0, ios::beg); // Move to the begin of the file
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

empty line after }


try
{
// Parse the JSON data from the file (validation)
nlohmann::json jsonData;
input_file >> jsonData;
input_file.close();

SWSS_LOG_DEBUG("%s\n","JSON file is valid.\n");

for (json::iterator it = jsonData.begin(); it != jsonData.end(); ++it)
{
json jj_key = it.key();

string keystr = jj_key;
string item_name = keystr;
size_t pos = keystr.find_first_of(":");
if (pos != string::npos)
{
if("ASIC_STATE" != keystr.substr(0, pos)) // filter out non ASIC_STATE
{
continue;
}
item_name = keystr.substr(pos + 1);
if (item_name.find(":") != string::npos)
{
item_name.replace(item_name.find_first_of(":"), 1, " ");
}
}
else
{
continue;
}

cout << item_name << " " << endl;

json jj = it.value();

if (!(*it).is_object())
{
continue;
}

TableMap map;
for (json::iterator itt = jj.begin(); itt != jj.end(); ++itt)
{
if (itt.key() == "NULL")
{
continue;
}
map[itt.key()] = itt.value();
}

size_t indent = 4;
size_t max_len = get_max_attr_len(map);
string str_indent = pad_string("", indent);

for (const auto&field: map)
{
stringstream ss;
ss << str_indent << pad_string(field.first, max_len) << " : ";
ss << field.second;
cout << ss.str() << std::endl;
}
cout << endl;
}
return SAI_STATUS_SUCCESS;
}
catch (exception &ex)
{
input_file.close();
cerr << "JSON file:" << file_name << " is invalid." << endl;
cerr << "JSON parsing error: " << ex.what() << endl;
}
return SAI_STATUS_FAILURE;
}

int main(int argc, char **argv)
{
swss::Logger::getInstance().setMinPrio(swss::Logger::SWSS_DEBUG);

Expand All @@ -411,6 +582,16 @@ int main(int argc, char ** argv)

g_cmdOptions = handleCmdLine(argc, argv);

if (g_cmdOptions.rdb_file.size() > 0)
{
if (SAI_STATUS_FAILURE == pre_process_file(g_cmdOptions.rdb_file))
{
return EXIT_FAILURE;
}
dump_from_redis_rdb_file(g_cmdOptions.rdb_file);
return EXIT_SUCCESS;
}

swss::DBConnector db("ASIC_DB", 0);

std::string table = ASIC_STATE_TABLE;
Expand Down