Skip to content

Commit

Permalink
Added command line switches to control logging level of monitors
Browse files Browse the repository at this point in the history
Global logging level can also be set

Updated README.md to include new command line switch and cloning instructions
  • Loading branch information
quantum-shift committed Jul 21, 2021
1 parent b100f36 commit 23a00b5
Show file tree
Hide file tree
Showing 4 changed files with 109 additions and 7 deletions.
12 changes: 11 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,12 @@ prmon currently runs on Linux machines as it requires access to the

## Build and Deployment

### Cloning the project

As prmon has dependencies on submodules, clone the project as

git clone --recurse-submodules https://github.com/HSF/prmon.git

### Building the project

Building prmon requires a C++ compiler that fully supports C++11,
Expand Down Expand Up @@ -83,7 +89,7 @@ The `prmon` binary is invoked with the following arguments:
```sh
prmon [--pid PPP] [--filename prmon.txt] [--json-summary prmon.json] \
[--interval 30] [--suppress-hw-info] [--units] [--netdev DEV] \
[--disable MON1] \
[--disable MON1] [--level LEV] [--level MON:LEV]\
[-- prog arg arg ...]
```

Expand All @@ -97,6 +103,10 @@ prmon [--pid PPP] [--filename prmon.txt] [--json-summary prmon.json] \
* `--disable` is used to disable specific monitors (and can be specified multiple times);
the default is that `prmon` monitors everything that it can
* Note that the `wallmon` monitor is the only monitor that cannot be disabled
* `--level` is used to set the logging level for monitors
* `--level LEV` sets the level for all monitors to LEV
* `--level MON:LEV` sets the level for monitor MON to LEV
* The valid levels are `trace`, `debug`, `info`, `warn`, `error`, `critical`
* `--` after this argument the following arguments are treated as a program to invoke
and remaining arguments are passed to it; `prmon` will then monitor this process
instead of being given a PID via `--pid`
Expand Down
67 changes: 64 additions & 3 deletions package/src/MessageBase.cpp
Original file line number Diff line number Diff line change
@@ -1,7 +1,64 @@
#include "MessageBase.h"

#include <map>
#include <cctype>

#include "Imonitor.h"
#include "registry.h"
#include "spdlog/spdlog.h"

bool invalid_level_option = false;
std::map<std::string, spdlog::level::level_enum> monitor_level;
spdlog::level::level_enum global_logging_level = spdlog::level::warn;

void processLevel(std::string s) {
for (auto& ch: s) {
ch = std::tolower(ch);
}
if (s.find(':') == std::string::npos) {
// No ':' in option -> set global level
spdlog::level::level_enum get_level_enum = spdlog::level::from_str(s);
if (get_level_enum == 6) {
// Invalid name
spdlog::error("Invalid level name " + s);
invalid_level_option = true;
} else
global_logging_level = get_level_enum;
} else {
size_t split_index = s.find(':');
std::string monitor_name = s.substr(0, split_index);
std::string level_name =
s.substr(split_index + 1, s.size() - (split_index + 1));

// Check validity of monitor name
bool valid_monitor = false;
auto monitors = registry::Registry<Imonitor>::list_registered();
for (const auto& monitor : monitors) {
if (monitor == monitor_name) {
valid_monitor = true;
break;
}
}
if (!valid_monitor) {
spdlog::error("Invalid monitor name " + monitor_name +
" for logging level");
invalid_level_option = true;
return;
}
// Check validity of level name
spdlog::level::level_enum get_level_enum =
spdlog::level::from_str(level_name);
if (get_level_enum == 6) {
// Invalid name
spdlog::error("Invalid level name " + level_name);
invalid_level_option = true;
return;
}

monitor_level[monitor_name] = get_level_enum;
}
}

