Adding a general logger and integrating it with daggyr
This commit is contained in:
71
libdaggy/include/daggy/GeneralLogger.hpp
Normal file
71
libdaggy/include/daggy/GeneralLogger.hpp
Normal file
@@ -0,0 +1,71 @@
|
||||
#pragma once
|
||||
|
||||
#include <atomic>
|
||||
#include <condition_variable>
|
||||
#include <deque>
|
||||
#include <functional>
|
||||
#include <mutex>
|
||||
#include <string>
|
||||
|
||||
#include "Defines.hpp"
|
||||
|
||||
namespace daggy {
|
||||
BETTER_ENUM(LogLevel, int, NONE = 0, ERROR, WARN, INFO, DEBUG);
|
||||
|
||||
class GeneralLogger
|
||||
{
|
||||
public:
|
||||
explicit GeneralLogger(std::ostream &os, LogLevel level = LogLevel::WARN);
|
||||
~GeneralLogger();
|
||||
|
||||
void setLevel(LogLevel level);
|
||||
void log(const std::string &msg, LogLevel level);
|
||||
|
||||
// Function will only be called if required
|
||||
void log(const std::function<std::string()> &fun, LogLevel level);
|
||||
|
||||
template <typename T>
|
||||
void error(const T &msg)
|
||||
{
|
||||
log(msg, LogLevel::ERROR);
|
||||
}
|
||||
template <typename T>
|
||||
void warn(const T &msg)
|
||||
{
|
||||
log(msg, LogLevel::WARN);
|
||||
}
|
||||
template <typename T>
|
||||
void info(const T &msg)
|
||||
{
|
||||
log(msg, LogLevel::INFO);
|
||||
}
|
||||
template <typename T>
|
||||
void debug(const T &msg)
|
||||
{
|
||||
log(msg, LogLevel::DEBUG);
|
||||
}
|
||||
|
||||
void shutdown();
|
||||
|
||||
private:
|
||||
void emitMessages();
|
||||
|
||||
struct LogMessage
|
||||
{
|
||||
LogLevel level;
|
||||
std::string msg;
|
||||
TimePoint time;
|
||||
};
|
||||
|
||||
std::atomic<bool> running_;
|
||||
std::ostream &os_;
|
||||
LogLevel level_;
|
||||
|
||||
std::condition_variable newMessage_;
|
||||
std::mutex messageGuard_;
|
||||
std::deque<LogMessage> messages_;
|
||||
|
||||
std::thread messageEmiter_;
|
||||
};
|
||||
|
||||
} // namespace daggy
|
||||
@@ -2,6 +2,7 @@ target_sources(${PROJECT_NAME} PRIVATE
|
||||
Serialization.cpp
|
||||
Utilities.cpp
|
||||
DAGRunner.cpp
|
||||
GeneralLogger.cpp
|
||||
)
|
||||
|
||||
add_subdirectory(executors)
|
||||
|
||||
66
libdaggy/src/GeneralLogger.cpp
Normal file
66
libdaggy/src/GeneralLogger.cpp
Normal file
@@ -0,0 +1,66 @@
|
||||
#include <daggy/GeneralLogger.hpp>
|
||||
#include <daggy/Serialization.hpp>
|
||||
|
||||
namespace daggy {
|
||||
GeneralLogger::GeneralLogger(std::ostream &os, LogLevel level)
|
||||
: running_(true)
|
||||
, os_(os)
|
||||
, level_(level)
|
||||
, messageEmiter_(&GeneralLogger::emitMessages, this)
|
||||
{
|
||||
}
|
||||
|
||||
GeneralLogger::~GeneralLogger()
|
||||
{
|
||||
shutdown();
|
||||
}
|
||||
|
||||
void GeneralLogger::shutdown()
|
||||
{
|
||||
if (!running_)
|
||||
return;
|
||||
running_ = false;
|
||||
newMessage_.notify_one();
|
||||
messageEmiter_.join();
|
||||
os_.flush();
|
||||
}
|
||||
|
||||
void GeneralLogger::setLevel(LogLevel level)
|
||||
{
|
||||
level_ = level;
|
||||
}
|
||||
void GeneralLogger::log(const std::string &msg, LogLevel level)
|
||||
{
|
||||
if (level > level_) {
|
||||
return;
|
||||
}
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(messageGuard_);
|
||||
messages_.emplace_back(
|
||||
LogMessage{.level = level, .msg = msg, .time = Clock::now()});
|
||||
}
|
||||
newMessage_.notify_one();
|
||||
}
|
||||
|
||||
void GeneralLogger::log(const std::function<std::string()> &fun,
|
||||
LogLevel level)
|
||||
{
|
||||
if (level > level_)
|
||||
return;
|
||||
log(fun(), level);
|
||||
}
|
||||
|
||||
void GeneralLogger::emitMessages()
|
||||
{
|
||||
while (running_ || !messages_.empty()) {
|
||||
std::unique_lock<std::mutex> lock(messageGuard_);
|
||||
newMessage_.wait(lock, [&] { return !(messages_.empty() && running_); });
|
||||
for (const auto &msg : messages_) {
|
||||
os_ << timePointToString(msg.time) << " [" << msg.level._to_string()
|
||||
<< "] " << msg.msg << '\n';
|
||||
}
|
||||
os_.flush();
|
||||
messages_.clear();
|
||||
}
|
||||
}
|
||||
} // namespace daggy
|
||||
@@ -11,6 +11,7 @@ add_executable(${PROJECT_NAME} main.cpp
|
||||
unit_serialization.cpp
|
||||
unit_threadpool.cpp
|
||||
unit_utilities.cpp
|
||||
unit_generallogger.cpp
|
||||
# integration tests
|
||||
int_basic.cpp
|
||||
# Performance checks
|
||||
|
||||
31
libdaggy/tests/unit_generallogger.cpp
Normal file
31
libdaggy/tests/unit_generallogger.cpp
Normal file
@@ -0,0 +1,31 @@
|
||||
#include <catch2/catch.hpp>
|
||||
#include <daggy/GeneralLogger.hpp>
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
|
||||
using namespace daggy;
|
||||
|
||||
TEST_CASE("General Logger", "[general_logger]")
|
||||
{
|
||||
std::stringstream ss;
|
||||
GeneralLogger logger(ss);
|
||||
|
||||
SECTION("Logger logs a message")
|
||||
{
|
||||
std::string testMessage = "Test Message";
|
||||
logger.setLevel(LogLevel::INFO);
|
||||
logger.warn(testMessage);
|
||||
logger.shutdown();
|
||||
|
||||
auto captured = ss.str();
|
||||
REQUIRE(!captured.empty());
|
||||
REQUIRE(captured.find(testMessage) != std::string::npos);
|
||||
}
|
||||
|
||||
SECTION("Logger does not emit messages of higher levels")
|
||||
{
|
||||
logger.setLevel(LogLevel::INFO);
|
||||
logger.debug("Test Message");
|
||||
REQUIRE(ss.str().empty());
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user