common/loglevel.cpp (183 lines of code) (raw):
#include <iostream>
#include <iomanip>
#include <vector>
#include <functional>
#include <algorithm>
#include <unistd.h>
#include "schema.h"
#include "loglevel.h"
#include "logger.h"
#include "dbconnector.h"
#include "producerstatetable.h"
using namespace swss;
[[ noreturn ]] void usage(const std::string &program, int status, const std::string &message)
{
if (message.size() != 0)
{
std::cout << message << std::endl << std::endl;
}
std::cout << "Usage: " << program << " [OPTIONS]" << std::endl
<< "SONiC logging severity level setting." << std::endl << std::endl
<< "Options:" << std::endl
<< "\t -h\tprint this message" << std::endl
<< "\t -l\tloglevel value" << std::endl
<< "\t -c\tcomponent name in DB for which loglevel is applied (provided with -l)" << std::endl
<< "\t -a\tapply loglevel to all components (provided with -l)" << std::endl
<< "\t -s\tapply loglevel for SAI api component (equivalent to adding prefix \"SAI_API_\" to component)" << std::endl
<< "\t -p\tprint components registered in DB for which setting can be applied" << std::endl
<< "\t -d\treturn all components to default loglevel" << std::endl<< std::endl
<< "Examples:" << std::endl
<< "\t" << program << " -l NOTICE -c orchagent # set orchagent severity level to NOTICE" << std::endl
<< "\t" << program << " -l SAI_LOG_LEVEL_ERROR -s -c SWITCH # set SAI_API_SWITCH severity to ERROR" << std::endl
<< "\t" << program << " -l DEBUG -a # set all not SAI components severity to DEBUG" << std::endl
<< "\t" << program << " -l SAI_LOG_LEVEL_DEBUG -s -a # set all SAI_API_* severity to DEBUG" << std::endl
<< "\t" << program << " -d # return all components to default loglevel" << std::endl;
exit(status);
}
void setLoglevel(swss::Table& logger_tbl, const std::string& component, const std::string& loglevel)
{
logger_tbl.hset(component, "LOGLEVEL",loglevel);
}
bool validateSaiLoglevel(const std::string &prioStr)
{
static const std::vector<std::string> saiPrios = {
"SAI_LOG_LEVEL_CRITICAL",
"SAI_LOG_LEVEL_ERROR",
"SAI_LOG_LEVEL_WARN",
"SAI_LOG_LEVEL_NOTICE",
"SAI_LOG_LEVEL_INFO",
"SAI_LOG_LEVEL_DEBUG",
};
return std::find(saiPrios.begin(), saiPrios.end(), prioStr) != saiPrios.end();
}
bool filterOutSaiKeys(const std::string& key)
{
return key.find("SAI_API_") != std::string::npos;
}
bool filterSaiKeys(const std::string& key)
{
return key.find("SAI_API_") == std::string::npos;
}
std::vector<std::string> get_sai_keys(std::vector<std::string> keys)
{
keys.erase(std::remove_if(keys.begin(), keys.end(), filterSaiKeys), keys.end());
return keys;
}
std::vector<std::string> get_no_sai_keys(std::vector<std::string> keys)
{
keys.erase(std::remove_if(keys.begin(), keys.end(), filterOutSaiKeys), keys.end());
return keys;
}
void setAllLoglevel(swss::Table& logger_tbl, std::vector<std::string> components, std::string loglevel)
{
for (const auto& component : components)
{
setLoglevel(logger_tbl, component, loglevel);
}
SWSS_LOG_DEBUG("All components are with %s loglevel", loglevel.c_str());
}
int swssloglevel(int argc, char** argv)
{
int opt;
bool applyToAll = false, print = false, default_loglevel_opt = false;
std::string prefix = "", component, loglevel;
auto exitWithUsage = std::bind(usage, argv[0], std::placeholders::_1, std::placeholders::_2);
while ( (opt = getopt (argc, argv, "c:l:sapdh")) != -1)
{
switch(opt)
{
case 'c':
component = optarg;
break;
case 'l':
loglevel = optarg;
break;
case 's':
prefix = "SAI_API_";
break;
case 'a':
applyToAll = true;
break;
case 'p':
print = true;
break;
case 'd':
default_loglevel_opt = true;
break;
case 'h':
exitWithUsage(EXIT_SUCCESS, "");
break;
default:
exitWithUsage(EXIT_FAILURE, "Invalid option");
}
}
DBConnector config_db("CONFIG_DB", 0);
swss::Table logger_tbl(&config_db, CFG_LOGGER_TABLE_NAME);
std::vector<std::string> keys;
logger_tbl.getKeys(keys);
if (print)
{
int errorCount = 0;
if (argc != 2)
{
exitWithUsage(EXIT_FAILURE, "-p option does not accept other options");
}
std::sort(keys.begin(), keys.end());
for (const auto& key : keys)
{
std::string level;
if (!(logger_tbl.hget(key, DAEMON_LOGLEVEL, level)))
{
std::cerr << std::left << std::setw(30) << key << "Unknown log level" << std::endl;
errorCount ++;
}
else
{
std::cout << std::left << std::setw(30) << key << level << std::endl;
}
}
if (errorCount > 0)
return (EXIT_FAILURE);
return (EXIT_SUCCESS);
}
if(default_loglevel_opt)
{
std::vector<std::string> sai_keys = get_sai_keys(keys);
std::vector<std::string> no_sai_keys = get_no_sai_keys(keys);
setAllLoglevel(logger_tbl,no_sai_keys, std::string(DEFAULT_LOGLEVEL));
setAllLoglevel(logger_tbl,sai_keys, std::string(SAI_DEFAULT_LOGLEVEL));
return (EXIT_SUCCESS);
}
if ((prefix == "SAI_API_") && !validateSaiLoglevel(loglevel))
{
exitWithUsage(EXIT_FAILURE, "Invalid SAI loglevel value");
}
else if ((prefix == "") && (Logger::priorityStringMap.find(loglevel) == Logger::priorityStringMap.end()))
{
exitWithUsage(EXIT_FAILURE, "Invalid loglevel value");
}
if (applyToAll)
{
if (component != "")
{
exitWithUsage(EXIT_FAILURE, "Invalid options provided with -a");
}
if (prefix == "SAI_API_")
{
keys.erase(std::remove_if(keys.begin(), keys.end(), filterSaiKeys), keys.end());
}
else
{
keys.erase(std::remove_if(keys.begin(), keys.end(), filterOutSaiKeys), keys.end());
}
setAllLoglevel(logger_tbl, keys, loglevel);
exit(EXIT_SUCCESS);
}
component = prefix + component;
if (std::find(std::begin(keys), std::end(keys), component) == keys.end())
{
exitWithUsage(EXIT_FAILURE, "Component not present in DB");
}
setLoglevel(logger_tbl, component, loglevel);
return EXIT_SUCCESS;
}