void MessageBase::log_init(const std::string& classname,
const spdlog::level::level_enum& level) {
// Initialise sink list
Expand All @@ -10,9 +67,13 @@ void MessageBase::log_init(const std::string& classname,
// Use the sink list to create multi sink logger
logger =
std::make_shared<spdlog::logger>(classname, s_list.begin(), s_list.end());
log_level = level;
set_log_level(level);
logger->flush_on(level);
if (monitor_level.find(classname) != monitor_level.end()) {
log_level = monitor_level[classname];
} else {
log_level = level;
}
set_log_level(log_level);
logger->flush_on(log_level);
spdlog::register_logger(logger);
info(classname + " logger initialised!");
}
Expand Down
14 changes: 13 additions & 1 deletion package/src/MessageBase.h
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
#ifndef PRMON_MESSAGEBASE_H
#define PRMON_MESSAGEBASE_H 1

#include <map>

#include "spdlog/sinks/basic_file_sink.h"
#include "spdlog/sinks/stdout_color_sinks.h"
#include "spdlog/spdlog.h"
Expand All @@ -12,13 +14,23 @@ static const std::shared_ptr<spdlog::sinks::stdout_color_sink_st> c_sink{
static const std::shared_ptr<spdlog::sinks::basic_file_sink_st> f_sink{
std::make_shared<spdlog::sinks::basic_file_sink_st>("prmon.log", true)};

// Map from monitor to logging level

extern bool invalid_level_option;
extern std::map<std::string, spdlog::level::level_enum> monitor_level;

// Processing command line switches

extern spdlog::level::level_enum global_logging_level;
void processLevel(std::string s);

class MessageBase {
std::shared_ptr<spdlog::logger> logger;

protected:
spdlog::level::level_enum log_level;
void log_init(const std::string& classname,
const spdlog::level::level_enum& level = spdlog::level::warn);
const spdlog::level::level_enum& level = global_logging_level);

public:
void set_log_level(const spdlog::level::level_enum& level);
Expand Down
23 changes: 21 additions & 2 deletions package/src/prmon.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -235,7 +235,6 @@ int main(int argc, char* argv[]) {
logger->set_level(spdlog::level::warn);
logger->flush_on(spdlog::level::warn);
spdlog::set_default_logger(logger);
spdlog::info("global logger initialised!");

pid_t pid = -1;
bool got_pid = false;
Expand All @@ -258,10 +257,11 @@ int main(int argc, char* argv[]) {
{"units", no_argument, NULL, 'u'},
{"netdev", required_argument, NULL, 'n'},
{"help", no_argument, NULL, 'h'},
{"level", required_argument, NULL, 'l'},
{0, 0, 0, 0}};

int c;
while ((c = getopt_long(argc, argv, "-p:f:j:i:d:sun:h", long_options,
while ((c = getopt_long(argc, argv, "-p:f:j:i:d:sun:h:l:", long_options,
NULL)) != -1) {
switch (char(c)) {
case 'p':
Expand Down Expand Up @@ -294,6 +294,9 @@ int main(int argc, char* argv[]) {
case 'h':
do_help = 1;
break;
case 'l':
processLevel(std::string(optarg));
break;
default:
spdlog::error("Use '--help' for usage ");
return 1;
Expand Down Expand Up @@ -331,6 +334,12 @@ int main(int argc, char* argv[]) {
<< " all monitors enabled by default\n"
<< " Special name '[~]all' sets default "
"state\n"
<< "[--level, -l lev] Set the logging level of all "
"monitors\n"
<< "[--level, -l mon:lev] Set the logging level of a "
"specific monitor\n"
<< " Valid level names are trace, debug, info,\n"
<< " warn, error and critical\n"
<< "[--] prog [arg] ... Instead of monitoring a PID prmon will\n"
<< " execute the given program + args and\n"
<< " monitor this (must come after other \n"
Expand Down Expand Up @@ -359,6 +368,16 @@ int main(int argc, char* argv[]) {
}
}

if (invalid_level_option) {
return EXIT_FAILURE;
}

// Now that we know given level option is valid, update the level of the
// global logger
logger->set_level(global_logging_level);
logger->flush_on(global_logging_level);
spdlog::set_default_logger(logger);

if ((!got_pid && child_args == -1) || (got_pid && child_args > 0)) {
std::stringstream strm;
strm << "One and only one PID or child program is required - ";
Expand Down

0 comments on commit 23a00b5

Please sign in to comment.