133 lines
3.0 KiB
C++
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
|