250 lines
6.5 KiB
C++
250 lines
6.5 KiB
C++
#pragma once
|
|
#ifndef _NB_LOGGER
|
|
#define _NB_LOGGER
|
|
|
|
#include <chrono>
|
|
#include <thread>
|
|
#include <unordered_map>
|
|
#include <vector>
|
|
|
|
#include <NBCore/DataSink.hpp>
|
|
#include <NBCore/ErrorsImpl.hpp>
|
|
#include <NBCore/Printer.hpp>
|
|
#include <NBCore/Processes.hpp>
|
|
#include <NBCore/ThreadSafeQueue.hpp>
|
|
#include <NBCore/TypeTraits.hpp>
|
|
|
|
namespace nb {
|
|
|
|
class ErrorBase;
|
|
|
|
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>
|
|
class LoggerBase : public MultithreadedDataProcessor<LogType, Logger>{
|
|
private:
|
|
Logger* const type_ptr = static_cast<LoggerType*>(this);
|
|
|
|
protected:
|
|
using LoggerType = Logger;
|
|
using Base = MultithreadedDataProcessor<LogType, LoggerType>;
|
|
using SinkType = DataSink<LogType>;
|
|
using Base::process;
|
|
std::shared_ptr<SinkType> _logsink;
|
|
LoggerBase(std::shared_ptr<SinkType> sink) : _logsink(sink) {}
|
|
|
|
public:
|
|
using Base::flush;
|
|
bool run() override {
|
|
_logsink->run();
|
|
return Base::run();
|
|
}
|
|
using Base::pause;
|
|
bool stop() noexcept override {
|
|
auto ret = Base::stop();
|
|
_logsink->stop();
|
|
return ret;
|
|
}
|
|
|
|
};
|
|
|
|
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;
|
|
};
|
|
|
|
class LogEventHandler : public DataSink<LogEvent> {
|
|
protected:
|
|
using Base = DataSink<LogEvent>;
|
|
using Base::_running;
|
|
std::atomic<uint8_t> _logLevel;
|
|
|
|
public:
|
|
using Base::isRunning;
|
|
LogEventHandler(uint8_t logging_level=0x01);
|
|
virtual uint8_t logLevel(uint8_t);
|
|
virtual uint8_t logLevel() const;
|
|
bool stop() noexcept override;
|
|
bool run() override;
|
|
};
|
|
|
|
template <typename LT>
|
|
class DebugLogger : public LoggerBase<LogEvent, LT>{
|
|
private:
|
|
LT* const type_ptr = static_cast<LT*>(this);
|
|
|
|
protected:
|
|
using LoggerType = LT;
|
|
using Base = LoggerBase<LogEvent, LoggerType>;
|
|
using SinkType = LogEventHandler;
|
|
using SinkPtr = std::shared_ptr<SinkType>;
|
|
using Distributor = MultiSink<LogEvent, LogEventHandler>;
|
|
using Base::_logsink;
|
|
using Base::process;
|
|
std::atomic<uint8_t> _loglvl;
|
|
virtual void write_message(
|
|
std::string msg,
|
|
uint8_t lvl=0x00,
|
|
std::string file="",
|
|
unsigned int line=0
|
|
) {
|
|
type_ptr->in(LogEvent{
|
|
std::chrono::system_clock::now(),
|
|
lvl,
|
|
msg,
|
|
std::this_thread::get_id(),
|
|
GetPID(),
|
|
file,
|
|
line
|
|
});
|
|
}
|
|
template <size_t N>
|
|
void write_message(
|
|
char const(&msg) [N],
|
|
uint8_t lvl=0x00,
|
|
std::string file="",
|
|
unsigned int line=0
|
|
) {
|
|
this->write_message(std::string(msg), lvl, file, line);
|
|
}
|
|
void write_message(
|
|
const ErrorBase& err,
|
|
uint8_t lvl=0x00,
|
|
std::string file="",
|
|
unsigned int line=0
|
|
) {
|
|
this->write_message(err.what(), lvl, file, line);
|
|
}
|
|
template<typename U>
|
|
std::enable_if_t<std::is_integral_v<U>, void> write_message(
|
|
const U& val,
|
|
uint8_t lvl=0x00,
|
|
std::string file="",
|
|
unsigned int line=0
|
|
) {
|
|
this->write_message(std::to_string(val), lvl, file, line);
|
|
}
|
|
|
|
public:
|
|
DebugLogger(std::vector<SinkPtr> sinks={}) : Base(
|
|
std::static_pointer_cast<DataSink<LogEvent>>(std::make_shared<Distributor>())
|
|
) {
|
|
for (auto sink : sinks) {
|
|
addLogHandler(sink);
|
|
}
|
|
}
|
|
~DebugLogger() { static_cast<LoggerType*>(this)->stop(); }
|
|
void addLogHandler(SinkPtr sink) {
|
|
auto multsink = std::static_pointer_cast<Distributor>(_logsink);
|
|
multsink->addSink(sink);
|
|
}
|
|
uint8_t minimalLogLevel() const {
|
|
return _loglvl.load(std::memory_order_acquire);
|
|
}
|
|
uint8_t minimalLogLevel(uint8_t level) {
|
|
_loglvl.store(level, std::memory_order_release);
|
|
auto multsink = std::static_pointer_cast<Distributor>(_logsink);
|
|
for (auto& sink : multsink->getSinks()) {
|
|
if (sink->logLevel() < level) {
|
|
sink->logLevel(level);
|
|
}
|
|
}
|
|
return minimalLogLevel();
|
|
}
|
|
|
|
template<typename U>
|
|
void msg(
|
|
U val,
|
|
std::string file="",
|
|
unsigned int line=0
|
|
) { this->write_message(val, 0x00, file, line); }
|
|
|
|
template<typename U>
|
|
void warn(
|
|
U val,
|
|
uint8_t lvl=0x01,
|
|
std::string file="",
|
|
unsigned int line=0
|
|
) { this->write_message(val, lvl, file, line); }
|
|
|
|
void error(
|
|
const ErrorBase& val,
|
|
std::string file="",
|
|
unsigned int line=0
|
|
) {
|
|
this->write_message(val, 0xFF, file, line);
|
|
auto lock = this->pause();
|
|
this->flush();
|
|
}
|
|
|
|
void error(
|
|
const std::string& val,
|
|
std::string file="",
|
|
unsigned int line=0
|
|
) {
|
|
this->write_message(Error<>(val), 0xFF, file, line);
|
|
auto lock = this->pause();
|
|
this->flush();
|
|
}
|
|
};
|
|
|
|
class DefaultTerminalLogEventPrinter : public LogEventHandler {
|
|
protected:
|
|
using Base = LogEventHandler;
|
|
using Base::_running;
|
|
|
|
public:
|
|
using Base::isRunning;
|
|
using Base::logLevel;
|
|
using Base::stop;
|
|
using Base::run;
|
|
using Base::Base;
|
|
bool in(const LogEvent&) override;
|
|
};
|
|
|
|
class DefaultDebugLogger : public DebugLogger<DefaultDebugLogger> {
|
|
protected:
|
|
using LoggerType = DefaultDebugLogger;
|
|
using Base = DebugLogger<DefaultDebugLogger>;
|
|
using MultiLogSink = MultiSink<LogEvent>;
|
|
using SinkPtr = std::shared_ptr<LogEventHandler>;
|
|
using Base::_logsink;
|
|
using Base::write_message;
|
|
virtual bool process(const LogEvent& msg) override;
|
|
|
|
public:
|
|
using Base::Base;
|
|
using Base::msg;
|
|
using Base::warn;
|
|
using Base::error;
|
|
using Base::addLogHandler;
|
|
using Base::minimalLogLevel;
|
|
DefaultDebugLogger(std::vector<SinkPtr> sinks={}) : Base(sinks) {}
|
|
~DefaultDebugLogger() { stop(); }
|
|
|
|
friend class BufferedDataProcessor<LogEvent, ThreadsafeQueue<LogEvent>, DefaultDebugLogger>;
|
|
};
|
|
|
|
extern const bool LOGGER_RUNNING;
|
|
|
|
extern const bool LOGGER_RUNNING;
|
|
#ifdef _NB_AUTOLOG
|
|
extern DefaultDebugLogger logger;
|
|
#endif // _NB_AUTOLOG
|
|
|
|
// Taking Charge of Adult ADHD by Russell Barkley
|
|
|
|
} // namespace nb
|
|
|
|
#endif // _NB_LOGGER
|