NBEngine/engine/NBCore/Logger.hpp
2025-12-27 03:49:34 -06:00

133 lines
3.0 KiB
C++

#pragma once
#ifndef _NB_LOGGER
#define _NB_LOGGER
#include <atomic>
#include <chrono>
#include <ostream>
#include <thread>
#include <unordered_map>
#include "ThreadSafeQueue.hpp"
namespace nb {
typedef std::chrono::time_point<
std::chrono::system_clock,
std::chrono::nanoseconds
> LoggerTimePoint;
struct LogEvent{
const LoggerTimePoint time;
const unsigned char lvl;
const std::string msg;
};
typedef std::string (*LogProcessFunction)(const LoggerTimePoint&, const std::string&);
typedef std::unordered_map<uint8_t, LogProcessFunction> LogProcessFunctionMap;
template<typename StreamType>
class Logger {
public:
Logger(StreamType& stream) : _ostream(&stream) {}
bool isRunning() const;
unsigned int count() const;
bool run();
bool stop();
LogEvent pop();
void flush() {
while(_queue.size()) {
pop();
}
}
void deleteAll() {
_queue.empty();
}
void msg(const std::string& _msg, uint8_t lvl=0) {
_queue.push(LogEvent{std::chrono::system_clock::now(), lvl, _msg});
}
void warn(const std::string& _msg, uint8_t lvl=1) {
msg(_msg, lvl);
}
void warn(const std::exception& _err, uint8_t lvl=1) {
msg(_err.what(), lvl);
}
void error(const std::string& _msg, uint8_t lvl=0xFF) {
msg(_msg, lvl);
}
void error(const std::exception& _err, uint8_t lvl=0xFF) {
msg(_err.what(), lvl);
}
protected:
virtual void process(const LogEvent& event) {
uint8_t lvl = event.lvl;
try {
*_ostream << _function_map.at(lvl)(event.time, event.msg).c_str();
} catch (std::out_of_range e) {
*_ostream << _function_map.at(0)(event.time, event.msg).c_str();
//*_ostream << event.msg;
}
*_ostream << "\n";
}
static const LogProcessFunctionMap _function_map;
ThreadsafeQueue<LogEvent> _queue;
StreamType* const _ostream;
std::atomic<bool> _running;
std::shared_ptr<std::thread> _runningThread = nullptr;
};
template <typename ST>
const LogProcessFunctionMap Logger<ST>::_function_map = {
{0, [](const LoggerTimePoint& tp, const std::string& msg){
return msg;
}}
};
template <typename ST>
bool Logger<ST>::isRunning() const {
return _running && bool(_runningThread);
}
template <typename ST>
unsigned int Logger<ST>::count() const {
return _queue.size();
}
template <typename ST>
bool Logger<ST>::run() {
if (!isRunning()) {
_runningThread = std::make_shared<std::thread>([&]{
while(this->isRunning()) {
this->flush();
}
});
}
return isRunning();
}
template <typename ST>
bool Logger<ST>::stop() {
if (isRunning()) {
_running = false;
_runningThread->join();
_runningThread = nullptr;
flush();
}
return isRunning();
}
template <typename ST>
LogEvent Logger<ST>::pop() {
std::shared_ptr<LogEvent> event;
_queue.pop(event);
process(*event);
return *event;
}
} // namespace nb
#endif // _NB_LOGGER