269 lines
7.1 KiB
C++
269 lines
7.1 KiB
C++
#pragma once
|
|
#ifndef _NB_LOGGER
|
|
#define _NB_LOGGER
|
|
|
|
#include <chrono>
|
|
#include <ostream>
|
|
#include <thread>
|
|
#include <unordered_map>
|
|
#include <vector>
|
|
|
|
#include "DataSink.hpp"
|
|
#include "Errors.hpp"
|
|
#include "Processes.hpp"
|
|
#include "ThreadSafeQueue.hpp"
|
|
#include "TypeTraits.hpp"
|
|
|
|
namespace nb {
|
|
|
|
typedef std::chrono::time_point<
|
|
std::chrono::system_clock,
|
|
std::chrono::nanoseconds
|
|
> LoggerTimePoint;
|
|
|
|
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() override {
|
|
if (!static_cast<LoggerType*>(this)->isRunning()) {
|
|
this->_running = true;
|
|
this->_runningThread = std::make_shared<std::thread>([&]{
|
|
while(static_cast<LoggerType*>(this)->isRunning()) {
|
|
static_cast<LoggerType*>(this)->flush();
|
|
}
|
|
static_cast<LoggerType*>(this)->flush();
|
|
});
|
|
}
|
|
return static_cast<LoggerType*>(this)->isRunning();
|
|
}
|
|
protected:
|
|
LoggerBase() = default;
|
|
|
|
StreamType _ostream;
|
|
};
|
|
|
|
struct LogEvent{
|
|
const LoggerTimePoint time;
|
|
const unsigned char lvl;
|
|
const std::string msg;
|
|
const std::thread::id tid;
|
|
const uint64_t pid;
|
|
const std::string file="";
|
|
const unsigned int line=0;
|
|
};
|
|
|
|
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(nb::RefPackToPtrVec<std::ostream, ST...>(streams...).vec) {}
|
|
|
|
~DebugLogger() { static_cast<LoggerType*>(this)->stop(); }
|
|
|
|
void log(
|
|
std::string msg,
|
|
uint8_t lvl=0x00,
|
|
std::string file="",
|
|
unsigned int line=0
|
|
) {
|
|
static_cast<LoggerType*>(this)->push(LogEvent{
|
|
std::chrono::system_clock::now(),
|
|
lvl,
|
|
msg,
|
|
std::this_thread::get_id(),
|
|
GetPID(),
|
|
file,
|
|
line
|
|
});
|
|
}
|
|
|
|
template <size_t N>
|
|
void log(
|
|
char const(&msg) [N],
|
|
uint8_t lvl=0x00,
|
|
std::string file="",
|
|
unsigned int line=0
|
|
) {
|
|
static_cast<LoggerType*>(this)->log(std::string(msg), lvl, file, line);
|
|
}
|
|
|
|
template <typename T>
|
|
void log(
|
|
const ErrorBase<T>& err,
|
|
uint8_t lvl=0xFF,
|
|
std::string file="",
|
|
unsigned int line=0
|
|
) {
|
|
static_cast<LoggerType*>(this)->log(err.what(), lvl, file, line);
|
|
}
|
|
|
|
template <typename T>
|
|
std::enable_if_t<std::is_base_of_v<std::exception, T>, void> log(
|
|
const T& err,
|
|
uint8_t lvl=0xFF,
|
|
std::string file="",
|
|
unsigned int line=0
|
|
) {
|
|
static_cast<LoggerType*>(this)->log(std::string(err.what()), lvl, file, line);
|
|
}
|
|
|
|
template<typename U>
|
|
void warn(
|
|
U val,
|
|
uint8_t lvl=0x01,
|
|
std::string file="",
|
|
unsigned int line=0
|
|
) { static_cast<LoggerType*>(this)->log(val, lvl, file, line); }
|
|
|
|
template<typename U>
|
|
void error(
|
|
U val,
|
|
std::string file="",
|
|
unsigned int line=0
|
|
) { static_cast<LoggerType*>(this)->log(val, 0xFF, file, line); }
|
|
|
|
protected:
|
|
std::vector<std::ostream*> _ostream;
|
|
|
|
};
|
|
|
|
class DefaultDebugLogger : public DebugLogger<DefaultDebugLogger> {
|
|
using LoggerType = DefaultDebugLogger;
|
|
using Base = DebugLogger<DefaultDebugLogger>;
|
|
|
|
template <typename... Ts>
|
|
struct LogRow;
|
|
|
|
public:
|
|
using Base::Base;
|
|
|
|
~DefaultDebugLogger() { stop(); }
|
|
|
|
friend class BufferedDataProcessor<LogEvent, ThreadsafeQueue<LogEvent>, DefaultDebugLogger>;
|
|
|
|
template <typename STR, typename... Ts>
|
|
friend STR& operator<<(STR&, const DefaultDebugLogger::LogRow<Ts...>&);
|
|
|
|
protected:
|
|
using Base::_ostream;
|
|
|
|
bool process(const LogEvent& msg);
|
|
};
|
|
|
|
#ifndef _NB_NO_LOGGER
|
|
extern DefaultDebugLogger logger;
|
|
#endif // _NB_NO_LOGGER
|
|
|
|
// Taking Charge of Adult ADHD by Russell Barkley
|
|
|
|
/* template <typename T=NoneType>
|
|
struct NB_DEFAULT_LOGGER_THROW;
|
|
|
|
template<>
|
|
struct NB_DEFAULT_LOGGER_THROW<NoneType> {
|
|
template <typename T>
|
|
NB_DEFAULT_LOGGER_THROW(T arg) {
|
|
#ifdef _NB_AUTOLOG
|
|
logger.error(arg);
|
|
#endif // _NB_AUTLOG
|
|
throw arg;
|
|
}
|
|
};
|
|
|
|
template <typename T>
|
|
struct NB_DEFAULT_LOGGER_THROW {
|
|
template <typename... Args>
|
|
NB_DEFAULT_LOGGER_THROW(Args&&... args) {
|
|
std::shared_ptr<T> error_ptr;
|
|
#ifdef _NB_AUTOLOG
|
|
#ifdef _NB_CODE_ERROR_LOCATIONS
|
|
error_ptr = std::make_shared<T>(args..., __LINE__, __FILE__);
|
|
#else
|
|
error_ptr = std::make_shared<T>(args...);
|
|
#endif // _NB_CODE_ERROR_LOCATIONS
|
|
logger.error(*error_ptr);
|
|
#endif // _NB_AUTLOG
|
|
throw *error_ptr;
|
|
}
|
|
}; */
|
|
|
|
/* template <typename Arg1=NoneType, typename...Args>
|
|
void NB_DEFAULT_LOGGER_THROW(Args&& ... args) {
|
|
std::shared_ptr<Arg1> error_ptr;
|
|
#ifdef _NB_AUTOLOG
|
|
#ifdef _NB_CODE_ERROR_LOCATIONS
|
|
error_ptr = std::make_shared<Arg1>(args..., __LINE__, __FILE__);
|
|
#else
|
|
error_ptr = std::make_shared<Arg1>(args...);
|
|
#endif // _NB_CODE_ERROR_LOCATIONS
|
|
logger.error(*error_ptr);
|
|
#endif // _NB_AUTLOG
|
|
throw *error_ptr;
|
|
}
|
|
|
|
template <typename Arg>
|
|
void NB_DEFAULT_LOGGER_THROW<NoneType>(const Arg& arg) {
|
|
#ifdef _NB_AUTOLOG
|
|
logger.error(arg);
|
|
#endif // _NB_AUTLOG
|
|
throw arg;
|
|
} */
|
|
|
|
template <typename T>
|
|
void NB_DEFAULT_LOGGER_THROW(const T& err, std::string file="", unsigned int line = 0) {
|
|
#ifdef _NB_AUTOLOG
|
|
if (file.empty()) {
|
|
logger.error(err);
|
|
} else {
|
|
logger.error(err, file, line);
|
|
}
|
|
#endif // _NB_AUTLOG
|
|
throw err;
|
|
}
|
|
|
|
} // namespace nb
|
|
|
|
#ifdef _NB_AUTOLOG
|
|
#ifdef _NB_CODE_ERROR_LOCATIONS
|
|
#ifndef LOG
|
|
#define LOG(args...) nb::logger.log(args, __FILE__, __LINE__)
|
|
#endif // LOG
|
|
#ifndef WARN
|
|
#define WARN(args...) nb::logger.warn(args, __FILE__, __LINE__)
|
|
#endif // WARN
|
|
#ifndef ERROR
|
|
#define ERROR(args...) nb::logger.error(args, __FILE__, __LINE__)
|
|
#endif // ERROR
|
|
#else
|
|
#ifndef LOG
|
|
#define LOG(args...) nb::logger.log(args)
|
|
#endif // LOG
|
|
#ifndef WARN
|
|
#define WARN(args...) nb::logger.warn(args)
|
|
#endif // WARN
|
|
#ifndef ERROR
|
|
#define ERROR(args...) nb::logger.error(args)
|
|
#endif // ERROR
|
|
#endif // _NB_CODE_ERROR_LOCATIONS
|
|
#endif // _NB_AUTOLOG
|
|
|
|
#ifndef THROW
|
|
#ifdef _NB_AUTOLOG
|
|
#define THROW(args...) ERROR(args); throw args
|
|
#else
|
|
#define THROW(args...) throw args
|
|
#endif // _NB_CODE_ERROR_LOCATIONS
|
|
#endif // THROW
|
|
|
|
#endif // _NB_LOGGER
|