class LogFile class LogConsole class LogStream
template<class LogType> class Logger : public <LogType>
class LogConsole { public: void do_log(log4cpp::LoggingEvent ev) { std::cout<<ev.timeStamp.getSeconds()<<" " <<log4cpp::Priority::getPriorityName(ev.priority)<<" " <<ev.categoryName<<" "<<ev.ndc<<": "<<ev.message<<std::endl; } };
class LogStream : SipAppender<std::ostringstream> { public: std::string do_buffer() const { return _w.str(); } void do_clear() { _w.str(std::string()); } void do_log(log4cpp::LoggingEvent ev) { appender.doAppend(ev); } };
class LogFile : SipAppender<std::ofstream> { public: LogFile() { _w.open("SIP_LOG.txt"); } ~LogFile() { _w.close(); } void do_log(log4cpp::LoggingEvent ev) { appender.doAppend(ev); } };
template<class Writer> struct SipAppender { Writer _w; log4cpp::OstreamAppender appender; SipAppender() : appender(log4cpp::OstreamAppender("logger", &_w)){} };
template<class LogType> class Logger : public <LogType> { DEFAULT_FUNC(do_buffer) DEFAULT_FUNC(do_clear) Logger() = default; static Logger& instance() { static Logger theSingleInstance; return theSingleInstance; } void log(log4cpp::Priority::PriorityLevel p, const std::string &msg) { this->do_log(log4cpp::LoggingEvent("CATEGORY",msg,"NDC",p)); } public: static void debug(const std::string ¶m){ instance().log(log4cpp::Priority::DEBUG, param); } static void info(const std::string ¶m){ instance().log(log4cpp::Priority::INFO, param); } static void error(const std::string ¶m){ instance().log(log4cpp::Priority::ERROR, param); } static std::string buffer() { return _do_buffer<Logger>::_do(&instance(), [](){return std::string();}); } static void clear() { _do_clear<Logger>::_do(&instance(), []()->void{}); } Logger& operator=(const Logger&) = delete; };
#define DEFAULT_FUNC(name) \ template<class T, class Enable = void> \ struct _##name \ { \ template<class DF> \ static auto _do(T *, DF df) -> decltype(df()) { return df(); } \ template<class DF> \ static auto _do(const T *, DF df) -> decltype(df()) { return df(); } \ }; \ template<class T> \ struct _##name <T, typename std::enable_if<std::is_member_function_pointer<decltype(&T::name)>::value>::type > \ { \ template<class DF> \ static auto _do(T *obj, DF df) -> decltype(df()) { (void)(df); return obj->name(); } \ template<class DF> \ static auto _do(const T *obj, DF df) -> decltype(df()) { (void)(df); return obj->name(); } \ };
using TestType = LogConsole; int main() { Logger<TestType>::info("Start log"); Logger<TestType>::error("Middle log"); Logger<TestType>::debug("End log"); std::cout<<Logger<TestType>::buffer()<<std::endl; Logger<TestType>::clear(); std::cout<<"clear: "<<std::endl; std::cout<<Logger<TestType>::buffer()<<std::endl; return 0; }
#define D_FUNC_VOID(name) \ template<class S, class R, class DEnable = void> \ struct __##name \ { \ template<class DF> \ static R _do(S *, DF df) { return df(); } \ template<class DF> \ static R _do(const S *, DF df) { return df(); } \ }; \ template<class S, class R> \ struct __##name <S, R, typename std::enable_if<std::is_same<std::decltype(declval<S>().name()), R>::value>::type > \ { \ template<class DF> \ static R _do(S *obj, DF df) { (void)(df); return obj->name(); } \ template<class DF> \ static R _do(const S *obj, DF df) { (void)(df); return obj->name(); } \ };
#define D_FUNC_ARG(name) \ template<class S, class A, class R, class DEnable = void> \ struct __##name \ { \ template<class DF> \ static R _do(S *, A a, DF df) { return df(a); } \ template<class DF> \ static R _do(const S *, A a, DF df) { return df(a); } \ }; \ template<class S, class A, class R> \ struct __##name <S, A, R, typename std::enable_if<std::is_same<decltype(std::declval<S>().name(std::declval<A>())), R>::value>::type> \ { \ template<class DF> \ static R _do(S *obj, A a, DF df) { (void)(df); return obj->name(a); } \ template<class DF> \ static R _do(const S *obj, A a, DF df) { (void)(df); return obj->name(a); } \ };
#define D_FUNC(name) \ template<class T, class Arg = void, class Ret = void, class Enable = void> \ struct _##name \ { \ D_FUNC_ARG(name) \ template<class DF> \ static Ret _do(T *obj, Arg a, DF df) { return __##name<T, Arg, Ret>::_do(obj, a, df); } \ }; \ template <class T, class Arg, class Ret> \ struct _##name<T, Arg, Ret, typename std::enable_if<std::is_void<Arg>::value>::type> \ { \ D_FUNC_VOID(name) \ template<class DF> \ static Ret _do(T *obj, DF df) { (void)(df); return __##name<T, Ret>::_do(obj, df); } \ };
_do_log<Logger, log4cpp::LoggingEvent>::_do(&instance(), log4cpp::LoggingEvent("CATEGORY",msg,"NDC",p), [](log4cpp::LoggingEvent){}); _do_buffer<Logger, void, std::string>::_do(&instance(), [](std::string){ return std::string();});
template<class LogType> class Logger : public LogType { D_FUNC(do_clear) D_FUNC(do_buffer) D_FUNC(do_log) Logger() = default; static Logger& instance() { static Logger theSingleInstance; return theSingleInstance; } void log(log4cpp::Priority::PriorityLevel p, const std::string &msg) { _do_log<Logger, log4cpp::LoggingEvent>::_do(&instance(), log4cpp::LoggingEvent("CATEGORY",msg,"NDC",p), [](log4cpp::LoggingEvent){}); } public: static void debug(const std::string ¶m){ instance().log(log4cpp::Priority::DEBUG, param); } static void info(const std::string ¶m){ instance().log(log4cpp::Priority::INFO, param);} static void error(const std::string ¶m){ instance().log(log4cpp::Priority::ERROR, param);} static std::string buffer() { return _do_buffer<Logger, void, std::string>::_do(&instance(), [](){ return std::string();}); } static void clear() { _do_clear<Logger>::_do(&instance(), [](){}); } Logger& operator=(const Logger&) = delete; Logger(const Logger&) = delete; };
Source: https://habr.com/ru/post/242869/
All Articles