Skip to content

Commit

Permalink
Added logging functionality (spdlog)
Browse files Browse the repository at this point in the history
spdlog was added as a submodule

All previous logging statements replaced with new logger

.github/workflows/ci.yml was updated to initialise submodules recursively
  • Loading branch information
quantum-shift committed Jun 30, 2021
1 parent f5bb448 commit f036e9d
Show file tree
Hide file tree
Showing 27 changed files with 257 additions and 106 deletions.
2 changes: 2 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ jobs:
steps:
# Checks-out our repository under $GITHUB_WORKSPACE, so our job can access it
- uses: actions/checkout@v2
with:
submodules: recursive

# Sets up useful environment variables
- name: Setup environment variables
Expand Down
3 changes: 3 additions & 0 deletions .gitmodules
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
[submodule "submodules/spdlog"]
path = submodules/spdlog
url = https://github.com/gabime/spdlog.git
11 changes: 11 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,11 @@ endif()
set(PROFILE_GPERFTOOLS "${PROFILE_GPERFTOOLS}"
CACHE BOOL "Build with the GPerfTools profiler library" FORCE)

if(NOT BUILD_BENCHMARK_LOG)
set(BUILD_BENCHMARK_LOG OFF)
endif()
set(BUILD_BENCHMARK_LOG "${BUILD_BENCHMARK_LOG}"
CACHE BOOL "Build binary which benchmarks spdlog speed" FORCE)

# Define a default build type when using a single-mode tool like make/ninja
# We make this default to Release, unless profiling is enabled, in which
Expand Down Expand Up @@ -92,9 +97,15 @@ install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/LICENSE
#--- project specific subdirectories -------------------------------------------
add_subdirectory(package)

#--- include directories -------------------------------------------
target_include_directories(prmon PRIVATE ${PROJECT_SOURCE_DIR}/package/include)
if (BUILD_BENCHMARK_LOG)
target_include_directories(benchmark-log PRIVATE ${PROJECT_SOURCE_DIR}/package/include)
endif(BUILD_BENCHMARK_LOG)
#--- create uninstall target ---------------------------------------------------
include(cmake/prmonUninstall.cmake)

#--- code format targets -------------------------------------------------------
include(cmake/clang-format.cmake)
include(cmake/python-format.cmake)

6 changes: 5 additions & 1 deletion package/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
find_package(nlohmann_json REQUIRED)


add_executable(prmon src/prmon.cpp
src/prmonutils.cpp
src/utils.cpp
Expand All @@ -10,8 +11,11 @@ add_executable(prmon src/prmon.cpp
src/wallmon.cpp
src/memmon.cpp
src/nvidiamon.cpp
src/MessageBase.cpp
)

if (BUILD_BENCHMARK_LOG)
add_executable(benchmark-log src/benchmark.cpp)
endif(BUILD_BENCHMARK_LOG)
# Some older versions of the nlohmann_json package don't define
# this target (< 3.0.0 ?). The build on these platforms seems to
# go ok even without this "link library" definition.
Expand Down
1 change: 1 addition & 0 deletions package/include/spdlog
28 changes: 28 additions & 0 deletions package/src/MessageBase.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
#include "MessageBase.h"

#include "spdlog/spdlog.h"

void MessageBase::log_init(const std::string& classname,
const spdlog::level::level_enum& level) {
// Initialise sink list
spdlog::sinks_init_list s_list = {c_sink, f_sink};

// 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);
spdlog::register_logger(logger);
info(classname + " logger initialised!");
}

void MessageBase::set_log_level(const spdlog::level::level_enum& level) {
log_level = level;
logger->set_level(level);
logger->flush_on(level);
}
void MessageBase::debug(const std::string& message) { logger->debug(message); }
void MessageBase::info(const std::string& message) { logger->info(message); }
void MessageBase::warning(const std::string& message) { logger->warn(message); }
void MessageBase::error(const std::string& message) { logger->error(message); }
31 changes: 31 additions & 0 deletions package/src/MessageBase.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
#ifndef PRMON_MESSAGEBASE_H
#define PRMON_MESSAGEBASE_H 1

#include "spdlog/sinks/basic_file_sink.h"
#include "spdlog/sinks/stdout_color_sinks.h"
#include "spdlog/spdlog.h"

// Global sinks

static const std::shared_ptr<spdlog::sinks::stdout_color_sink_st> c_sink{
std::make_shared<spdlog::sinks::stdout_color_sink_st>()};
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)};

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);

public:
void set_log_level(const spdlog::level::level_enum& level);
void debug(const std::string& message);
void info(const std::string& message);
void warning(const std::string& message);
void error(const std::string& message);
};

