184 lines
4.7 KiB
C++
184 lines
4.7 KiB
C++
#pragma once
|
|
#ifndef _NB_LOGGER
|
|
#define _NB_LOGGER
|
|
|
|
#include <atomic>
|
|
#include <chrono>
|
|
#include <ostream>
|
|
#include <thread>
|
|
#include <type_traits>
|
|
#include <unordered_map>
|
|
#include <vector>
|
|
|
|
#include "DataSink.hpp"
|
|
#include "Processes.hpp"
|
|
#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;
|
|
const std::thread::id tid;
|
|
const uint64_t pid;
|
|
};
|
|
|
|
typedef std::string (*LogProcessFunction)(const LoggerTimePoint&, const std::string&);
|
|
typedef std::unordered_map<uint8_t, LogProcessFunction> LogProcessFunctionMap;
|
|
|
|
template<typename LogType, typename Logger, typename ST=std::ostream*>
|
|
class LoggerBase
|
|
: public MultithreadedDataProcessor<LogType, Logger>{
|
|
using StreamType = ST;
|
|
using LoggerType = Logger;
|
|
using Base = MultithreadedDataProcessor<LogType, LoggerType>;
|
|
public:
|
|
bool run() {
|
|
if (!type_ptr->isRunning()) {
|
|
this->_running = true;
|
|
this->_runningThread = std::make_shared<std::thread>([&]{
|
|
while(type_ptr->isRunning()) {
|
|
type_ptr->flush();
|
|
}
|
|
type_ptr->flush();
|
|
});
|
|
}
|
|
return type_ptr->isRunning();
|
|
}
|
|
protected:
|
|
LoggerBase() = default;
|
|
|
|
StreamType _ostream;
|
|
|
|
private:
|
|
LoggerType* type_ptr = static_cast<LoggerType*>(this);
|
|
};
|
|
|
|
template <typename T, typename... Pack>
|
|
struct PackIsType;
|
|
|
|
template <typename T, typename PackType>
|
|
struct PackIsType<T, PackType> {
|
|
const bool value = std::is_base_of<T, PackType>::value;
|
|
};
|
|
|
|
template <typename T, typename FirstPack, typename... Pack>
|
|
struct PackIsType<T, FirstPack, Pack...> {
|
|
const bool value = std::is_base_of<T, FirstPack>::value && PackIsType<T, Pack...>::value;
|
|
};
|
|
|
|
template <typename T, typename Pack1, typename... Pack>
|
|
struct StreamRefToPtrVec {
|
|
StreamRefToPtrVec(std::vector<T*> _vec, Pack1& p1, Pack&... packs)
|
|
: vec(_vec) {
|
|
static_assert(std::is_base_of<T, Pack1>::value);
|
|
vec.push_back(&p1);
|
|
vec = StreamRefToPtrVec<T, Pack...>(vec, packs...).vec;
|
|
}
|
|
|
|
StreamRefToPtrVec(Pack1& p1, Pack&... packs)
|
|
: StreamRefToPtrVec({}, p1, packs...) {}
|
|
|
|
std::vector<T*> vec;
|
|
};
|
|
|
|
template <typename T, typename Pack>
|
|
struct StreamRefToPtrVec<T, Pack> {
|
|
StreamRefToPtrVec(std::vector<T*> _vec, Pack& p1)
|
|
: vec(_vec) {
|
|
static_assert(std::is_base_of<T, Pack>::value);
|
|
vec.push_back(&p1);
|
|
}
|
|
|
|
StreamRefToPtrVec(Pack& p1)
|
|
: StreamRefToPtrVec({}, p1) {}
|
|
|
|
std::vector<T*> vec;
|
|
};
|
|
|
|
template <typename LT>
|
|
class DebugLogger : public LoggerBase<LogEvent, LT, std::vector<std::ostream*>>{
|
|
using StreamType = std::vector<std::ostream*>;
|
|
using LoggerType = LT;
|
|
using Base = LoggerBase<LogEvent, LoggerType, StreamType>;
|
|
public:
|
|
|
|
template<typename... ST>
|
|
DebugLogger(ST&... streams) : _ostream(StreamRefToPtrVec<std::ostream, ST...>(streams...).vec) {}
|
|
|
|
~DebugLogger() { type_ptr->stop(); }
|
|
|
|
void log(const std::string& msg, const uint8_t& lvl=0xFF) {
|
|
type_ptr->push(LogEvent{
|
|
std::chrono::system_clock::now(),
|
|
lvl,
|
|
msg,
|
|
std::this_thread::get_id(),
|
|
GetPID(),
|
|
});
|
|
}
|
|
|
|
template <size_t N>
|
|
void log(char const(&msg) [N], const uint8_t& lvl=0xFF) {
|
|
type_ptr->log(std::string(msg), lvl);
|
|
}
|
|
|
|
void log(const std::exception& err, const uint8_t& lvl=0xFF) {
|
|
type_ptr->log(err.what(), lvl);
|
|
}
|
|
|
|
template<typename U>
|
|
void warn(const U& val, const uint8_t& lvl=0x01) { type_ptr->log(val, lvl); }
|
|
|
|
template<typename U>
|
|
void error(const U& val) { type_ptr->log(val, 0xFF); }
|
|
|
|
protected:
|
|
std::vector<std::ostream*> _ostream;
|
|
|
|
private:
|
|
LoggerType* type_ptr = static_cast<LoggerType*>(this);
|
|
|
|
};
|
|
|
|
class DefaultDebugLogger : public DebugLogger<DefaultDebugLogger> {
|
|
using LoggerType = DefaultDebugLogger;
|
|
using Base = DebugLogger<DefaultDebugLogger>;
|
|
public:
|
|
using Base::Base;
|
|
|
|
~DefaultDebugLogger() { stop(); }
|
|
|
|
friend class BufferedDataProcessor<LogEvent, ThreadsafeQueue<LogEvent>, DefaultDebugLogger>;
|
|
|
|
protected:
|
|
using Base::_ostream;
|
|
|
|
bool process(const LogEvent& msg) {
|
|
for (const auto os : this->_ostream) {
|
|
(*os) << msg.pid << " - " << msg.tid << " : " << msg.msg << "\n";
|
|
}
|
|
return true;
|
|
}
|
|
|
|
};
|
|
|
|
/* class BasicLogger : public LoggerBase<BasicLogger> {
|
|
public:
|
|
using Base = LoggerBase<BasicLogger>;
|
|
BasicLogger(std::ostream& stream) : Base(stream) {}
|
|
|
|
virtual void process(const LogEvent& event) {
|
|
*_ostreams[0] << event.msg << "\n";
|
|
}
|
|
}; */
|
|
|
|
} // namespace nb
|
|
#endif // _NB_LOGGER
|