#endif // PRMON_MESSAGEBASE_H
18 changes: 18 additions & 0 deletions package/src/benchmark.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
#include "spdlog/sinks/basic_file_sink.h"
#include "spdlog/sinks/stdout_color_sinks.h"
#include "spdlog/spdlog.h"

int main() {
auto sink = std::make_shared<spdlog::sinks::stdout_color_sink_st>();
auto fsink =
std::make_shared<spdlog::sinks::basic_file_sink_mt>("sample.log", true);
spdlog::sinks_init_list sink_list = {sink, fsink};
auto logger = std::make_shared<spdlog::logger>("benchmark", sink_list.begin(),
sink_list.end());
logger->set_level(spdlog::level::warn);
const int maxN = 1e6;
for (int i = 0; i < maxN; ++i) {
logger->warn("Hello, benchmarking currently");
}
return 0;
}
2 changes: 2 additions & 0 deletions package/src/countmon.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
#include <iostream>
#include <sstream>

#include "MessageBase.h"
#include "utils.h"

// Constructor; uses RAII pattern to be valid
Expand All @@ -21,6 +22,7 @@ countmon::countmon()
count_average_stats{},
count_total_stats{},
iterations{0L} {
log_init(MY_NAME);
count_params.reserve(params.size());
for (const auto& param : params) {
count_params.push_back(param.get_name());
Expand Down
4 changes: 3 additions & 1 deletion package/src/countmon.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,17 +6,19 @@

#ifndef PRMON_COUNTMON_H
#define PRMON_COUNTMON_H 1
#define MY_NAME "countmon"

#include <map>
#include <string>
#include <unordered_map>
#include <vector>

#include "Imonitor.h"
#include "MessageBase.h"
#include "parameter.h"
#include "registry.h"

class countmon final : public Imonitor {
class countmon final : public Imonitor, public MessageBase {
private:
// Setup the parameters to monitor here
const prmon::parameter_list params = {{"nprocs", "1", "1"},
Expand Down
6 changes: 3 additions & 3 deletions package/src/cpumon.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,10 @@
#include <sstream>

#include "utils.h"

// Constructor; uses RAII pattern to be valid
// after construction
cpumon::cpumon() : cpu_params{}, cpu_stats{} {
log_init(MY_NAME);
cpu_params.reserve(params.size());
for (const auto& param : params) {
cpu_params.push_back(param.get_name());
Expand Down Expand Up @@ -74,8 +74,8 @@ void const cpumon::get_hardware_info(nlohmann::json& hw_json) {

// If the command failed print an error and move on
if (cmd_result.first) {
std::cerr << "Failed to execute 'lscpu' to get CPU information (code "
<< cmd_result.first << ")" << std::endl;
error("Failed to execute 'lscpu' to get CPU information (code " +
std::to_string(cmd_result.first) + ")");
return;
}

Expand Down
5 changes: 3 additions & 2 deletions package/src/cpumon.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,17 +6,18 @@

#ifndef PRMON_CPUMON_H
#define PRMON_CPUMON_H 1
#define MY_NAME "cpumon"

#include <map>
#include <string>
#include <unordered_map>
#include <vector>

#include "Imonitor.h"
#include "MessageBase.h"
#include "parameter.h"
#include "registry.h"

class cpumon final : public Imonitor {
class cpumon final : public Imonitor, public MessageBase {
private:
// Setup the parameters to monitor here
const prmon::parameter_list params = {{"utime", "s", ""}, {"stime", "s", ""}};
Expand Down
27 changes: 18 additions & 9 deletions package/src/iomon.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
// Constructor; uses RAII pattern to be valid
// after construction
iomon::iomon() : io_params{}, io_stats{} {
log_init(MY_NAME);
io_params.reserve(params.size());
for (const auto& param : params) {
io_params.push_back(param.get_name());
Expand Down Expand Up @@ -49,20 +50,28 @@ void iomon::update_stats(const std::vector<pid_t>& pids) {
#endif

for (auto& stat : io_stats) {
#if IOMON_TEST == 1
// This code block randomly suppresses io stat values
// to test recovery from the peak measured values
auto t = time(NULL);
auto m = (t + stat_counter) % 4;
std::cout << stat_counter << " " << t << " " << m << std::endl;
if (m == 0) stat.second = 0;
++stat_counter;
#if IOMON_TEST == 1
if (log_level <= spdlog::level::debug) {
auto t = time(NULL);
auto m = (t + stat_counter) % 4;
std::stringstream strm;
strm << stat_counter << " " << t << " " << m << std::endl;
debug(strm.str());
if (m == 0) stat.second = 0;
++stat_counter;
}
#endif
if (stat.second < io_max_stats[stat.first]) {
// Uh oh - somehow the i/o stats dropped so some i/o was lost
std::clog << "prmon: Warning, detected drop in i/o values for "
<< stat.first << " (" << io_max_stats[stat.first] << " became "
<< stat.second << ")" << std::endl;
if (log_level <= spdlog::level::warn) {
std::stringstream strm;
strm << "prmon: Warning, detected drop in i/o values for " << stat.first
<< " (" << io_max_stats[stat.first] << " became " << stat.second
<< ")" << std::endl;
warning(strm.str());
}
stat.second = io_max_stats[stat.first];
} else {
io_max_stats[stat.first] = stat.second;
Expand Down
5 changes: 3 additions & 2 deletions package/src/iomon.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,16 +6,17 @@

#ifndef PRMON_IOMON_H
#define PRMON_IOMON_H 1
#define MY_NAME "iomon"

#include <map>
#include <string>
#include <vector>

#include "Imonitor.h"
#include "MessageBase.h"
#include "parameter.h"
#include "registry.h"

class iomon final : public Imonitor {
class iomon final : public Imonitor, public MessageBase {
private:
// Setup the parameters to monitor here
const prmon::parameter_list params = {{"rchar", "B", "B/s"},
Expand Down
4 changes: 2 additions & 2 deletions package/src/memmon.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@
#include <sstream>

#include "utils.h"

// Constructor; uses RAII pattern to be valid
// after construction
memmon::memmon()
Expand All @@ -23,6 +22,7 @@ memmon::memmon()
mem_average_stats{},
mem_total_stats{},
iterations{0} {
log_init(MY_NAME);
mem_params.reserve(params.size());
for (const auto& param : params) {
mem_params.push_back(param.get_name());
Expand Down Expand Up @@ -93,7 +93,7 @@ void const memmon::get_hardware_info(nlohmann::json& hw_json) {
// Read some information from /proc/meminfo
std::ifstream memInfoFile{"/proc/meminfo"};
if (!memInfoFile.is_open()) {
std::cerr << "Failed to open /proc/meminfo" << std::endl;
error("Failed to open /proc/meminfo");
return;
}

Expand Down
4 changes: 3 additions & 1 deletion package/src/memmon.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,16 +6,18 @@

#ifndef PRMON_MEMMON_H
#define PRMON_MEMMON_H 1
#define MY_NAME "memmon"

#include <map>
#include <string>
#include <vector>

#include "Imonitor.h"
#include "MessageBase.h"
#include "parameter.h"
#include "registry.h"

class memmon final : public Imonitor {
class memmon final : public Imonitor, public MessageBase {
private:
// Default paramater list
// const static std::vector<std::string> default_memory_params{"vmem", "pss",
Expand Down
17 changes: 10 additions & 7 deletions package/src/netmon.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@

#include <cstring>
#include <memory>
#include <sstream>

#include "utils.h"

Expand All @@ -16,6 +17,7 @@
// to the monitor relative differences
netmon::netmon(std::vector<std::string> netdevs)
: interface_params{}, network_if_streams{} {
log_init(MY_NAME);
interface_params.reserve(params.size());
for (const auto& param : params) interface_params.push_back(param.get_name());

Expand Down Expand Up @@ -51,9 +53,9 @@ std::vector<std::string> const netmon::get_all_network_devs() {
}
closedir(d);
} else {
std::cerr << "Failed to open " << netdir
<< " to get list of network devices. "
<< "No network data will be available" << std::endl;
error("Failed to open " + std::string(netdir) +
" to get list of network devices. " +
"No network data will be available");
}
return devices;
}
Expand Down Expand Up @@ -94,10 +96,11 @@ void netmon::update_stats(const std::vector<pid_t>& pids) {
if (i.second >= network_stats_last[i.first]) {
network_net_counters[i.first] += i.second - network_stats_last[i.first];
} else {
std::clog
<< "prmon: network statistics error, counter values dropped for "
<< i.first << " (" << i.second << " < " << network_stats_last[i.first]
<< ")" << std::endl;
std::stringstream strm;
strm << "prmon: network statistics error, counter values dropped for "
<< i.first << " (" << i.second << " < "
<< network_stats_last[i.first] << ")" << std::endl;
warning(strm.str());
}
network_stats_last[i.first] = i.second;
}
Expand Down
Loading

0 comments on commit f036e9d

Please sign in to comment.